Jobeetをやってみる 7日目
カテゴリページを作る
ルーティングの設定
# apps/frontend/config/routing.yml category: url: /category/:slug class: sfDoctrineRoute param: { module: category, action: show } options: { model: JobeetCategory, type: object }
:slugパラメータはカテゴリテーブルに対応していないので、アクセサを用意する
<?php // lib/model/doctrine/JobeetCategory.class.php public function getSlug() { return Jobeet::slugify($this->getName()); }
カテゴリページへのリンク
<?php /* apps/frontend/modules/job/templates/indexSuccess.php */ ?> <!-- some HTML code --> <h1> <?php echo link_to($category, 'category', $category) ?> </h1> <!-- some HTML code --> </table> <?php if (($count = $category->countActiveJobs() - sfConfig::get('app_max_jobs_on_homepage')) > 0): ?> <div class="more_jobs"> and <?php echo link_to($count, 'category', $category) ?> more... </div> <?php endif; ?> </div> <?php endforeach; ?> </div>
カテゴリ毎のjob数をカウントするメソッドが必要
<?php // lib/model/doctrine/JobeetCategory.class.php public function countActiveJobs() { $q = Doctrine_Query::create() ->from('JobeetJob j') ->where('j.category_id = ?', $this->getId()); return Doctrine::getTable('JobeetJob')->countActiveJobs($q); }
次にJobeetJobTableに表示するjobをカウントするメソッドを作成するんだけど、DRYに違反しないように、クエリだけを生成するメソッドを作る。
その時、利用しているところによってテーブルの別名が異なる可能性もあるので、getRootAlias()を使って吸収する
<?php // lib/model/doctrine/JobeetJobTable.class.php class JobeetJobTable extends Doctrine_Table { public function retrieveActiveJob(Doctrine_Query $q) { return $this->addActiveJobsQuery($q)->fetchOne(); } public function getActiveJobs(Doctrine_Query $q = null) { return $this->addActiveJobsQuery($q)->execute(); } public function countActiveJobs(Doctrine_Query $q = null) { return $this->addActiveJobsQuery($q)->count(); } public function addActiveJobsQuery(Doctrine_Query $q = null) { if (is_null($q)) { $q = Doctrine_Query::create() ->from('JobeetJob j'); } $alias = $q->getRootAlias(); $q->andWhere("{$alias}.expires_at > ?", date('Y-m-d H:i:s')) ->addOrderBy("{$alias}.expires_at DESC"); return $q; } }
categoryモジュールを作成する
空のモジュールを作る
$ ./symfony generate:module frontend category
DBスキーマを更新
slugカラムを作るためにSluggableというビヘイビアを利用する
# config/doctrine/schema.yml JobeetCategory: actAs: Timestampable: ~ Sluggable: fields: [name] columns: name: type: string(255) notnull: true
slugカラムができたので、JobeetCategory::getSlug()を削除する必要がある
設定をリロード
$ ./symfony doctrine:build-all-reload
ページの作成
<?php // apps/frontend/modules/category/actions/actions.class.php class categoryActions extends sfActions { public function executeShow(sfWebRequest $request) { $this->category = $this->getRoute()->getObject(); } }
<?php /* apps/frontend/modules/category/templates/showSuccess.php */ ?> <?php use_stylesheet('jobs.css') ?> <?php slot('title', sprintf('Jobs in the %s category', $category->getName())) ?> <div class="category"> <div class="feed"> <a href="">Feed</a> </div> <h1><?php echo $category ?></h1> </div> <table class="jobs"> <?php foreach ($category->getActiveJobs() as $i => $job): ?> <tr class="<?php echo fmod($i, 2) ? 'even' : 'odd' ?>"> <td class="location"> <?php echo $job->getLocation() ?> </td> <td class="position"> <?php echo link_to($job->getPosition(), 'job_show_user', $job) ?> </td> <td class="company"> <?php echo $job->getCompany() ?> </td> </tr> <?php endforeach; ?> </table>
Partialの利用
<?php /* apps/frontend/modules/category/templates/showSuccess.php */ ?> <?php use_stylesheet('jobs.css') ?> <?php slot('title', sprintf('Jobs in the %s category', $category->getName())) ?> <div class="category"> <div class="feed"> <a href="">Feed</a> </div> <h1><?php echo $category ?></h1> </div> <table class="jobs"> <?php foreach ($category->getActiveJobs() as $i => $job): ?> <tr class="<?php echo fmod($i, 2) ? 'even' : 'odd' ?>"> <td class="location"> <?php echo $job->getLocation() ?> </td> <td class="position"> <?php echo link_to($job->getPosition(), 'job_show_user', $job) ?> </td> <td class="company"> <?php echo $job->getCompany() ?> </td> </tr> <?php endforeach; ?> </table>
パーシャルの使い方は
<?php include_partial('job/list', array('jobs' => $jobs)) ?>
- 第一引数 : パーシャルファイル名
- スラッシュ"/"で区切ることで、module/partial といった指定が可能
- ファイル名にあるアンダーバー"_"は必要ない
- 第二引数 : パーシャル内で利用する変数の指定
- array('変数名' => '値')
<?php /* apps/frontend/modules/job/templates/indexSuccess.php at 13 */ ?> <?php include_partial('job/list', array('jobs' => $category->getActiveJobs(sfConfig::get('app_max_jobs_on_homepage')))) ?> <?php /* apps/frontend/modules/category/templates/showSuccess.php at 12 */ ?> <?php include_partial('job/list', array('jobs' => $category->getActiveJobs())) ?>
ページャー
1ページに20個ずつ表示させる
このページング処理を行なうために、sfDoctrinePagerクラスが提供されている
<?php // apps/frontend/modules/category/actions/actions.class.php public function executeShow(sfWebRequest $request) { $this->category = $this->getRoute()->getObject(); $this->pager = new sfDoctrinePager( 'JobeetJob', sfConfig::get('app_max_jobs_on_category') ); $this->pager->setQuery($this->category->getActiveJobsQuery()); $this->pager->setPage($request->getParameter('page', 1)); $this->pager->init(); }
- sfRequest::getParameter()は、パラメータが存在しなかったときのデフォルト値を第二引数で設定することができる。
- 指定しない場合はnullになる。
app設定値が追加されたので、設定
# apps/frontend/config/app.yml all: active_days: 30 max_jobs_on_homepage: 5 max_jobs_on_category: 5
JobeetCategory::getActiveJobsQuery()の実装
getActiveJobsQuery()を実装するので、ついでにリファクタリング
<?php // lib/model/doctrine/JobeetCategory.class.php class JobeetCategory extends BaseJobeetCategory { public function getActiveJobs($max = 10) { $q = $this->getActiveJobsQuery() ->limit($max); return $q->execute(); } public function countActiveJobs() { return $this->getActiveJobsQuery()->count(); } public function getActiveJobsQuery() { $q = Doctrine_Query::create() ->from('JobeetJob j') ->where('j.category_id = ?', $this->getId()); return Doctrine::getTable('JobeetJob')->addActiveJobsQuery($q); } }
テンプレートの記述
テンプレート内では以下のメソッドが利用できる
メソッド名 | 結果 |
---|---|
getResult() | Doctrineオブジェクトの配列のリスト |
getNbResult() | リストの個数 |
gethavToPaginate() | 2ページ以上かどうか |
getLinks() | ページングのリンク |
getPage() | 現在のページ番号 |
getPreviousPage() | 1ページ前の番号 |
getNextPage() | 次のページ番号 |
getLastPage() | 最後のページ番号(総ページ数) |
<?php /* apps/frontend/modules/category/templates/showSuccess.php */ ?> <?php use_stylesheet('jobs.css') ?> <?php slot('title', sprintf('Jobs in the %s category', $category->getName())) ?> <div class="category"> <div class="feed"> <a href="">Feed</a> </div> <h1><?php echo $category ?></h1> </div> <?php include_partial('job/list', array('jobs' => $pager->getResults())) ?> <?php if ($pager->haveToPaginate()): ?> <div class="pagination"> <a href="<?php echo url_for('category', $category) ?>?page=1"> <img src="/images/first.png" alt="First page" /> </a> <a href="<?php echo url_for('category', $category) ?>?page=<?php echo $pager->getPreviousPage() ?>"> <img src="/images/previous.png" alt="Previous page" title="Previous page" /> </a> <?php foreach ($pager->getLinks() as $page): ?> <?php if ($page == $pager->getPage()): ?> <?php echo $page ?> <?php else: ?> <a href="<?php echo url_for('category', $category) ?>?page=<?php echo $page ?>"><?php echo $page ?></a> <?php endif; ?> <?php endforeach; ?> <a href="<?php echo url_for('category', $category) ?>?page=<?php echo $pager->getNextPage() ?>"> <img src="/images/next.png" alt="Next page" title="Next page" /> </a> <a href="<?php echo url_for('category', $category) ?>?page=<?php echo $pager->getLastPage() ?>"> <img src="/images/last.png" alt="Last page" title="Last page" /> </a> </div> <?php endif; ?> <div class="pagination_desc"> <strong><?php echo $pager->getNbResults() ?></strong> jobs in this category <?php if ($pager->haveToPaginate()): ?> - page <strong><?php echo $pager->getPage() ?>/<?php echo $pager->getLastPage() ?></strong> <?php endif; ?> </div>