uthorofotus iruc
プログラムを組むために考えたり憶えたりした、いろいろなことを記録していきます。タイトルの読みは「ウソロフォトス イルーク」
[18] [17] [16] [15] [14] [13] [12] [11] [10] [9] [8]
[PR]
[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。
askeet day four:refactoring の解説
4日目チュートリアルの日本語版はこちらです。本家英語版はこちらです。
■前回までのsymfony(Previously on symfony)
質問モジュールに対して、さらに機能を追加していきます。機能を追加していきながらコードの整理も並行して進めます。
■質問に対しての回答の表示(Show the answers to a question)
▽このアクションについて少し(A quick look at the action)
showアクションを修正する前に、"symfony propel-generate-crud"で生成されたコードを見直します。ここでは"symfony propel-build-model"で生成したModelを使って質問内容を取得しています。QuestionPeerクラスはlib/model/QuestionPeer.phpで定義されていて、このクラスを使ってDBへアクセスできます。retrieveByPkメソッドは、指定されたプライマリキーの質問内容を取得します。アクセスURLに入っていたidはgetRequestParameterメソッドを使って取得します。
▽showSuccess.php テンプレートの変更(Modify the showSuccess.php template)
テーブルタグで書かれていたテンプレートを、divタグを使ってcssが効くように書き直します。注意しておくことは、getAnswersメソッドによって質問に関連した回答を取得してる箇所と、日付を表示するためのformat_dateヘルパーメソッドを使うため、Dateヘルパーを読み込んでいるところです。
▽テストデータの追加(Add some new test data)
"symfony propel-load-data frontend"でも登録出来ます。今回追加するテストデータは、前に設定したQuestionデータの前に追加することはできません。これは、Answerデータの定義の際に、question_idの値がQuestionデータを差しているためです。
■モデルの変更 パート1(Modify the model, part I)
フルネームの部品はすでにDBに入っているので、新しくテーブルにカラム追加したりはせず、get~を使ってフルネームを生成するようにしています。
このメソッド追加は、BaseUser.phpではなくUser.phpに追加しています。BaseUser.phpはschema.ymlを基にpropel-build-modelで生成するファイルです。なので、BaseUser.phpに追加してしまうとschemaの修正をした際、Propelによって修正部分が消えてしまいます。それを避けるために、BaseUser.phpを継承したUser.phpクラスが用意されています。このクラスはModelの再構築時に修正内容が消えてしまうことはありません。
■同じことは繰り返さない(Don't repeat yourself)
テンプレートの重複部分を共通部品化するには、4種類の方法があります。今回は、Interestの数を表示するだけなので、ビューだけで処理が完結しています。こういう場合はパーシャル(Partial)という方法を使っています。他にはコンポーネント(Component)、スロット(Slot)、コンポーネントスロット(ComponentSlot)があります。もし、Modelで行うべき処理があるのであれば、コンポーネントなどを使うべきです。スロットはパーシャルと仕組みは同じですが、読み込むテンプレートをアクションごとに設定ファイルで指定出来るところが違います。
■モデルの変更 パート2(Modify the model, part II)
$question->getInterests()を呼び出すと、その都度InterestへのDBアクセスが発生します。ここで必要としている処理は、Interestの内容を取得ではなくInterestの数を取得したいだけです。そこで、Question自体にInterestの数を登録してしまうことにより、DBアクセスを減らします。
こういう時は、Triggerを使えばDB側で実装できそうな気がします。propelにその機能がないか、DB実装に依存してしまうことからあえて使っていないのかもしれません。
▽User オブジェクトモデルへの項目の追加(Add a field to the User object model)
schema.ymlへは以下のように追加します。
interested_users: { type: integer, default: 0 }
schema.ymlの修正後、"symfony propel-build-all"と"symfony propel-load-data frontend"を実行して、修正内容をModelとデータベースに反映しましょう。
▽Interest オブジェクトの save() メソッドの変更(Modify the save() method of the Interest object)
propelで生成したクラスは、データを更新する際にsaveメソッドを使います。Interestクラスのsaveメソッドをオーバーライドして、save時にQuestionクラスのinterested_usersも更新するように修正することにより、interested_usersの値をInterestの値と連動するようにしています。これにより、Questionクラスのinterested_usersの値を見ればいいため、InterestへのDBアクセスをしなくても済むようになります。
▽トランザクションで更新を安全に(Secure the updating request with a transaction)
Interestクラスの更新、Questionクラスのinterested_usersを更新する際にエラーが発生した際、トランザクションを戻す(rollback)するようにしています。
▽テンプレートの変更(Change the template)
Questionクラスのinterested_usersの値を表示するように修正します。先ほどテンプレートをパーシャルを使って整理したので、1カ所の修正済むようになりました。
ウェブデバッグツールバーで、発行されたSQL文を確認してください。Interestクラスへのアクセスをしなくなっているはずです。
▽変更点の正当性テスト(Test the validity of the modification)
バッチや"symfony propel-load-data frontend"の処理をした際であっても、Interestクラスのsaveメソッドを使って登録されているので、interested_usersの値もちゃんと入っています。
■回答にも同じ事を(Same for the answers)
各回答には評価(その回答が良かったか悪かったか)という値が入るようにします。ここでいきなりcount($answer->getRelevancys())と出てきますが、これは後で出てきますので、とりあえずそのまま入力しておきます。schema.ymlは以下のようになります。
relevancy_up: { type: integer, default: 0 }
relevancy_down: { type: integer, default: 0 }
※2日目の記事でschema.ymlのサンプルを載せましたが、Relevancyのカラム名が間違っていました。そのままコピーして使っている場合は、question_idとなっている部分をanswer_idに修正してください。
ask_relevancy:
_attributes: { phpName: Relevancy }
answer_id:
user_id:
score: integer
created_at:
Modelの修正ではRelevancyを更新した際、同時にAnswerクラスのrelevancy_up/relevancy_downも更新するようにしています。
■ルーティング(Routing)
ようやく、アクセスするURLをコントロールできるようになります。今まではプライマリキー(id)でアクセスしていましたが、質問タイトルが入ったURLでアクセスできるようにします。日本語が入った場合上手く動くか不安ですが、商品の型番をキーにしたい場合など、日本語を使わない場合などに使えるので覚えておきます。
▽タイトルの別バージョンを作る(Create an alternate version of the title)
stripped_titleカラムをのschema.ymlは以下のようになります。stripped_titleをキーにしてデータを呼び出すことが多くなりそうなので、indexも追加しておきました。不要なら_indexesを消してください。
stripped_title: varchar(255)
_uniques:
unique_stripped_title: [stripped_title]
_indexes:
index_stripped_title: [stripped_title]
stripped_titleの定義行でindexの指定もできますが、index名が気に入らなかったのでやめました。1行でindexも定義する場合は、以下のymlです。
stripped_title: { type: varchar(255), index: true }
_uniques:
unique_stripped_title: [stripped_title]
unique定義は1行でできないようですので、_uniquesを別行で定義してください。
▽カスタムクラス(Custom class)
stripped_titleを作るための処理は、他のアプリケーションやモジュールでも使いそうなのでライブラリ化します。そのライブラリを使って、Questionのtitleを更新したらstripped_titleも更新するようにgetTitleメソッドをオーバーライドします。
myToolsライブラリを追加したら、"symfony cc"をして、http://askeet/ にアクセスしてみてください。キャッシュディレクトリ内に cache/frontend/prod/config/config_autoload.yml.phpというファイルができているはずです。このファイルは、symfony上で処理する際に自動的に読み込むライブラリリストを保存しているファイルです。ここの内容を見ると
// project
'myTools' => '/~~/askeet/lib/myTools.class.php',
と、先ほど作ったmyToolsライブラリを読むこむ指定が追加されているのが確認できます。これで、askeet内どこでもmyToolsクラスのstripTextメソッドが使えるようになりました。
▽show アクションへのリンクを変更(Change the links to the show action)
今まではlink_toでのリンク先指定にはidを使っていましたが、これをstripped_titleを使った物に修正します。それに対応して、showアクションで質問内容を取得する方法を。プライマリキー(id)ではなく、stripped_titleから取得するようにします。
▽ルーティングルールの変更(Changing the routing rules)
URL中の/stripped-title/が邪魔なので、これを省略できるようにします。routing.ymlを修正する際、すでに設定されているルールも確認しておきましょう。
■それではまた明日(See you Tomorrow)
4日目の作業では、askeetの見た目は大きく変わってはいません。ただし、中身が大きく変わり、より整理されました。5日目はフォーム処理についてです。
この記事にコメントする
← askeet day five:forms and pager の解説 HOME askeet day three:dive into the MVC architecture の解説 →
プロフィール
Wassr
カレンダー
04 | 2025/05 | 06 |
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 | 31 |
最新記事
アクセス解析