早速ページング処理してみます。
まずapp.ymlに1ページあたりの表示件数を記述。
config/app.yml
1
2
|
all:
max_jobs_on_category: 20
|
チュートリアルではapps/frontend/config/app.ymlに書くようになっていますがどちらでもいいです。
apps/frontend/modules/category/actions/actions.class.php
1
2
3
4
5
6
7
8
9
10
11
|
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();
}
|
sfDoctrinePagerがページャーオブジェクトです。
setQuery()でクエリオブジェクトを突っ込むとページング処理を行ってくれます。
JobeetCategory::getActiveJobsQuery()はまだ無いので作成します。
lib/model/doctrine/JobeetCategory.class.php
1
2
3
4
5
6
|
public function getActiveJobsQuery(){
$q = Doctrine_Query::create()
->from('JobeetJob j')
->where('j.category_id = ?', $this->getId());
return Doctrine::getTable('JobeetJob')->addActiveJobsQuery($q);
}
|
やってることはJobeetCategory::getActiveJobs()とほぼ同じで、実際にクエリを実行してしまうかクエリオブジェクトをそのまま持ってくるかの違いしかありません。
ということでリファクタリングできます。
lib/model/doctrine/JobeetCategory.class.php
1
2
3
4
5
6
7
|
public function getActiveJobs($max = 10){
$q = $this->getActiveJobsQuery()->limit($max);
return $q->execute();
}
public function countActiveJobs(){
return $this->getActiveJobsQuery()->count();
}
|
JobeetCategory::getActiveJobsQuery()はクエリオブジェクトをそのまま返し、countActiveJobs()は取得できる件数を返し、getActiveJobs()は実際にその内容を取得して返します。
最後にテンプレートを更新。
ページング関連を追加します。
apps/frontend/modules/category/templates/showSuccess.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
|
use_stylesheet('jobs.css')
slot('title', sprintf('Jobs in the %s category', $category->getName()))
<div class="category">
<div class="feed">
<a href="">Feed</a>
</div>
<h1> echo $category </h1>
</div>
include_partial('job/list', array('jobs' => $pager->getResults()))
if ($pager->haveToPaginate()):
<div class="pagination">
<a href=" echo url_for('category', $category) ?page=1">
<img src="/images/first.png" alt="First page" title="First page" />
</a>
<a href=" echo url_for('category', $category) ?page= echo $pager->getPreviousPage() ">
<img src="/images/previous.png" alt="Previous page" title="Previous page" />
</a>
foreach ($pager->getLinks() as $page):
if ($page == $pager->getPage()):
echo $page
else:
<a href=" echo url_for('category', $category) ?page= echo $page "> echo $page </a>
endif;
endforeach;
<a href=" echo url_for('category', $category) ?page= echo $pager->getNextPage() ">
<img src="/images/next.png" alt="Next page" title="Next page" />
</a>
<a href=" echo url_for('category', $category) ?page= echo $pager->getLastPage() ">
<img src="/images/last.png" alt="Last page" title="Last page" />
</a>
</div>
endif;
<div class="pagination_desc">
<strong> echo $pager->getNbResults() </strong>
jobs in this category
if ($pager->haveToPaginate()):
- page <strong> echo $pager->getPage() / echo $pager->getLastPage() </strong>
endif;
</div>
|
なんだこのややこしいテンプレートは。
こんな訳の解らないものを出して「ロジックとデザインの分離が出来た!」とか言ってる場合じゃないと思うんだが。
こんなの絶対デザイナーには触れない。
あとどうでもいいけどチュートリアルのテンプレはFirstpageにtitleが無い。
やってることを順に解説すると、まずsfDoctrinePager::haveToPaginate()でページングの必要があるかどうか判断。
その後は、1ページ目へのリンク、前のページへのリンク、各ページへの順番リンク、次のページへのリンク、最後のページへのリンクを順に書いているだけです。
ちなみにsfDoctrinePager::getLinks()で返ってくるのは単なる数値の配列です。
非常に残念なのがリンクを自力で書かなければならないこと。
Pear::PagerやCakePHP、Zend_Paginatorといった主なページャーはここらへんを自動でやってくれるので、これらに比べると使い勝手の悪さが目立ちます。
せっかくのフルスタックフレームワークなんだからurl_for('category', $pager->next())くらいやってほしかった。
てーかそこらへんリファレンスで何一つ解説されてないとか酷すぎる。
Symfonyの記事一覧
ていうか最近漫画ばっかりだな。
前はもっとまともな本も読んでたんだよ。
最近漫画ばかりなのはあれだ、よく行く本屋がコミック売り場だけ別の建物に隔離されてるせいなんだ。
おかげでコミックコーナー行って力尽きる。
やはり本屋はヨドバシ博多みたいなワンフロア形式がいい。
デュラララ!!4
☆☆☆☆
珍しく臨也がハブられてる話。
なんで毎回強キャラは人格破綻者ばっかりなんでしょうか。
あやしい男と失恋ってきました。
☆☆☆
痛い男に痛い女総出演の痛い漫画。
なんだけど、残念ながら私には全く縁のない世界の話なのでさっぱりわからない。
ああ、世界にはこんな人がいるんだなあ、というかこんな世界があるんだなあという生態を見てみるには最適。
数学ガール上
☆☆☆
椅子を蹴るなよ。
ということでよくわからんかった。
いやまあ数式はわかるんだけど、ミルカさんの性格が特異すぎてよくわからん。
個人的にはテトラちゃんのほうが良い。
BTOOOM!2
☆☆☆
吉良との戦闘は他と違って如何にもフィクションな戦闘だったので逆に違和感があった。
あとガスタイプ性能高過ぎじゃね?
まあ、あんな環境で女の子がどうなるかなんて考えるまでもないわな。
9時間9人9の扉
やーっっっっっっと売ってるの見つけた。
なんでこんなにレアなんだ。
現在2周目ですがいかにも打越っぽいネタが隠されてそうな感じで楽しみだ。
リンク先はcategoryモジュールという別個のモジュールにしてしまうので、とりあえずコマンドラインから骨組みを作成します。
> php symfony generate:module frontend category
次に前回url:slugとか書いていた部分に対してその実体を作成します。
>categoryテーブル用にslugカラムを追加する必要があります:
>このslugカラムはDoctrineのSluggableビヘイビアによって考慮されます。
>JobeetCategoryモデルのビヘイビアを有効にすればすべてが考慮されます。
駄目だ、何度読んでも意味がわからない。
Doctrineのドキュメントでようやくそれっぽい記述を発見しました。
スキーマにテーブル名:actAs:Sluggable:というオプションを記述しておけば、テーブル自体にはカラムを作成しないけどモデル的にはカラムが存在するように振る舞う、というような内容のようです。
あと、"Sluggable ビヘイビア"でようやくslugの意味がわかったわ。
何故Doctrineのサイト自身にこれを適用していないんだろう?
スキーマファイル、JobeetCategory:actAs:内に以下を追加します。
config/doctrine/schema.yml
1
2
3
4
|
JobeetCategory:
actAs:
Sluggable:
fields: [name]
|
スキーマを書き換えたのでデータベースを作り直します。
例によって直接DBを触った内容は全削除されます。
>php symfony doctrine:build-all-reload --no-confirmation
1
2
3
4
5
6
7
8
9
10
|
CREATE TABLE IF NOT EXISTS `jobeet_category` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
`created_at` datetime DEFAULT NULL,
`updated_at` datetime DEFAULT NULL,
`slug` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `name` (`name`),
UNIQUE KEY `sluggable_idx` (`slug`)) ENGINE=InnoDB DEFAULT CHARSET=utf8 ;
|
slugフィールドが作成されていました。なんだそれ。
この定義により、JobeetCategory::save()メソッド等で保存を行った際、jobeet_category.nameをslugifyした結果が勝手にslugフィールドに入るようになります。
さて、slugフィールドが実在するようになったので、今日スキーマに書いた
url: /category/:slug
の:slugは実在のカラムを参照できるようになり、せっかく書いたJobeetCategory::getSlug()は不要となります。
あったとしても元のメソッドがオーバーライドされるだけですが、まあ意味がないので削除しましょう。
ようやく画面表示コントローラとテンプレートの作成です。
ルーティングでparam: {module: category,action: show }と定義しているのでcategoryActions::executeShow()が呼び出されます。
apps/frontend/modules/category/actions/actions.class.php
1
2
3
|
public function executeShow(sfWebRequest $request){
$this->category = $this->getRoute()->getObject();
}
|
apps/frontend/modules/category/templates/showSuccess.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
use_stylesheet('jobs.css') slot('title', sprintf('Jobs in the %s category', $category->getName()))
<div class="category">
<div class="feed">
<a href="">Feed</a>
</div>
<h1> echo $category </h1>
</div>
<table class="jobs">
foreach ($category->getActiveJobs() as $i => $job):
<tr class=" echo fmod($i, 2) ? 'even' : 'odd' ">
<td class="location">
echo $job->getLocation()
</td>
<td class="position">
echo link_to($job->getPosition(), 'job_show_user', $job)
</td>
<td class="company">
echo $job->getCompany()
</td>
</tr>
endforeach;
</table>
|
ようやくカテゴリ単位で閲覧を行えるようになりました。
なにげに10件しか表示されていないのですが、それはまた今度。
先にパーシャルテンプレートを解説します。
テンプレートをよく見てみると、apps/frontend/modules/job/templates/indexSuccess.phpとapps/frontend/modules/category/templates/showSuccess.phpの<table class="jobs">
の中身は全く同じです。
こういう場合、共通する部分だけ別のファイルに書き出して共有を行うことができます。
apps/frontend/modules/job/templates/_list.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
<table class="jobs">
foreach ($jobs as $i => $job):
<tr class=" echo fmod($i, 2) ? 'even' : 'odd' ">
<td class="location">
echo $job->getLocation()
</td>
<td class="position">
echo link_to($job->getPosition(), 'job_show_user', $job)
</td>
<td class="company">
echo $job->getCompany()
</td>
</tr>
endforeach;
</table>
|
include_partial()でインクルードを行うことができます。
<?php include_partial('job/list'); ?>とすると、jobモジュール内のlistテンプレート、すなわちapps/frontend/modules/job/templates/_list.phpがそのまま取得できます。
注意点としては、変数はそのままでは全く渡されないということです。
上記apps/frontend/modules/category/templates/showSuccess.phpから単にinclude_partial('job/list');としただけでは、_list.php内の$jobsは空っぽです。
共通して変数を使いたい場合は、第二引数で渡す必要があります。
よって、上記showSuccess.phpのテーブル表示部分はこのようになります。
apps/frontend/modules/category/templates/showSuccess.php
1
|
include_partial('job/list', array('jobs' => $category->getActiveJobs()))
|
トップ画面の方も修正しましょう。
apps/frontend/modules/job/templates/indexSuccess.php
1
2
3
|
include_partial('job/list',
array('jobs' => $category->getActiveJobs(
sfConfig::get('app_max_jobs_on_homepage'))))
|
ちなみにトップ画面の場合、同じモジュール内にあるのでモジュール名を省略してinclude_partial('list')と書くこともできます。
Symfonyの記事一覧
| 採血日 | 2009/12/30 | 2009/12/06 | 2009/11/07 | 2009/09/23 | 2009/08/16 |
| ALT(GPT) | 41 | 17 | 13 | 17 | 19 |
| γ-GTP | 21 | 14 | 17 | 15 | 16 |
| TP | 7.6 | 7.8 | 7.7 | 7.8 | 7.5 |
| ALB | 4.3 | 4.4 | 4.5 | 4.5 | 4.4 |
| A/G | 1.3 | 1.3 | 1.4 | 1.3 | 1.4 |
| CHOL | 162 | 171 | 169 | 173 | 187 |
| GA | 13.5 | 13.9 | 14.2 | 14.3 | 14.3 |
| RBC | 493 | 481 | 482 | 509 | 508 |
| Hb | 14.1 | 14.0 | 13.7 | 13.9 | 14.9 |
| Ht | 43.1 | 41.1 | 41.7 | 43.9 | 43.4 |
| MCV | 87.4 | 85.4 | 86.5 | 86.2 | 85.4 |
| MCH | 28.6 | 29.1 | 28.4 | 27.3 | 29.3 |
| MCHC | 32.7 | 34.1 | 32.9 | 31.7 | 34.3 |
| WBC | 62 | 63 | 82 | 71 | 74 |
| PLT | 31.2 | 25.9 | 27.4 | 27.6 | 30.7 |
一体俺の体に何が!
と思ったら標準値が5~45で何気に問題無い値だった。
まず、カテゴリ宛へのリンクでやってきた場合のルーティングを定義します。
apps/frontend/config/routing.yml
1
2
3
4
5
|
category:
url: /category/:slug
class: sfDoctrineRoute
param: { module: category, action: show }
options: { model: JobeetCategory, type: object }
|
だからslugって何なんだよ。
とりあえず以上のルーティングで下記のようなURLに合致することになります。
http://symfony.localhost/frontend_dev.php/category/hoge
categoryモジュールのshowアクションが実行されます。
>ルートは関連オブジェクトからの任意のカラムをパラメーターとして使うことができます。
>オブジェクトクラスで定義された関連アクセサーが存在する場合、ルートは他の値も使用できます。
>slugパラメーターは対応するcategoryテーブルのカラムを持たないので、ルートを動作させるためにJobeetCategoryのバーチャルアクセサーを追加する必要があります:
何この日本語。
解読すると、どうやらルーティングのurl:パラメータに、options:model:のモデルで指定されているカラムが存在しない場合、モデルにあるgetメソッドを実行する、ということのようです。
というか、全てのurl:パラメータに対してgetメソッドを実行してるんだけど、カラムが存在しているパラメータに対してのgetメソッドは最初から存在するので実装する必要が無く、存在しないカラムの場合は書かないといけないよ、ということのようです。
さてポイントは、これらはcategory:に合致するURLにやってきたときに動作するのではなく、テンプレートからcategoryを使用したURLへのリンクを作成しようとした際に動作するということです。
リンク先に移動したときではなく、リンクを表示するときに必要だったわけですね。
7日目にしてようやく明かされるこの真実。
ようやく5日目後半に作成したslugifyの動作原理がなんとなくわかったような気がしないでもありません。
ということでJobeetCategoryモデルに:slugなんてカラムは存在しないので、対応するgetメソッドを作成します。
lib/model/doctrine/JobeetCategory.class.php
1
2
3
|
public function getSlug(){
return Jobeet::slugify($this->getName());
}
|
Jobeet::slugify()は+や%といったURLとして表示するには美しくない文字をすべて削除します。
テンプレートからlink_to()した際のリンク先URLを勝手に書き換えてくれます。
メソッド自体は昔作成したので改めて実装する必要はありません。
しかし、このクラス名をいきなり書いたら何故か/lib/Jobeet.phpがインクルードされるというのが意味不明なのですが、これは一体何処から出てくるのでしょうか。
あとslugifyって何だ。
トップページからカテゴリへのリンクを作成します。
apps/frontend/modules/job/templates/indexSuccess.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
<!-- some HTML code -->
<h1>
echo link_to($category, 'category', $category)
</h1>
<!-- some HTML code -->
</table>
if (($count = $category->countActiveJobs() -
sfConfig::get('app_max_jobs_on_homepage')) > 0):
<div class="more_jobs">
and echo link_to($count, 'category', $category)
more...
</div>
endif;
</div>
endforeach;
</div>
|
どういうこと?
上半分は、既存テンプレートの
<h1><?php echo $category ?></h1><br />
の部分を差し替えます。
下半分は
</table><br />
以下を差し替えます。
こうすることでインデックスからカテゴリページへのリンクが表示されま、せん。
JobeetCategory::countActiveJobs()が実装されていないからです。
早速実装します。
lib/model/doctrine/JobeetCategory.class.php
1
2
3
4
5
6
7
|
public function countActiveJobs(){
return Doctrine_Query::create()
->from('JobeetJob j')
->addWhere('j.category_id = ?', $this->getId())
->addWhere('j.expires_at > NOW() ')
->count();
}
|
できました。
単に有効な求人件数を取得するというメソッドです。
結果として、有効な求人全てを表示できない場合に、カテゴリページへのリンクが作成されます。
link_to()の第二引数に'category'を与えると、ルーティングのcategory:url:に合致するように勝手にURLを組み立ててくれます。
まだ存在していないcategoryモジュールへのルーティングなんてものを先に設置しなければならなかった理由が、このlink_to()というわけです。
JobeetCategoryにJobeetJobの内容を書いてしまったので、例によって分割します。
lib/model/doctrine/JobeetCategory.class.php
1
2
3
4
5
6
|
public function countActiveJobs(){
$q= Doctrine_Query::create()
->from('JobeetJob j')
->addWhere('j.category_id = ?', $this->getId());
return Doctrine::getTable('JobeetJob')->countActiveJobs($q);
}
|
1
2
3
4
5
6
7
8
|
public function countActiveJobs(Doctrine_Query $q = null){
if (is_null($q)){
$q = Doctrine_Query::create()
->from('JobeetJob j');
}
$q->addWhere('j.expires_at > NOW() ');
return $q->count();
}
|
できました。
この状態で問題無いといえば問題無いのですが、JobeetJobTableクラスをよく見るとJobeetJobTable::getActiveJobs()とJobeetJobTable::countActiveJobs()にほとんど同じコードが並んでいます。
効率よく纏めてしまいましょう。
lib/model/doctrine/JobeetJobTable.class.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
class JobeetJobTable extends Doctrine_Table{
/*
* 現在有効なJobeetJobを一件だけ取得
*/
public function retrieveActiveJob(Doctrine_Query $q){
return $this->addActiveJobsQuery($q)->fetchOne();
}
/*
* 現在有効なJobeetJobを全件取得
*/
public function getActiveJobs(Doctrine_Query $q = null){
return $this->addActiveJobsQuery($q)->execute();
}
/*
* 現在有効なJobeetJobの件数を取得
*/
public function countActiveJobs(Doctrine_Query $q = null){
return $this->addActiveJobsQuery($q)->count();
}
/*
* DQLに現在有効なJobeetJobを追加
*/
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 > NOW()')
->addOrderBy($alias . '.created_at DESC');
return $q;
}}
|
SQLを組み立てる部分と実行する部分を分けることにより、すっきりしたコードにすることができました。
ただORDER BYは本来そんなところに書くべきではないと思うのですが、Doctrineはcount()の際に不要なORDERとかを削除してくれるのでひとまずは問題ありません。
しかしgetRootAliasは突如出てきて一切説明無しですか。
動作から推測するに、$q->addWhere('j.expires_at > NOW() ');の'j'の部分を取得するメソッドのようです。
Doctrine_Hydrate::getRootAlias()で定義されているようですがヘルプが存在しねえ。
Symfonyの記事一覧
どうでもいいが「こえでおしごと パスワード」でググって来る奴ってどうなんだろうね。
たかが一冊くらい買えよ。
文学少女見習いの傷心。
☆☆☆☆☆
野村美月って大昔に赤城山卓球場に歌声は響くって本を読んで、全然わけがわからねえ、という印象しか持てなかった記憶があるんだ。
なんか魔王とか出てなかったっけ。
で、夏頃になんとなく文学少女読んでみたらそのレベルの高さにびっくりしましたよ。
いつのまにかこんな本を書けるようになっちゃってまあ。
というわけで当時出ていた文学少女全部買いそろえました。
本作はようやく美羽の軛から解放されたと思いきやあんまり変わってない心葉の話。
登場人物がどいつもこいつも影や闇や裏や逆や対偶持ちの中、ほぼ唯一まっすぐな菜乃が清涼剤になっています。
そういえば確かにあの二人は直接会ってないからそういうトリックも有りではあるが、では何故そんなことをしたという動機がよく判らなかった。
あと最後のオチは一体どうやって収拾付けられるんだろうか。
デュラララ!!3
☆☆☆☆
だから言ったのに!
あまりにも予想通りの展開で逆にびっくりだ。
あと警察が格好良すぎる。
どうでもいいんだが、セルティが毎回PDAに…とか!とか入力する姿を想像するたびになんとなく吹く。
画面を見せるんじゃなくてテキスト読み上げ機能くらい付けてやればいいのにと思うんだがどうだろう。
論理少女3
☆☆☆☆
サイコロの高さはいつきの目線まであるので相当でかいのだが、そんな壁そうそう登れるものかね?
まあサイコロの一辺は1.5メートルとしよう。
天井の高さはサイコロ4つ分ほどなので約6メートル。
階段13段で高低差6メートルはどう考えても無理なのでこの時点でおかしいと気付くべき。
実は階段の半分は描写されていなかった等の理由で高低差6メートルがきちんと存在したと仮定する。
通路の幅としてはサイコロ5個分、迷路ブロック15個分なので迷路ブロックはサイコロの1/3の大きさ。
よって三角砦一辺の長さは長さはサイコロ約10個分となる。
と思いきや表示されている部分だけで最低12個分あったので、前後の余裕とかを見て一辺サイコロ15個分としよう。
すると三角砦一辺の長さは22.5メートル。
泥部分に傾斜は付けられないのでそのぶん短くなるはずですが、ここでは大幅に余裕を見てざっと一周100メートルとしよう。
そうすると傾斜角は6%となる。
公共施設などのスロープは傾斜角度5%以下にすること、という目安があります。
かの有名な碓氷峠は6.7%です。
つまり、6%の傾斜って見ればわかる。
ちばてつやとジョーの戦いと青春の1954日
☆☆☆☆
☆は資料性として。
あしたのジョー関連の掲載誌などの情報、そしてその漫画を書いていたときのちばてつや氏の心境などが時系列順に纏められています。
力石の葬儀が実際に行われるなどの社会現象にまでなったジョーですが、ちばてつやと梶原一騎がどのようにして本作を作り上げていったかということがわかって面白かったです。
終盤の梶原一騎ちょっとひどくねーかと思うようなこともありますが、「今まで散々変えてきたくせに今さらなんだ!任せる!」で全部許す。
ゲームサイドVol.22
☆☆☆☆
カプコンのFCソフト特集、ゲームウォッチ特集、萌え系ノベル特集。
今回も読ませる記事が多くて全部読むのが大変だ。
ただ個人的には発売前ゲーム記事は要らない。
ほしいと思ってもまだ発売されてないし、それに実際発売されてみたらアレだったということも多いからな。
やはり発売されて、実際にプレイしての赤裸々な感想を書いてこそのゲーサイだと思う。
「コメントを掲載許可せずにその内容について罵倒」
というのがあります。
どう考えても常識的に有り得ない。
天国と地獄じゃなくて、地獄と地獄なんだよね。@さあのコメント欄一件目がまさにそれです。
誰もが「お前誰に向かって何を言ってんだ?」と思うところです。
たまたま被害者が全文をアップしてくれたので紹介してみたいと思います。
|
<被害者:エントリへのコメント:非掲載> |
|
<DAKINI:コメントを非掲載の上返答> |
|
<被害者:DAKINIのコメントへの返答:非掲載> |
どちらの主張の方が筋が通っているかは、各自で判断してみてください。
ちなみにマーベラスの惨劇とは
魂の叫び、切なる願い@王様物語クリエイターズBLOG
過ぎたるは及ばざるが如し@王様物語クリエイターズBLOG
の2本の記事のことです。
感想は読んだ人の意志に任せるとして、マベは海腹川背でやってしまったからいまいち信用しきれない。
チュートリアルは最初に表示の上限を設定するようになっていますが、こちらでは先にその下のフィクスチャから行います。
フィクスチャはYAMLでデータベースの中身を書いとけば下記コマンドでデータベースに内容を登録できるよ、というものです。
>php symfony doctrine:data-load
で、実はYAMLファイル内にPHPコードを書くことができます。
まずチュートリアルのjobs.ymlフィクスチャをコピーし、これまでの3つのjob_sensio_labs、job_extreme_sensio、expired_jobの下に追加。
上記コマンドを実行。
データベースを覗いてみると、さくっと34件のレコードが作成されています。
ブラウザから覗いてみると、期限切れになっていないレコードがだだーと33件表示されるはずです。
求人件数が100件とか1000件になったら非常に困るので、表示上限とページング処理が必要となります。
とりあえず表示上限を追加しましょう。
といっても単にLIMIT句を追加するだけですが。
lib/model/doctrine/JobeetCategory.class.php
1
2
3
4
5
6
7
|
public function getActiveJobs($max = 10){
$q = Doctrine_Query::create()
->from('JobeetJob j')
->where('j.category_id = ?', $this->getId())
->limit($max);
return Doctrine::getTable('JobeetJob')->getActiveJobs($q);
}
|
$maxとlimitメソッドを追加しただけです。
この状態でリロードすると、カテゴリ毎の最大表示件数が10件になります。
テンプレートから呼び出しを行うときに、最大表示件数を追加します。
apps/frontend/modules/job/templates/indexSuccess.php
1
|
foreach ($category->getActiveJobs(10) as $i => $job):
|
最大表示件数をテンプレートに直書きしてしまうのはよろしくないので、デフォルト値をapp.ymlに持たせ、テンプレートから呼び出すようにしましょう。
config/app.yml
1
2
3
|
all:
active_days: 30
max_jobs_on_homepage: 5
|
apps/frontend/modules/job/templates/indexSuccess.php
1
2
3
|
foreach ($category->getActiveJobs(
sfConfig::get('app_max_jobs_on_homepage')) as $i => $job):
|
デフォルトの10件がmax_jobs_on_homepageの5件で上書きされ、カテゴリ毎の最大表示件数が5件になります。
さて、上記のようにチュートリアルではテンプレートの呼び出し側でデフォルト値を取得していますが、ここはgetActiveJobsに実装するのが意味的に正しいと思うんだがどうだろう。こんなかんじで。
lib/model/doctrine/JobeetCategory.class.php
1
2
3
4
5
6
7
8
|
public function getActiveJobs($max = null){
if(!$max){$max=sfConfig::get('app_max_jobs_on_homepage');}
$q = Doctrine_Query::create()
->from('JobeetJob j')
->where('j.category_id = ?', $this->getId())
->limit($max);
return Doctrine::getTable('JobeetJob')->getActiveJobs($q);
}
|
さて、一覧では非表示にすることができた期限切れの求人ですが、↓のようにjob_show_user:ルーティングに直通でアクセスすると普通に見えてしまいます。
http://symfony.localhost/frontend_dev.php/job/a/b/3/c
実際は何度も作り直しているのでid=3は無いと思いますが、データベースから直接確認して行ってみてください。
その表示する部分のロジックはどんなだったか確認してみます。
apps/frontend/modules/job/actions/actions.class.php
1
2
3
|
public function executeShow(sfWebRequest $request){
$this->job = $this->getRoute()->getObject();
}
|
なんだこれ。
ああ、昨日意味がわからんと投げたやつでしたか。
とりあえずこのURLはrouting.ymlのjob_show_userにひっかかるので、job_show_user:options:にmethod_for_queryを追加します。
apps/frontend/config/routing.yml
1
2
|
job_show_user:
options: { model: JobeetJob, type: object, method_for_query: retrieveActiveJob }
|
JobeetJobTableに該当のメソッドを追加します。
lib/model/doctrine/JobeetJobTable.class.php
1
2
3
4
|
public function retrieveActiveJob(Doctrine_Query $q){
$q->andWhere('a.expires_at > NOW()');
return $q->fetchOne();
}
|
すると上記のURLで、期限が切れた求人は見えなくなりました。
めでたしめでたし。
……そのaってどこから来たの?
method_for_queryって何?
これを一日一時間で終わらせろとかどう考えても無理。
十分な時間なんて何処にもねえよ。
Symfonyの記事一覧