忍者ブログ
[PR]
×

[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。



2024/04/25 10:42 |
Symfony-7日目その1
十分な時間なんてなかったので何もせずに7日目スタート。

まず、カテゴリ宛へのリンクでやってきた場合のルーティングを定義します。

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>
          <?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>

どういうこと?

上半分は、既存テンプレートの
<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);
}
lib/model/doctrine/JobeetJobTable.class.php
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の記事一覧
PR


2010/01/11 20:18 | Comments(0) | TrackBack() | PHP

トラックバック

トラックバックURL:

コメント

コメントを投稿する






Vodafone絵文字 i-mode絵文字 Ezweb絵文字 (絵文字)



<<ALTが突然変異 | HOME | 買ったものリスト 2010/01/10>>
忍者ブログ[PR]