まずは結合です。
単なる結合だけから始めればいいのに、なんでソートとか書いて騙すようなわかりにくいことするんだろうか?
内容としては、最初から記事を取得するのではなく、まずカテゴリリストを取得し、その後各カテゴリ毎に記事を取得していって表示する、という内容になります。
まずコントローラを、記事リストの取得ではなく、カテゴリリストの取得を行うように変更します。
apps/frontend/modules/job/actions/actions.class.php
JobeetCategoryTableモデルクラスに、有効なジョブを含むカテゴリリストの取得を行うメソッドを追加します。
lib/model/doctrine/JobeetCategoryTable.class.php
JobeetCategoryテーブルに対し、JobeetJobテーブルをLEFT JOINするという内容です。
スキーマでリレーションを設定してあるテーブルの場合、このようにjoin系のメソッドで簡単に結合を行えます。
最後の条件はチュートリアルではdate()とか使ってますがSQL任せでいいじゃん。
この時点で、テンプレートから$categoriesでカテゴリリストを取得することができます。
簡単にテンプレートを書いて確認してみます。
apps/frontend/modules/job/templates/indexSuccess.php
Design
Programming
2行が表示されました。
この2カテゴリのみが、現在有効な求人を持っているからです。
実行されたSQLは以下のようになります。
さて、ここからがSymfonyの便利な点ですが、SQLの時点で呼ばれてない内容にも、リレーションが設定されている限り進んでいくことができます。
テンプレートをちょっと変更してみます。
apps/frontend/modules/job/templates/indexSuccess.php
取得されたjobeet_categoryテーブルから、そこに含まれるjobeet_jobテーブルの内容を引っ張ってきて全部表示する、という内容です。
各モデルには、get+相手のモデル名で、リレーションのあるテーブルの中身を全部取得するというメソッドが予め定義されています。
JobeetCategoryモデルには他の3テーブルから直接リレーションが張ってあるのですが、スキーマの書き方によって呼び出し方が少しだけ違います。
relationsが単数形のJobeetCategoryで定義されているjobeet_jobsやjobeet_category_affiliateはgetJobeetJobs()、getJobeetCategoryAffiliate()で呼ぶことができ、複数形のJobeetCategoriesで定義されているjobeet_affiliateテーブルはgetJobeetAffiliates()で呼ぶことができます。
今回はありませんが、テーブルa→b→cなんて関連があった場合でも、$a->getB()->getC()といったふうにすることができるので非常に便利です。
上で使用したgetJobeetJobs()メソッドは、関連するカラムを全て引っ張ってくるという内容ですので、たとえばexpired_atが切れているようなものがあったとしても気にせず呼び出してしまいます。
job_extreme_sensio
job_sensio_labs
job_expired
の3行が表示されることになりま………………されないぞ?
job_expiredが表示されません。
本来getJobeetJobs()の際は、リレーション以外の条件を気にしないはずなのですが、ログを見てみると、getJobeetJobs()の際に新たなSQLが発行されず、上記SQLの実行結果をそのまま使い回していました。
そりゃ表示されるわけ無いな。
しかしこの動作では、チュートリアルのように以下のJobeetCategory::getActiveJobs()メソッドを作成する意味が全く無いのですが。
まあいいや、気を取り直して。
本来はget+モデル名のメソッドを呼び出した場合、リレーション以外の条件を全く気にせずにカラムを拾ってきてしまいます。
上記のgetJobeetJobs()で拾わなかったのは偶然です。たぶん。きっと。おそらく。
ということでexpired_at切れを確実に排除するために、getJobeetJobs()のかわりにgetActiveJobs()メソッドを作成することにします。
前JobeetJobTableクラスにgetActiveJobs()を作成しましたが、今回はJobeetCategory::getActiveJobs()です。
二者の違いは、前者はカテゴリを気にせず、後者はカテゴリを気にするということです。
チュートリアルではいきなり分けてますが、わかりにくいのでとりあえずJobeetCategoryに全部書いてしまうことにします。
lib/model/doctrine/JobeetCategory.class.php
$this->getId()の$thisは一見何処からやってくるのかさっぱりなのですが、きちんとテンプレートでループ中の$category.idを取得してきてくれます。
メソッドを作成したのでテンプレートに反映します。
apps/frontend/modules/job/templates/indexSuccess.php
job_extreme_sensio
job_sensio_labs
の2件がやっぱり表示されました。
こちらの場合はSQLを使い回しているわけではなく、ループのたびにJobeetCategory::getActiveJobs()が呼ばれ、SQLが実行されています。
今回はカテゴリが2件しかなかったので追加発行されるSQLも2件なのですが、今後カテゴリが1000個に増えたよ、みたいなことになれば発行回数がえらいことになってしまいます。
なのでこの設計はいまいちよろしくないのですが、とりあえずまあいいや。
どうでもいいのですがDoctrineのマニュアルではWHERE句追加のメソッドはandWhereです。
確かにor系メソッドとの対比上andが正しいのでしょうが、よく使われるaddも使用できるようになっています。
さて、jobeet_jobテーブルに関する処理内容がJobeetCategoryに書かれているという事態は好ましくありません。
ということで適切なクラスにメソッドを分けてしまいましょう。
まずJobeetCategory。
lib/model/doctrine/JobeetCategory.class.php
この$qの持ち回しがポイントです。
呼ばれる側のJobeetJobTable::getActiveJobs()を修正。
lib/model/doctrine/JobeetJobTable.class.php
引数があればそのクエリにWHERE句を付け足し、無ければ単純にJobeetJobモデルを作成して返すということになります。
単に先ほどのJobeetCategory::getActiveJobs()を二つに分けただけなので、動作結果も全く変わりません。
しかし、このTableが付くか付かないかのモデルの使い分けがよくわからん。
Symfonyの記事一覧
単なる結合だけから始めればいいのに、なんでソートとか書いて騙すようなわかりにくいことするんだろうか?
内容としては、最初から記事を取得するのではなく、まずカテゴリリストを取得し、その後各カテゴリ毎に記事を取得していって表示する、という内容になります。
まずコントローラを、記事リストの取得ではなく、カテゴリリストの取得を行うように変更します。
apps/frontend/modules/job/actions/actions.class.php
1
2
3
|
public function executeIndex(sfWebRequest $request){
$this->categories = Doctrine::getTable('JobeetCategory')->getWithJobs();
}
|
JobeetCategoryTableモデルクラスに、有効なジョブを含むカテゴリリストの取得を行うメソッドを追加します。
lib/model/doctrine/JobeetCategoryTable.class.php
1
2
3
4
5
|
public function getWithJobs(){
$q = $this->createQuery('c')
->leftJoin('c.JobeetJobs j')->where('j.expires_at > NOW() ');
return $q->execute();
}
|
JobeetCategoryテーブルに対し、JobeetJobテーブルをLEFT JOINするという内容です。
スキーマでリレーションを設定してあるテーブルの場合、このようにjoin系のメソッドで簡単に結合を行えます。
最後の条件はチュートリアルではdate()とか使ってますがSQL任せでいいじゃん。
この時点で、テンプレートから$categoriesでカテゴリリストを取得することができます。
簡単にテンプレートを書いて確認してみます。
apps/frontend/modules/job/templates/indexSuccess.php
1
2
3
4
|
foreach($categories as $category){
print($category->name."<br />");
}
|
Design
Programming
2行が表示されました。
この2カテゴリのみが、現在有効な求人を持っているからです。
実行されたSQLは以下のようになります。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
SELECT
j.id AS j__id, j.name AS j__name, j.created_at AS j__created_at
, j.updated_at AS j__updated_at, j2.id AS j2__id
, j2.category_id AS j2__category_id, j2.type AS j2__type
, j2.company AS j2__company, j2.logo AS j2__logo
, j2.url AS j2__url, j2.position AS j2__position
, j2.location AS j2__location, j2.description AS j2__description
, j2.how_to_apply AS j2__how_to_apply, j2.token AS j2__token
, j2.is_public AS j2__is_public, j2.is_activated AS j2__is_activated
, j2.email AS j2__email, j2.expires_at AS j2__expires_at
, j2.created_at AS j2__created_at, j2.updated_at AS j2__updated_at
FROM jobeet_category j
LEFT JOIN jobeet_job j2 ON j.id = j2.category_id
WHERE j2.expires_at > NOW()
|
さて、ここからがSymfonyの便利な点ですが、SQLの時点で呼ばれてない内容にも、リレーションが設定されている限り進んでいくことができます。
テンプレートをちょっと変更してみます。
apps/frontend/modules/job/templates/indexSuccess.php
1
2
3
4
5
6
7
|
foreach($categories as $category){
$jobeetjobs=$category->getJobeetJobs();
foreach($jobeetjobs as $jobeetjob){
print($jobeetjob->token.'<br />');
}
}
|
取得されたjobeet_categoryテーブルから、そこに含まれるjobeet_jobテーブルの内容を引っ張ってきて全部表示する、という内容です。
各モデルには、get+相手のモデル名で、リレーションのあるテーブルの中身を全部取得するというメソッドが予め定義されています。
JobeetCategoryモデルには他の3テーブルから直接リレーションが張ってあるのですが、スキーマの書き方によって呼び出し方が少しだけ違います。
relationsが単数形のJobeetCategoryで定義されているjobeet_jobsやjobeet_category_affiliateはgetJobeetJobs()、getJobeetCategoryAffiliate()で呼ぶことができ、複数形のJobeetCategoriesで定義されているjobeet_affiliateテーブルはgetJobeetAffiliates()で呼ぶことができます。
今回はありませんが、テーブルa→b→cなんて関連があった場合でも、$a->getB()->getC()といったふうにすることができるので非常に便利です。
上で使用したgetJobeetJobs()メソッドは、関連するカラムを全て引っ張ってくるという内容ですので、たとえばexpired_atが切れているようなものがあったとしても気にせず呼び出してしまいます。
job_extreme_sensio
job_sensio_labs
job_expired
の3行が表示されることになりま………………されないぞ?
job_expiredが表示されません。
本来getJobeetJobs()の際は、リレーション以外の条件を気にしないはずなのですが、ログを見てみると、getJobeetJobs()の際に新たなSQLが発行されず、上記SQLの実行結果をそのまま使い回していました。
そりゃ表示されるわけ無いな。
しかしこの動作では、チュートリアルのように以下のJobeetCategory::getActiveJobs()メソッドを作成する意味が全く無いのですが。
まあいいや、気を取り直して。
本来はget+モデル名のメソッドを呼び出した場合、リレーション以外の条件を全く気にせずにカラムを拾ってきてしまいます。
上記のgetJobeetJobs()で拾わなかったのは偶然です。たぶん。きっと。おそらく。
ということでexpired_at切れを確実に排除するために、getJobeetJobs()のかわりにgetActiveJobs()メソッドを作成することにします。
前JobeetJobTableクラスにgetActiveJobs()を作成しましたが、今回はJobeetCategory::getActiveJobs()です。
二者の違いは、前者はカテゴリを気にせず、後者はカテゴリを気にするということです。
チュートリアルではいきなり分けてますが、わかりにくいのでとりあえずJobeetCategoryに全部書いてしまうことにします。
lib/model/doctrine/JobeetCategory.class.php
1
2
3
4
5
6
7
8
|
public function getActiveJobs(){
$q = Doctrine_Query::create()
->from('JobeetJob j')
->addWhere('j.category_id = ?', $this->getId())
->addWhere('j.expires_at > NOW()')
->addOrderBy('j.expires_at DESC');
return $q->execute();
}
|
$this->getId()の$thisは一見何処からやってくるのかさっぱりなのですが、きちんとテンプレートでループ中の$category.idを取得してきてくれます。
メソッドを作成したのでテンプレートに反映します。
apps/frontend/modules/job/templates/indexSuccess.php
1
2
3
4
5
6
7
|
foreach($categories as $category){
$jobeetjobs=$category->getActiveJobs();
foreach($jobeetjobs as $jobeetjob){
print($jobeetjob->token.'<br />');
}
}
|
job_extreme_sensio
job_sensio_labs
の2件がやっぱり表示されました。
こちらの場合はSQLを使い回しているわけではなく、ループのたびにJobeetCategory::getActiveJobs()が呼ばれ、SQLが実行されています。
今回はカテゴリが2件しかなかったので追加発行されるSQLも2件なのですが、今後カテゴリが1000個に増えたよ、みたいなことになれば発行回数がえらいことになってしまいます。
なのでこの設計はいまいちよろしくないのですが、とりあえずまあいいや。
どうでもいいのですがDoctrineのマニュアルではWHERE句追加のメソッドはandWhereです。
確かにor系メソッドとの対比上andが正しいのでしょうが、よく使われるaddも使用できるようになっています。
さて、jobeet_jobテーブルに関する処理内容がJobeetCategoryに書かれているという事態は好ましくありません。
ということで適切なクラスにメソッドを分けてしまいましょう。
まずJobeetCategory。
lib/model/doctrine/JobeetCategory.class.php
1
2
3
4
5
6
|
public function getActiveJobs(){
$q = Doctrine_Query::create()
->from('JobeetJob j')
->where('j.category_id = ?', $this->getId());
return Doctrine::getTable('JobeetJob')->getActiveJobs($q);
}
|
この$qの持ち回しがポイントです。
呼ばれる側のJobeetJobTable::getActiveJobs()を修正。
lib/model/doctrine/JobeetJobTable.class.php
1
2
3
4
5
6
7
8
9
|
public function getActiveJobs(Doctrine_Query $q = null){
if (is_null($q)) {
$q = Doctrine_Query::create()
->from('JobeetJob j');
}
$q->andWhere('j.expires_at > NOW()')
->addOrderBy('j.expires_at DESC');
return $q->execute();
}
|
引数があればそのクエリにWHERE句を付け足し、無ければ単純にJobeetJobモデルを作成して返すということになります。
単に先ほどのJobeetCategory::getActiveJobs()を二つに分けただけなので、動作結果も全く変わりません。
しかし、このTableが付くか付かないかのモデルの使い分けがよくわからん。
Symfonyの記事一覧
PR
トラックバック
トラックバックURL: