忍者ブログ

uthorofotus iruc

プログラムを組むために考えたり憶えたりした、いろいろなことを記録していきます。タイトルの読みは「ウソロフォトス イルーク」

[28]  [27]  [26]  [25]  [24]  [23]  [22]  [21]  [20]  [19]  [18

[PR]

×

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

askeet day thirteen: Tags の解説

askeetチュートリアルの13日目『タグ』です。質問の整理にタグを使います。


13日目チュートリアルの日本語版はありません。本家英語版はこちらです。

■これまでのsymfony(Previously on symfony)
13日目と14日目のチュートリアルでは、質問にタグを付けて探しやすくします。
延々と続くツリー構造にしてしまうと、何千ものの枝から目的の質問を探すのは大変です。
タグはカテゴリーと同じですが、階層が無く1つの質問に複数付けられます。
13日目ではデータベースレイヤーCreoleを使って、複雑なSQLを実行します。

■QuestionTagクラス(The QuestionTag class)
ユーザが質問にタグ付けをした際、そのデータを保存するQuestionTagテーブルが必要になります。データ(タグをつけたユーザ、付けられた質問、タグ内容)の他に、normalized_tagがあります。多分、Questionクラスのstripped_titleのようにURLに使う文字列にするかと思います。

▽スキーマの更新(Schema update)
タグを格納するQuestionTagテーブルをschema.ymlで定義し、Modelを生成します。

  ask_question_tag:
    _attributes:  { phpName: QuestionTag }
    question_id:  { type: integer, primaryKey: true, foreignTable: ask_question, foreignReference: id }
    user_id:      { type: integer, primaryKey: true, foreignTable: ask_user, foreignReference: id }
    created_at:
    tag       :   varchar(100)
    normalized_tag:     { type: varchar(100), primaryKey: true }
    _indexes:
      normalized_tag_index:    [normalized_tag]

▽カスタムクラス(Custom class)
ユーザから入力されたタグ文字列を処理するためのクラスを作ります。normalizeメソッドで記号などを除去します。ユーザがタグ文字列を登録する際は、複数のタグをスペースで区切ってまとめます。そのデータからタグを1個1個取り出すのがsplitPhraseメソッドです。文字が『"』(ダブルクォーテーション)囲まれていたら、囲まれた文字列はスペースが入っていたとしても、1つのタグとして見なす処理が入っています。このクラスが定義されたphpファイルは、自動的に読み込まれる(require不要)ように /lib/に置いています。

▽モデルの拡張(Extend the model)
先ほど作成したTagクラスを使って、tagを入力されたnormalized_tagも更新するようにセッターメソッドを修正します。以前のチュートリアルでQuestionのstripped_titleセッターを修正したのと同じ要領ですから、/lib/model/QuestionTag.php になります。

▽テストデータの追加(Add some test data)
タグのテストデータにデータベースに登録します。QuestionTagはUserとQuestionへのforeignKeyを持っていますから、テストデータはymlの最後に書きます。

■質問にタグを表示する(Display the tags of a question)
タグ処理用の新しいモジュールを作成します。

▽モデルの拡張(Extend model)
Questionモデルに関連するタグを取得するメソッドを追加します。普通にdoSelectメソッドを使ってデータを取得すると、QuestionTagクラスの全プロパティを取得(ハイドレーシング)します。しかし、ここではnormalized_tagしか使いません。そこで、clearSelectColumnsで一旦取得プロパティ(カラム/フィールド)をリセットし、addSelectColumnメソッドにてnormalized_tagだけを取得するように修正します。複数のユーザが同じタグを入力していた場合、そのうち1つだけ取得する必要があるので、setDistinctメソッドを使い、SELECT文にDISTINCT句を追加するように指定しています。

▽ビューの修正(Modify the view)
質問の詳細(question/show)ページ表示の際、画面右の部分にその質問が持っているタグ一覧を出すようにします。そこはコンポーネントで管理していましたので、question/showの時だけ表示を変えるように設定を上書きできます。今まで表示していたナビゲーションの下にタグを表示したいので、新しく作ったコンポーネントアクション/ビューでは、sidebar/defaultコンポーネントを呼んだその下にタグを表示するようにしています。なぜタグの表示部分を_question_tags.phpパーシャルで分けているのかというと、後ほどタグの追加をAjax化するため、Ajaxのタグ追加処理が返す結果ビューでの流用を考えているからです。
タグ表示のビュー部品構成イメージ

▽テスト(Test it)
タグのリンク(/tag/:tag)はアクションを実装していないので404エラーが帰ってきます。

■人気のあるタグリストを表示する(Display a short list of popular tags for a question)
質問をリスト表示した際にもタグを表示させることにします。

▽モデルの拡張(Extend model)
先ほどと同じようにQuestionモデルにgetPopularTagsメソッドを追加していきます。しかし、ここでPropelを使うと多重(タグ総数処理のため1回では終わらない)処理が発生し、時間がかかります。そこでデータベースレイヤーのCreoleに直接アクセスをして、こちらで用意したSQLを実行させます。

ただし、実行するSQLをそのままソースコード中に書いてしまうと、せっかくコード中にテーブル名やカラム名を直接書かなくて良いsymfonyの利点が失われてしまいます。たとえば後々データベース設定が変わってしまった場合に、schema.yml以外にも修正が必要になってしまいます。それを避けるためにモデルのPeerクラス([モデル名]Peer)を使います。Peerクラスにはテーブル名やカラム名が登録されていて、この値はpropel-build-modelによって常にschema.ymlと連動しています。その値を使ってSQL文を生成します。

SQL内では"WHERE %s = ?"と、『?』があります。これは、Creoleのプリペアードステートメントです。setIntメソッドによって、その場所に質問のidが入るようになっています。なので、最終的に"WHERE question_id = 5" などへ置き換わります。

Creoleについての詳細は、こちらをみてください。

▽ビューの修正(Modify the view)
以前のチュートリアルで作成した質問リストのパーシャルを修正します。パーシャルではQuestionヘルパーの呼び出し追加と、質問本文の後にタグを表示するtags_for_questionメソッドの呼び出しを追加します。その後、Questionヘルパーを作り、tags_for_questionメソッドを定義します。

▽テスト(Test)
タグが追加されているか確認します。タグのリンクはまだ実装されていません。

■タグが付けられた質問リストの表示(Display the list of questions tagged with a word)

▽tag/showアクション(The tag/show action)
QuestionPeerクラスを使って質問データを取得します。実際の処理はこの後でgetPopularByTagメソッドに書きます。

▽モデルの拡張(Extend model)
今回はCriteriaクラスの機能でカバー出来るので、Propelを使って1回の処理ですみます。QuestionTag中に指定した$tagが1個でもあればよいので、QuestionテーブルとQuestionTagテーブルをLEFT_JOINします。

▽ビューの修正(Modify the view)
チュートリアルの指示はちょっと間違っています。パーシャルに渡すデータ配列部分は以下のようになります。

array('question_pager' => $question_pager, 'rule' => '@tag?tag='.$sf_params->get('tag'))

▽ルーティングルールにページャー用パラメータを追加(Add the page parameter in the routing rule)
ページャー機能を使うようになりましたので、pageパラメータの指定を追加しておきます。

▽テスト(Test it)
キャッシュをクリアして動作を確認します。

■また明日(See you Tomorrow)
Propelでは対応出来ないような複雑なSQLを使う場合は、データベースレイヤーCreoleを使います。ただ、せっかくPropelがオブジェクトを使ってデータベースを扱えるようにしていますので、単純な処理はできるだけPropelを使うようにしましょう。
14日目ではタグの続きをします。ユーザがタグを追加したり、タグクラウドを生成します。

PR

この記事にコメントする

お名前
タイトル
文字色
メールアドレス
URL
コメント
パスワード   Vodafone絵文字 i-mode絵文字 Ezweb絵文字

この記事へのトラックバック

この記事にトラックバックする:

askeet day fourteen: Tags, part II の解説 HOME askeet day twelve:Emails の解説

プロフィール

HN:
flyfront
性別:
非公開
自己紹介:
PHPプログラマ。東京でsymfonyな仕事してます。

HNはflyfrontですが、
仕事関係ではr_koike名義を使ってる場合もあります。

Wassr

カレンダー

05 2017/06 07
S M T W T F S
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

最新コメント

[01/02 通りすがり]
[10/18 flyfront]

バーコード

アクセス解析

忍者ブログ [PR]
Template by repe