review askeet Day 4
詳細画面をtableからdiv化する。
このテーブルでできたサイトを直す。
場所: askeet2/apps/frontend/modules/question/templates/showSuccess.php
<?php use_helper('Date') ?> <div class="interested_block"> <div class="interested_mark" id="mark_<?php echo $question->getId() ?>"> <?php echo count($question->getInterests()) ?> </div> </div> <h2><?php echo $question->getTitle() ?></h2> <div class="question_body"> <?php echo $question->getBody() ?> </div> <div id="answers"> <?php foreach ($question->getAnswers() as $answer): ?> <div class="answer"> posted by <?php echo $answer->getUser()->getFirstName().' '.$answer->getUser()->getLastName() ?> on <?php echo format_date($answer->getCreatedAt(), 'p') ?> <div> <?php echo $answer->getBody() ?> </div> </div> <?php endforeach; ?> </div>
テストデータの追加
答えと妥当さのデータをテストデータに入れる。
場所: askeet2/data/fixtures/test_data.yml
User: anonymous: nickname: anonymous first_name: Anonymous last_name: Coward crazyup: nickname: crazyup first_name: Shota last_name: Enomoto dinotaro: nickname: dino first_name: Taro last_name: Dino Question: q1: title: What shall I do tonight with my girlfriend? user_id: crazyup body: | We shall meet in front of the Dunkin'Donuts before dinner, and I haven't the slightest idea of what I can do with her. She's not interested in programming, space opera movies nor insects. She's kinda cute, so I really need to find something that will keep her to my side for another evening. q2: title: What can I offer to my step mother? user_id: anonymous body: | My stepmother has everything a stepmother is usually offered (watch, vacuum cleaner, earrings, del.icio.us account). Her birthday comes next week, I am broke, and I know that if I don't offer her something sweet, my girlfriend won't look at me in the eyes for another month. q3: title: How can I generate traffic to my blog? user_id: dinotaro body: | I have a very swell blog that talks about my class and mates and pets and favorite movies. Interest: i1: { user_id: crazyup, question_id: q1 } i2: { user_id: dinotaro, question_id: q1 } i3: { user_id: dinotaro, question_id: q2 } i4: { user_id: crazyup, question_id: q2 } Answer: a1_q1: question_id: q1 user_id: dinotaro body: | You can try to read her poetry. Chicks love that kind of things. a2_q1: question_id: q1 user_id: crazyup body: | Don't bring her to a donuts shop. Ever. Girls don't like to be seen eating with their fingers - although it's nice. a3_q2: question_id: q2 user_id: crazyup body: | The answer is in the question: buy her a step, so she can get some exercise and be grateful for the weight she will lose. a4_q3: question_id: q3 user_id: crazyup body: | Build it with symfony - and people will love it.
で、
php batch/load_data.php
モデルの変更
まずはいちいちgetUserの中のgetFirstNameとか呼び出さなくても
getUserすれば苗字+名前が出るようにする。
現在、askeet2/lib/model/User.phpは空っぽなので
そこに__toStringで書く。
public function __toString() { return $this->getFirstName().' '.$this->getLastName(); }
あとはテンプレートを直すだけ。
さっそく、askeet2/apps/frontend/modules/question/templates/showSuccess.phpを直す。
posted by <?php echo $answer->getUser() ?>
同じことは繰り返さない
listSuccess.phpとshowSuccess.phpには同じコードがある。
同じことは繰り返さないということに反するのでフラグメントにする。
場所: askeet2/apps/frontend/modules/question/templates/_interested_user.php
<div class="interested_mark" id="mark_<?php echo $question->getId() ?>"> <?php echo count($question->getInterests()) ?> </div>
↑が書かれた部分を↓のコードに置き換える。
場所: askeet2/apps/frontend/modules/question/templates/listSuccess.php
場所: askeet2/apps/frontend/modules/question/templates/showSuccess.php
<?php include_partial('interested_user',array('question' => $question)) ?>
にすると共通化ができる。これで同じところを何度も直す必要がなくなる。
オブジェクトモデルに項目を追加
場所: askeet2/config/schema.yml
ask_question: _attributes: { phpName: Question, idMethod: native } id: { type: integer, required: true, primaryKey: true, autoIncrement: true } user_id: { type: integer, foreignTable: ask_user, foreignReference: id } title: { type: longvarchar } body: { type: longvarchar } interested_users: { type: integer, default: 0 } created_at: ~ updated_at: ~
関心の更新をできるようにする
InnoDBなのでトランザクションを使えるように書きます。
場所: askeet2/lib/model/Interest.php
<?php /** * Subclass for representing a row from the 'ask_interest' table. * * * * @package lib.model */ class Interest extends BaseInterest { public function save($con = null) { $con= Propel::getConnection(); try { $con->begin(); $ret = parent::save($con); // interested_usersを更新 $question = $this->getQuestion(); $interested_users = $question->getInterestedUsers(); $question->setInterestedUsers($interested_users + 1); $question->save($con); $con->commit(); return $ret; } catch (Exception $e) { throw $e; } } }
interested_userパーシャルの更新
場所: askeet2/apps/frontend/modules/question/templates/_interested_user.php
<div class="interested_mark" id="mark_<?php echo $question->getId() ?>"> <?php echo $question->getInterestedUsers() ?> </div>
修正したら、テストデータを更新する。
php batch/load_data.php
回答の投票システム
まずはschema.ymlに追加。
場所: askeet2/config/schema.yml
ask_answer: _attributes: { phpName: Answer, idMethod: native } id: { type: integer, required: true, primaryKey: true, autoIncrement: true } question_id: { type: integer, foreignTable: ask_question, foreignReference: id } user_id: { type: integer, foreignTable: ask_user, foreignReference: id } body: { type: longvarchar } relevancy_up: { type: integer, default: 0 } relevancy_down: { type: integer, default: 0 } created_at: ~
できたら、モデルを再設定してDB更新
symfony propel-build-model symfony propel-build-sql symfony propel-insert-sql
Revancyクラスのsaveを書き換える
場所: askeet2/lib/model/Relevancy.php
<?php /** * Subclass for representing a row from the 'ask_relevancy' table. * * * * @package lib.model */ class Relevancy extends BaseRelevancy { public function save($con = null) { $con = Propel::getConnection(); try { $con->begin(); $ret = parent::save(); // relevancy(妥当性)を更新する $answer = $this->getAnswer(); if($this->getScore() == 1) { $answer->setRelevancyUp($answer->getRelevancyUp() + 1); } else { $answer->setRelevancyDown($answer->getRelevancyDown() + 1); } $answer->save($con); $con->commit(); return $ret; } catch(Exception $e) { $con->rollback(); throw $e; } } }
Answerクラスにメソッドを追加
場所: askeet2/lib/model/Answer.php
<?php /** * Subclass for representing a row from the 'ask_answer' table. * * * * @package lib.model */ class Answer extends BaseAnswer { public function getRelevancyUpPercent() { $total = $this->getRelevancyUp() + $this->getRelevancyDown(); return $total ? sprintf('$.0f',$this->getRelevancyUp() * 100 / $total) : 0; } public function getRelevancyDownPercent() { $total = $this->getRelevancyUp() + $this->getRelevancyDown(); return $total ? sprintf('%.0f',$this->getRelevancyDown() * 100 / $total) : 0; } }
テンプレートの変更
場所: askeet2/apps/frontend/modules/question/templates/showSuccess.php
<?php use_helper('Date') ?> <div class="interested_block"> <?php include_partial('interested_user',array('question' => $question)) ?> </div> <h2><?php echo $question->getTitle() ?></h2> <div class="question_body"> <?php echo $question->getBody() ?> </div> <div id="answers"> <?php foreach ($question->getAnswers() as $answer): ?> <div class="answer"> <?php echo $answer->getRelevancyUpPercent() ?>% UP <?php echo $answer->getRelevancyDownPercent() ?>% DOWN posted by <?php echo $answer->getUser() ?> on <?php echo format_date($answer->getCreatedAt(), 'p') ?> <div> <?php echo $answer->getBody() ?> </div> </div> <?php endforeach; ?> </div>
テストデータに追加する。
場所: askeet2/data/fixtures/test_data.yml
User: anonymous: nickname: anonymous first_name: Anonymous last_name: Coward crazyup: nickname: crazyup first_name: Shota last_name: Enomoto dinotaro: nickname: dino first_name: Taro last_name: Dino Question: q1: title: What shall I do tonight with my girlfriend? user_id: crazyup body: | We shall meet in front of the Dunkin'Donuts before dinner, and I haven't the slightest idea of what I can do with her. She's not interested in programming, space opera movies nor insects. She's kinda cute, so I really need to find something that will keep her to my side for another evening. q2: title: What can I offer to my step mother? user_id: anonymous body: | My stepmother has everything a stepmother is usually offered (watch, vacuum cleaner, earrings, del.icio.us account). Her birthday comes next week, I am broke, and I know that if I don't offer her something sweet, my girlfriend won't look at me in the eyes for another month. q3: title: How can I generate traffic to my blog? user_id: dinotaro body: | I have a very swell blog that talks about my class and mates and pets and favorite movies. Interest: i1: { user_id: crazyup, question_id: q1 } i2: { user_id: dinotaro, question_id: q1 } i3: { user_id: dinotaro, question_id: q2 } i4: { user_id: crazyup, question_id: q2 } Answer: a1_q1: question_id: q1 user_id: dinotaro body: | You can try to read her poetry. Chicks love that kind of things. a2_q1: question_id: q1 user_id: crazyup body: | Don't bring her to a donuts shop. Ever. Girls don't like to be seen eating with their fingers - although it's nice. a3_q2: question_id: q2 user_id: crazyup body: | The answer is in the question: buy her a step, so she can get some exercise and be grateful for the weight she will lose. a4_q3: question_id: q3 user_id: crazyup body: | Build it with symfony - and people will love it. Relevancy: rel1: answer_id: a1_q1 user_id: crazyup score: 1 rel2: answer_id: a1_q1 user_id: dinotaro score: -1
書いたらバッチを走らせる。
php batch/load_data.php
ルーティング
http://review.askeet.localhost/question/show/id/1
↓
http://review.askeet.localhost/question/what-shall-i-do-tonight-with-my-girlfriend
↑のようにするためにはQuestionテーブルにwhat-shall-i-do-tonight-with-my-girlfriendを保存すればよい。
と、言うことでschema.ymlを書こう。
場所: askeet2/config/schema.yml
ask_question: _attributes: { phpName: Question, idMethod: native } id: { type: integer, required: true, primaryKey: true, autoIncrement: true } user_id: { type: integer, foreignTable: ask_user, foreignReference: id } title: { type: longvarchar } body: { type: longvarchar } interested_users: { type: integer, default: 0 } stripped_title: varchar(255) _uniques: unique_stripped_title: [stripped_title] created_at: ~ updated_at: ~
モデルを書いたら再設定とデータベースを更新。
symfony propel-build-model symfony propel-build-sql symfony propel-insert-sql
タイトルから生成する。
場所: askeet2/lib/myTools.class.php
<?php class myTools { public static function stripText($text) { $text = strtolower($text); //単語以外をはぎ取る $text = preg_replace('/\W/',' ',$text); //空白文字をハイフンに置き換える $text = preg_replace('/\ +/','-',$text); //ハイフンをトリムする $text = preg_replace('/\-$/','',$text); $text = preg_replace('/^\-/','',$text); return $text; } }
Questionクラスを書く
場所: askeet2/lib/model/Question.php
<?php /** * Subclass for representing a row from the 'ask_question' table. * * * * @package lib.model */ class Question extends BaseQuestion { public function setTitle($v) { parent::setTitle($v); $this->setStrippedTitle(myTools::stripText($v)); } }
テストデータのリロード
キャッシュも捨てておきます。
symfony cc php batch/load_data.php
テンプレートの書き換え
リンク部分を書き換える
場所: askeet2/apps/frontend/modules/question/templates/listSuccess.php
<h2><?php echo link_to($question->getTitle(),'question/show?stripped_title='.$question->getStrippedTitle()) ?></h2>
Questionのshowアクションを直す。
場所: askeet2/apps/frontend/modules/actions/actions.class.php
public function executeShow() { $c = new Criteria(); $c->add(QuestionPeer::STRIPPED_TITLE,$this->getRequestParameter('stripped_title')); $this->question = QuestionPeer::doSelectOne($c); $this->forward404Unless($this->question); }
ただ、今の状態だと
http://review.askeet.localhost/question/show/stripped_title/what-shall-i-do-tonight-with-my-girlfriend
となる。
/show/stripped_title/は要らない。