2012年5月30日水曜日

2012年05月30日 講義073日目

2012年05月30日
講義073日目
------------------------------1H------------------------------
★symfony
●検索機能の追加
・画像の検索
actions.class.phpの検索フォームの取得に
"photo" => $this->getRequestParameter("photo"),を追加
三パターンの条件
有だけチェック
無だけチェック
有無両方チェック無し
                case "photo":
                    if($v == "y"){
                       $c1 = $c->getNewCriterion(self::PHOTO, "", Criteria::NOT_EQUAL);
                       $c2 = $c->getNewCriterion(self::PHOTO, NULL, Criteria::NOT_EQUAL);
                       $c1->addAnd($c2);
                       $c->add($c1);
                    }elseif($v == "n"){
                       $c1 = $c->getNewCriterion(self::PHOTO, "");
                       $c2 = $c->getNewCriterion(self::PHOTO, NULL);
                       $c1->addOr($c2);
                       $c->add($c1);
                    }
                    break;
☆$c->getNewCriterion()で条件を増やす場合
$c1 = $c->getNewCriterion()
$c2 = $c->getNewCriterion()
$c3 = $c->getNewCriterion()
$c4 = $c->getNewCriterion()
をどれか一つにまとめる
$c1->addAnd($c2);
$c1->addAnd($c3);
...
などのようにして最終的に
$c->add($c1);
にまとめる
一つのカラムに対する条件の指定は一つにしておく
------------------------------2H------------------------------
★symfony
●検索機能の追加
・urlの検索
actions.class.phpの検索フォームの取得に
"url" => $this->getRequestParameter("url"),を追加
三パターンの条件
有だけチェック
無だけチェック
有無両方チェック無し
                case "url":
                    if($v == "y"){
                        $c1 = $c->getNewCriterion(self::URL, "", Criteria::NOT_EQUAL);
                        $c2 = $c->getNewCriterion(self::URL, NULL, Criteria::NOT_EQUAL);
                        $c1->addAnd($c2);
                        $c->add($c1);
                    }elseif($v == "n"){
                        $c1 = $c->getNewCriterion(self::URL,"");
                        $c2 = $c->getNewCriterion(self::URL,NULL);
                        $c1->addOr($c2);
                        $c->add($c1);
                    }
                    break;

・ieなどで画像を取得しようとして画像無いです表示を回避するために
indexSuccess.php
<?php if($comment->getPhoto() != ""):?>
<?php echo image_tag("comment/".$comment->getPhoto(),array("width" => 100))?><br>
<?php endif;?>
・検索フォームリセットボタン
_kensaku.php
<?php echo reset_tag("検索条件をリセット")?>
検索後の内容はリセットできないっぽい
検索後のjavascriptで実装するのがいいっぽい

・replyの内容も検索したい場合
$c->add($ReplyPeer::CONTENT, "%{$v}%", Criteria::LIKE);
とか追加して(そこからロジックを調整)
●ちゃんとMODEL化する
actionsにあるCriteriaの処理をmodelに移行する
・component.class.php
$result = ReplyPeer::countCommentId();
・replyPeer.php

☆最後に渡したい値をreturnして、ReplyPeer::countCommentId()を呼び出してるところに渡せるようにしておく
------------------------------3H------------------------------
★symfony
●MODEL

オブジェクトから得られるメソッドを増やしたいときにはPeerの付いてない
例えば/lib/model/Comment.phpを使う
例)CommentPeer.php
動的に動作させる関数を記述する
各テーブルごとに取得したいデータ郡など呼び出す時に「CommentPeer::hoge()」

例)Comment.php
インスタンス化されたオブジェクトから使用する
メソッドを追加できる
インスタンス化してから呼び出すときに「$Comment->hoge()」

indexSuccess.php
リプライ
<?php foreach($comment->getReplys() as $reply):?>

//Comment.phpに記述したメソッドを使って返信を取得
<?php foreach($comment->getReplysFromCommentId() as $reply):?>

Comment.php
    //自身のIDを元にして、付いている返信のオブジェクト配列を取得
    public function getReplysFromCommentId()
    {
        $c = new Criteria;
        $c->add(ReplyPeer::COMMENT_ID, $this->getId());
        $c->addDescendingOrderByColumn(ReplyPeer::CREATED_AT);
        $rtn = ReplyPeer::doSelect($c);

        return $rtn;
    }
------------------------------4H------------------------------
★symfony
●お問い合わせ
・mailモジュールを作る
[nishi@localhost sf.shonanbbs.com]$ symfony cc

・contact/actions.class.php
$this->getPresentationFor()
指定したモジュールの出力を取得する
    public function executeSubmit()
    {

        $contact = $this->flow->getData('contact');
        $contact->save();

        //メール送信

        //文字コードを設定する
        mb_language("Ja");
        mb_internal_encoding("ECU-JP");

        //各データを変数に分けておく
        $mailto = "root";
        $title = "タイトル";

        //mailモジュールで使用するために、セッションに保存
        $this->setflash("contact", $contact);
        //指定したモジュールの出力を取得する
        $content = $this->getPresentationFor("mail", "sendToContact");
        $header = "From:", mb_encode_mineheader("サーバー管理者");

        if(mb_send_mail($mailto, $title, $content, $header)){
            $contact->setSendFlg("y");
            $contact->save();
        }

        $this->flow->transitOnSuccess();
        return $this->flow->execute();
    }
------------------------------5H------------------------------
★symfony
●お問い合わせ
・front/mailモジュールを作る
/mail/actions.class.php
    public function executeSendToContact()
    {
        $this->contact = $this->getflash('contact');
        //セッション情報の開放
        $this->setflash("contact",NULL);
        return sfView::SUCCESS;
    }

/mail/templates/sendToContactSuccess.php
TO:<?php echo $contact->getName()?>様

お問い合わせありがとうございます。
・お問い合わせ内容

<?php echo $contact->getContent()?>

このメールに心当たりのない場合は無視してください

-------------------------------
ほげ山ほげ男
Email:hogehoge.com
-------------------------------

・ymlファイルの設定
/mail/config/view.yml
default:
  has_layout: off

・rootに送るようにテストしてみる
業務では複数にメールを送ることが多い

●sendmail
/var/log/maillogでエラーなどのログをチェックすることができる

●ブラックリスト
公開されてるブラックリストなどもある
------------------------------6H------------------------------
★symfony
●Pager機能
CommentPeer.php

        //ページフローチェック用の値でテスト、後で消す
        $perpage=3;
        $page=1;

        //ページ数とページ位置により、表示する内容を操作するクラス
        $pager = new sfPropelPager("Comment",$perpage);
        $pager->setCriteria($c);
        $pager->setPage($page);
        $pager->init();
        return $pager->getResults();
       
・pagerを機能させる
CommentPeer.php
static function getBbsArticles($search_arr = array())の引数にpagerの設定を記述
    static function getBbsArticles($search_arr = array(), $page = 1, $perpage = 10)

default/action.class.php
pageの値を受け取ったりする
        $page = $this->getRequestParameter("page");
        if($page <= 1){
            $page = 1;
        }
        $this->pager = CommentPeer::getBbsArticles($this->search_arr, $page);
        $this->comments = $this->pager->getResults();
       
indexSuccess.php
pagerの表示場所をつくる
<?php include_partial("global/pager",
            array("pager" => $pager.
                  "query" => $sf_context->getModuleName().
                             "/".
                             $sf_context->getActionName().
                             "?"
                 )
)?>
/front/templates/_pager.php
にダウンロードしたpagerを設置
-----------------------------memo------------------------------

2012年5月29日火曜日

2012年05月29日 講義072日目

2012年05月29日
講義072日目
------------------------------1H------------------------------
★symfony
●validation
sf.shonanbbs.com/backend/member/addの変更
・入力フォームでパスワードを隠すようにする
/backend/modules/member_add/templates/displatForm.php
input_password_tag()
に変更
・validate/validate.ymlの作成
public function executeValidate()に対応させるファイル名validate.ymlを作る
インデントに注意
必須項目のバリデーションはrequired:
symfonyが用意してくれてるバリデーションはsf~~Validator:
↓sfEmailValidator:とsfStringValidator:

fields:

  nickname:
    required:
      msg: ニックネームを入力してください。

  mailaddress:
    required:
      msg: メールアドレスを入力してください。
    sfEmailValidator:
      strict:       true
      email_error:  このメールアドレスは無効です。

  password:
    required:
      msg: パスワードを入力してください。

・特殊なカスタムバリデータを使いたい場合
validatorにデータを通さないとカスタムバリデータが機能しないので
特に意味のないhiddenを使ってvalidate.ymlの必須項目required:に通して解決する

・とりあえず管理者権限と削除フラグを決め打ち"n"に設定
public function executeValidate()の編集
    $member->setAdminYn("n");
    $member->setDeleteYn("n");
------------------------------2H------------------------------
★symfony
●validation
・カスタムバリデーションの作成
DBの情報を参照したい場合にはカスタムバリデーションを作成
lib/validator/myCreateMemberCheckValidator.class.php
<?php
class myCreateMemberCheckValidator extends sfValidator
{
    public function execute(&$value, &$error)
    //$value,$errorはフォームから受け取ったデータ
    {
        //削除フラグが"y"でないレコードを取得
        //退会した人のメールアドレスは使えるようにするため
        //SELECT * FROM member WHERE delete_yn != "y" AND mailaddress = "hoge.@mail.com";
        $c = new Criteria;
        $c->add(MemberPeer::DELETE_YN,"y", Criteria::NOT_EQAUL);
        $c->add(MemberPeer::MAILADDRESS, $value);
        $member = MemberPeer::doSelect($c);

        //既に登録されてるメールアドレスがあったら
        if($member)
        {
            //validate.ymlでoverlap_errorを使うために
            $error = $this->getParameter("overlap_error");
            return false;
        }
        return true;

    }
}

・validate/validate.ymlのmailaddress:に追加
    myCreateMemberCheckValidator:
      overlap_error: このメールアドレスは登録済みです。

・myLoginCheckValidator()の編集
削除フラグを見るようにする
        //削除フラグが"y"のユーザをログインさせない処理を追加
        $c = new Criteria;
        $c->add(MemberPeer::MAILADDRESS, $mailaddress);
        $c->add(MemberPeer::PASSWORD, $password);
        $c->add(MemberPeer::DELETE_YN, "y" ,Criteria::NOT_EQUAL);
        $member = MemberPeer::doSelectOne($c);
●管理者権限
/front/modules/login/actions/actions.class.php
にてログインしたときに管理者権限の有無を確認する処理を追加する
・管理者権限を持っているならの処理を追加
            if($member)
            {
                //ログイン状態にする
                $this->getUser()->setAuthenticated(true);
                $this->getUser()->clearCredentials();
                $this->getUser()->addCredential('member');

                //会員情報をセッションにセット
                $this->getUser()->setAttribute('member_id',$member->getId(),sfConfig::get('sf_session_name'));
                $this->getUser()->setAttribute('nickname', $member->getNickname(), sfConfig::get('sf_session_name'));

                //管理者権限を持っているなら
                if($member->getAdminYn() == "y"){
                    $this->getUser()->addCredential('admin');
                }


                $this->redirect('/backend');
            }
・管理者情報を追記
/backend/templates/_header.php
<?php if($sf_user->hasCredential("admin")):?>
(管理者)
<?php endif;?>
を追記
------------------------------3H------------------------------
★symfony
●管理者権限
・メンバー追加
管理者であればメンバーの管理者権限と削除フラグを編集できるようにする
<?php if($sf_user->hasCredential("admin")):?>
<tr>
<th><span class="required"></span>管理者権限</th>
<td <?php if ($sf_request->haserror('admin_yn')) :?>class="errortd"<?php endif;?>>

<?php if($flow->getData('admin_yn') != "y"):?>
<?php echo radiobutton_tag('admin_yn',"y");?>有
<?php echo radiobutton_tag('admin_yn',"n", array("checked"=>"checked")); ?>無
<?php else:?>
<?php echo radiobutton_tag('admin_yn',"y", array("checked"=>"checked")); ?>有
<?php echo radiobutton_tag('admin_yn',"n");?>無
<?php endif;?>

<?php echo form_error('admin_yn'); ?>
</td>
</tr>
<?php endif;?>


<tr>
<th><span class="required"></span>削除フラグ</th>
<td <?php if ($sf_request->haserror('delete_yn')) :?>class="errortd"<?php endif;?>>

<?php if($flow->getData('delete_yn') != "y"):?>
<?php echo radiobutton_tag('delete_yn',"y");?>有
<?php echo radiobutton_tag('delete_yn',"n", array("checked"=>"checked")); ?>無
<?php else:?>
<?php echo radiobutton_tag('delete_yn',"y", array("checked"=>"checked")); ?>有
<?php echo radiobutton_tag('delete_yn',"n");?>無
<?php endif;?>

<?php echo form_error('delete_yn'); ?>
</td>
</tr>

・member_add/action.class.php
public function executeValidate()を編集
    //管理者権限が有無で分岐
    if($this->getUser()->hasCredential("admin")){
        $member->setAdminYn($this->getRequestParameter("admin_yn"));
    }else{
    $member->setAdminYn("n");
    }

------------------------------4H------------------------------
★symfony
●MODELについて
データベースに接続する処理はMODELにまとめてちゃんとしたMVCの形にする
プロジェクト/lib/model/
にまとめる
まとめられた接続のためのメソッドをコントローラで呼び出すMVCの形にする
・データベースに接続するメソッドを作る
/front/default/actions/actions.class.php


        $c = new Criteria;
        $c->addDescendingOrderByColumn(CommentPeer::CREATED_AT);
        //ascはaddAscendingOrderByColumn
        //ORDER BY created_at DESCのsql文と同じ
        $this->comments = CommentPeer::doSelect($c);

↑を/lib/model/Comment::Peer.phpにコピー
$this->comments = CommentPeer::getBbsArticles();
だけ残す

・/lib/model/Comment::Peer.phpを編集
class CommentPeer extends BaseCommentPeer
{
    static function getBbsArticles(){
        $c = new Criteria;
        $c->addDescendingOrderByColumn(CommentPeer::CREATED_AT);
        return CommentPeer::doSelect($c);
    }
}
・自身のクラスを参照する場合のみ、「Peer」ではなく「salf」で参照する
class CommentPeer extends BaseCommentPeer
{
    static function getBbsArticles(){
        $c = new Criteria;
        //自身のクラスを参照する場合のみ、「Peer」ではなく「salf」で参照する
        $c->addDescendingOrderByColumn(self::CREATED_AT);
        return self::doSelect($c);
    }
}
------------------------------5H------------------------------
★symfony
●検索フォームの作成
・検索条件の設定
投稿日時の範囲指定→セレクトボックス*2
本文のワード検索→input
タイトルのワード検索→input
画像の有無→ラジオボタン
URLの有無→ラジオボタン
カテゴリ検索→セレクトボックス

・front/modules/default/templates/_kensaku.phpの作成
パーシャルをグローバルで作るなら/front/templatesに作成する

・front/modules/default/templates/indexSuccess.phpに追加
<!-- 検索フォーム -->
<?php include_partical("default/kensaku");?>
<!-- 検索フォームここまで -->

・/lib/model/Comment::Peer.phpを編集
class CommentPeer extends BaseCommentPeer
{
    static function getBbsArticles($search_arr = array()){
        $c = new Criteria;
       
        //$search_arrが存在する場合、検索条件によりadd
       
        //自身のクラスを参照する場合のみ、「Peer」ではなく「salf」で参照する
        $c->addDescendingOrderByColumn(self::CREATED_AT);
        return self::doSelect($c);
    }
}
------------------------------6H------------------------------
★symfony
●検索用のパーシャルを作成
・_kensaku.php
<?php echo form_tag("/",",method=get")?>
本文検索:
<?php echo input_tag("word", $search_arr["word"]) ?>
カテゴリ検索:
<?php echo select_tag("category", options_for_select($categorys, $search_arr["category"], array("include_blank" => true)))?>
<br>
投稿年月:
<?php echo input_date_tag("input_date_start", $search_arr["date_start"])?>

<?php echo input_date_tag("input_date_end", $search_arr["date_end"])?>
<br>
画像:
<?php echo radiobutton_tag("photo", "y")?>有
<?php echo radiobutton_tag("photo", "n")?>無
URL:
<?php echo radiobutton_tag("url", "y")?>有
<?php echo radiobutton_tag("url", "n")?>無
<br>
<?php echo submit_tag("検索")?>

</form>

・indexSuccessのカテゴリーと検索条件を_kensaku.phpにわたすために
<!-- 検索フォーム -->
<?php include_partial("default/kensaku",array("categorys"=>$categorys,"search_arr" => $search_arr));?>
<!-- 検索フォームここまで -->

・actions.class.phpの編集
        //検索のフォームを取得
        $this->search_arr = array(
        "word" => $this->getRequestParameter("word"),
        "category" => $this->getRequestParameter("category"),
        "date_start" => $this->getRequestParameter("date_start"),
        "date_end" => $this->getRequestParameter("date_end"),
        );

●検索する
・/front/module/default/actions/actions.class.phpの編集
$this->comments = CommentPeer::getBbsArticles($this->search_arr);

・/lib/model/CommentPeer.php
class CommentPeer extends BaseCommentPeer
{
    static function getBbsArticles($search_arr = array()){
        $c = new Criteria;

        //$search_arrが存在する場合、検索条件によりadd
        foreach($search_arr as $k =>$v){
            switch($k){
                case "word":
                    if($v != ""){
                        $c->add(self::CONTENT,"%{$v}%", Criteria::LIKE);
                    }
                    break;
                case "category":
                    if($v != ""){
                        $c->add(self::CATEGORY_ID, $v);
                    }
                    break;
                case "date_start":
                case "date_end":
                    if(isset($date_flg)){
                        break;
                    }
                    //一つのカラムに複数の条件をつける際にgetNewCriterion()を使う
                    if($search_arr["date_start"] && $search_arr["date_end"]){
                        $c1 = $c->getNewCriterion(self::CREATED_AT,$search_arr["date_start"], Criteria::GREATER_EQUAL);
                        $c2 = $c->getNewCriterion(self::CREATED_AT,$search_arr["date_end"], Criteria::LESS_EQUAL);
                        $c1->addAnd($c2);
                        $c->add($c1);
                    }elseif($search_arr["date_start"]){
                        $c->add(self::CREATED_AT,$search_arr["date_start"],Criteria::GREATER_THAN);
                    }elseif($search_arr["date_end"]){
                        $c->add(self::CREATED_AT,$search_arr["date_end"],Criteria::LESS_THAN);
                    }
                    $date_flg = 1;
                    break;
            }
        }

        //自身のクラスを参照する場合のみ、「Peer」ではなく「salf」で参照する
        $c->addDescendingOrderByColumn(self::CREATED_AT);
        return self::doSelect($c);
    }
}

-----------------------------memo------------------------------

2012年5月25日金曜日

2012年05月25日 講義071日目

2012年05月25日
講義071日目
------------------------------1H------------------------------
★職場体験
------------------------------2H------------------------------
★symfony
●お問い合わせフォーム作成
・contactテーブルにデータが入り、メールが飛ぶこと
ページフローを使う
symfony propel-generate-create front contact Contact
・frontのrouting.ymlを編集
contact_add:
  url:   /contact
  param: { module: contact, action: flow }
ページフローを使う時のrouting.ymlの設定はactionをflowにしておく
------------------------------3H------------------------------
★symfony
●プラグインの入れ替え
・sfPageFlowPluginをフォルダごと消去
新たに入れなおしたいバージョンをダウンロードし、入れ替える
プラグインはフォルダに存在するだけで機能してしまう
使わないプラグインは消去しておく
・newsが消えてない場合
tail /var/spool/mail/root
view /var/spool/mail/root
などで参照し、原因を探る
apacheのログを参照
  tail /etc/httpd/logs/error_log
------------------------------4H------------------------------
★symfony
●お問い合わせ
・生成されたフォームを手動で好みにカスタマイズする
・displayForm.phpを編集
タグを好みに編集したりする
テーブルの<td>部分の表示を変更
send_flgのフォームは使わないので消去
  (フラグ入力は、決め打ちにするので<tr>ごと消去)
・displayConfirm.php
各項目を日本語に
  send_flgを消去
・action.class.php
public function executeSetup()
入力画面
public function executeValidate()
エラーチェックをかけて確認画面
public function executeSubmit()
登録

ページフローではアクションとテンプレートの名前が一致しない(sfpageflowの都合)
config/pageflow.ymlにその設定が生成されている
動作をカスタマイズするために編集可能

・public function executeValidate()に対応するvalidateを作る
/contact/validete/validate.ymlの作成
・エラーチェックを書いていく
mailaddress
name
content
・作ったファイルにmailaddressの形式であるかをチェックするsfEmailValidatorをかける
fields:
  mailaddress:
    required:
      msg: メールアドレスを入力してください。
    sfEmailValidator:
      strict:       true
      email_error:  このメールアドレスは無効です。
  name:
    required:
      msg: お名前を入力してください。
  content:
    required:
      msg: 内容を入力してください。

------------------------------5H------------------------------
★symfony
●お問い合わせ
・public function executeValidate()
フラグ入力を決め打ちにする
$contact->setSendFlg($this->getRequestParameter('send_flg'));

$contact->setSendFlg("n");

●メール送信
mb_send_mail("メールアドレス","title","message");
☆注意点
①文字化けに対処(utf-8じゃない)
②送り主の指定
指定しておく方がいい
フィルターに引っかかる可能性が高いから
        mb_send_mail("メールアドレス","title",
        "TO: {$contact->getName()}様
        お問い合わせありがとうございます。
        メールアドレス:{$contact->getMailaddress()}
        お問い合わせ内容:{$contact->getContent()}"
        ,"From:サーバ管理者"
        ,"");
------------------------------6H------------------------------
★symfony
●管理者画面メンバーの登録フローの作成
・member/addのrothing.ymlの編集
member_add
  url:   /member/add
  param: { module: member_add, action: flow }
action: initialize

action: flow
・バリデーションの作成など
  後日、管理者権限を持つ者のみが変更、追加できるようにします
  決め打ちで"n"が入るようにexecuteValidateで指定し、フォームでは無視
  パスワードは隠すようにする
  nickname,mailaddress,passwordは必須項目
  mailaddressにはsfEmailValidator
  パスワードは2桁以上20桁未満制限
  可能なら
    既に存在するメールアドレスの登録は弾くように
    カスタムバリデータを作る
    削除フラグは後日ラジオボタンでON/OFFを切り替えられるようにする(現時点では"n"決め打ちでOK)
    管理者権限はそのままでOK
-----------------------------memo------------------------------
viでコピーする時に入力モードに入ってからじゃないと、ちゃんとコピーできてない確立が高いから気をつける

2012年05月24日 講義070日目

2012年05月24日
講義070日目
------------------------------1H------------------------------
★symfony
●detailのアクションを通るたびにカウントアップしていくロジック
・comment/action.class.php
    public function executeDetail()
    {
        $comment_id = $this->getRequestParameter("id");
        $this->comment = CommentPeer::retrieveByPk($comment_id);

        //access_cntの値をカウントアップ
        $access_cnt = $this->comment->getAccessCnt();
        $access_cnt++;
        $this->comment->setAccessCnt($access_cnt);
        $this->comment->save();

        $this->categorys = sfConfig::get("sf_categorys");

        return sfView::SUCCESS;
    }
・component.class.php
    public function executeAccessCountRanking()
    {
        $c = new Criteria;
        $c->addDescendingOrderByColumn(CommentPeer::ACCESS_CNT);
        $c->setLimit(5);
        $this->access_ranks = CommentPeer::doselect($c);

        //確認用↓
        //print_r($this->access_ranks);

    }

・_accessCountRanking
<?php use_helper("MyUtility")?>
<div class="componentBox" >
<h3>アクセスランキング</h3>
<?php foreach($access_ranks as $v):?>
<p>
  アクセス数:<?php echo $v->getAccessCnt()?><br>
  記事:<a href="/comment/detail/id/<?php echo $v->getId()?>"><?php echo my_mb_truncate_text($v->getContent())?></a>
</p>
<?php endforeach;?>
</div>

・ランキングを時間によって切り替えるロジックを入れてみる
<div id="contentRight">
<?php if(date("i") < 30):?>
<?php include_component("default","replyRanking");?>
  <?php else:?>
<?php include_component("default","accessCountRanking");?>
<?php endif;?>
</div>

●Criteriaでsql文を使う
発行されるSql文を参照する関数「toString」
echo $c->toString();exit;
SELECT FROM ORDER BY comment.ACCESS_CNT DESC
がメッセージとして表示される

------------------------------2H------------------------------
★symfony
●機能別にモジュールやアクションを増やす
・news
モジュール
  一日おきに削除フラグで表示しないようにcrontabで自動化
テーブルの構成
  id
  title text
  article text
  delete char(1)
  created_at datetime
 
・contact
モジュール
  お問い合わせが完了したらテーブルに保存メールを投げる
テーブルの構成
  id
  mailaddress text
  name text
  contact text
  send_flg char(1)
  created_at datetime
     
・sitemapアクション
サイトマップ
特に増える要素が無いので
・indexSuccessで表示できるように追加
<div id="header">
<?php echo link_to("トップへ","/")?>
 |
<?php echo link_to("NEWS","/news/")?>
 |
<?php echo link_to("お問い合わせ","/contact/")?>
 |
<?php echo link_to("サイトマップ","/sitemap/")?>
 |
<?php echo link_to("管理者用ページへ","/backend/")?>
</div>
------------------------------3H------------------------------
★symfony

・newsの一覧がページに表示される
毎日15時に、newsテーブル内のデータを参照し
作成時間から1週間以上経過してるレコードは削除フラグを立てて表示しないようにする
・テスト用のデータをデータベースに入れる
insert into news (title, article, delete_flg, created_at)
values("ニュース1","テスト用の記事です","n","2012-05-16 00:00:00");
・schema.ymlの中のデータベースの外部キーの設定を維持するために
sf.shonanbbs.com/config/schema.yml
    comment_id:
      type: INTEGER
      required: true
      foreignTable: comment
      foreignReference: id
をどこかにコピーしておく

mysqlで外部キー設定をしておけばこの設定は消えない
・symfony propel-build-schema
schema.ymlにコピーしておいた部分を貼り付ける
☆インデントに注意しないとsymfony propel-build-modelを打ったときにエラーがでる

schema.ymlがデータベースの構成の元に新たに作成された
・symfony propel-build-model
モデルを作成する
------------------------------4H------------------------------
★symfony


  public function executeIndex()
  {

      $c = new Criteria;
      $c->add(NewsPeer::DELETE_FLG,"y",Criteria::NOT_EQUAL);
      $c->addDescendingOrderByColumn(NewsPeer::CREATED_AT);
      $this->news_arr = NewsPeer::doSelect($c);


      return sfView::SUCCESS;
    //$this->forward('default', 'module');
  }



------------------------------5H------------------------------
★symfony
●batchフォルダ
・symfonyにおいて、自動的に動く処理をおいてくのが推奨されてる
プロジェクト/batch/にnewsAutoDelete.phpの作成

・外部からsymfonyのプロジェクト内の処理を操りたい場合、
  フロントコントローラと同様の記述が必要
フロントコントローラの記述をコピー
index.phpからコピー
define('SF_ROOT_DIR',    realpath(dirname(__FILE__).'/..'));
define('SF_APP',         'front');
//define('SF_ENVIRONMENT', 'prod');
//define('SF_DEBUG',       false);
define('SF_ENVIRONMENT', 'dev');
define('SF_DEBUG',       true);

require_once(SF_ROOT_DIR.DIRECTORY_SEPARATOR.'apps'.DIRECTORY_SEPARATOR.SF_APP.DIRECTORY_SEPARATOR.'config'.DIRECTORY_SEPARATOR.'config.php');

・データベースに接続するための処理を書く
$sfDataBaseManager = new sfDataBeseManager;
$sfDataBaseManager->initialize();
と記述するとデータベースに接続できるようになる

------------------------------6H------------------------------
★symfony
●データベースを使う処理を作ってみる
①Criteriaを使って、Newsテーブル内でdelete_flgが"y"でないものを取得

②①で取得した配列をループし、現在の時刻一週間よりも前のレコードがあったら、
delete_flgを"y"に書き換える
・デバックしたい場合は
echo date(strtotime("-1 week",time()));
などをファイルに記述しputtyからコマンドを打って表示を確認する
[nishi@localhost batch]$ php ./newsAutoDelete.php
1337238315[nishi@localhost batch]$

・デリートフラグを書き換える処理
$c = new Criteria;
$c->add(NewsPeer::DELETE_FLG,"y",Criteria::NOT_EQUAL);
$news_arr = NewsPeer::doselect($c);

$del_date = date("Y-m-d H:i:s", strtotime("-1 week"));
foreach($news_arr as $v){
    if($del_date > $v->getCreatedAt()){
        $v->setDeleteFlg("y");
        $v->save();
    }
}

・crontabの設定
[root@localhost batch]# crontab -e
* 12 * * * /usr/bin/php /home/nishi/sf.shonanbbs.com/batch/newsAutoDelete.php
毎日昼の12時に動くようになる
-----------------------------memo------------------------------

2012年05月22日 講義069日目

2012年05月22日
講義069日目
------------------------------1H------------------------------
★symfony
●部品化
・パーシャル
  テンプレートの部品化
・スロット
  データの部品化
・コンポーネント
  アクションとテンプレートで部品を作る
  部品化したいが、その部品を作成するためにはデータベースからデータを取得する必要がある場合に使用される
●コンポーネント化する
・/front/modules/default/actions/components.class.phpを作成
class モジュール名Components extends sfComponents としてクラスを定義
これまでactions.classに書いていたように、components.classにロジックを書き、テンプレートを用意する
<?php
class defaultComponents extends sfComponents{
    public function executeReplyRaning()
    {
        //return sfView::SUCCESS;
        //↑はいらないっぽい
    }
}
?>
コンポーネントだけしかないモジュールを作るのも管理が楽で良い場合がある

・/front/modules/default/templates/_replyRanking.php
何か表示テストに記述しておく
・/front/modules/default/templates/indexSuccess.php
コンポーネントを呼び出す
ウィジットが入る予定だったところに呼んでみる
<div id="contentRight">
<?php include_component("default","replyRanking");?>
</div>

●コンポーネントで掲示板のサイドバーに返信の多い記事ランキングを表示する
SELECT count(id),comment_id FROM reply GROUP BY comment_id ORDER BY count(id) DESC;
+-----------+------------+
| count(id) | comment_id |
+-----------+------------+
|         5 |          0 |
|         4 |         89 |
|         4 |         78 |
|         3 |          9 |
|         3 |          1 |
|         3 |         37 |
|         2 |       NULL |
|         1 |         10 |
|         1 |         11 |
|         1 |         15 |
|         1 |         17 |
|         1 |          2 |
+-----------+------------+
12 rows in set (0.01 sec)
を表示させる
------------------------------2H------------------------------
★symfony
●部品化
・Criteria
doSelect()
doSelectOne()
↑ではカラム名を指定してデータを取得することはできない
doSelectRS()
を使うとデータを絞り込める
リソース型で取得
doSelectRS()でデータを絞り込んで取得する方法
doSelect()でデータを取得して、その後ロジックで絞り込む方法
・components.class.php
doSelectRS()を使う
<?php
class defaultComponents extends sfComponents{
    public function executeReplyRanking()
    {
        //返信の多いランキングを表示する

        //doSelectRS()で実装
        $c = new Criteria();

        //選択するカラムの設定をクリア
        $c->clearSelectColumns();

        //必要なカラムを設定
        $c->addSelectColumn(ReplyPeer::COMMENT_ID);
        $c->addSelectColumn("COUNT(COMMENT_ID)");

        //GROUP BY命令を指定
        $c->addGroupByColumn(ReplyPeer::COMMENT_ID);

        //doSelectRSで取得し、配列に格納
        $result = array();
        $rs = ReplyPeer::doSelectRS($c);
        $rs->setFetchMode(ResultSet::FETCHMODE_ASSOC);
        while ($rs->next()) {
            $result[] = $rs->getRow();
        }
        print_r($result);

    }
}
?>
・_replyRanking.php
テンプレート側で表示の外枠だけ作っておく
<div class="componentBox" >
<h3>返信数ランキング</h3>
<p>
  返信数:10<br>
  記事:<a href="/">この投稿はテスト...</a>
</p>
<p>
  返信数:4<br>
  記事:<a href="/">この投稿はテスト...</a>
</p>
</div>
------------------------------3H------------------------------
★symfony
●部品化
・取得したデータをロジックで絞り込む
返信数が多い順の配列になること
要素数が5つの配列になること

・コンポーネントに追記
        $arr = array();
        foreach($result as $value){
            if(CommentPeer::retrieveByPk($value["COMMENT_ID"])){
                $arr[$value["COMMENT_ID"]] = $value["COUNT(COMMENT_ID)"];
            }
        }
        arsort($arr);
        $this->replyranks = array();
        $cnt = 0;
        foreach($arr as $k => $v){
            $this->replyranks[]=array("cnt" => $v,"obj" => CommentPeer::retrieveByPk($k));
            $cnt++;
            if($cnt >= 5){
                break;
            }
        }
        //表示テスト↓
        //print_r($this->replyranks);exit;

・テンプレート
<?php use_helper("MyUtility")?>
<div class="componentBox" >
<h3>返信数ランキング</h3>
<?php foreach($replyranks as $v):?>
<p>
  返信数:<?php echo $v["cnt"]?><br>
  記事:<a href="/"><?php echo my_mb_truncate_text($v["obj"]->getContent())?></a>
</p>
<?php endforeach?>
<p>
  返信数:test<br>
  記事:<a href="/">この投稿はテスト...</a>
</p>
</div>
※my_mb_truncate_text()で表示を短くしたりは好みで
------------------------------4H------------------------------
------------------------------5H------------------------------
------------------------------6H------------------------------
★symfony
●部品化
・コメントの詳細ページを作り、アクセス数をログ、サイドバーにアクセス数ランキングを表示する
  「アクセス数ランキングを出力するコンポーネント」を作成すること
  アクション名:accessCountRanking

●実際にやってみる
・コメントの詳細ページを作る
  comment モジュールを作成
  default アクションを作成
    idを受け取って、そのid番号のコメントと返信のみを出力するページ
    機能として、そのアクションが読み込まれた回数を記録しておく
・commentテーブルに「access_cnt」カラムをint型で作成し、アクションが読み込まれるたびにカウントアップしていくようにする!!!注意点!!
    カラムを新規追加した後はpropel-build-schema、propel-build-modelを実行するが、
    schema.ymlに手動で追加した外部キー設定などが残るか確認しておく

☆作業中に引っかかったところ
●コメントの詳細ページを作る
・executeDetail()に対応させるべきdetailSuccess.phpを作成してなかった
・symfony propel-build-modelを打ってなかった
・schema.ymlに手動で追加した外部キー設定などが残るか確認しておく
    残って無かったから追記した
    comment_id:
      type: INTEGER
      required: true
      foreignTable: comment
      foreignReference: id
・actionでカテゴリーを読み込んでなかった
    $this->categorys = sfConfig::get("sf_categorys");

●commentテーブルに「access_cnt」カラムをint型で作成し、アクションが読み込まれるたびにカウントアップしていくようにする!・sqlコマンドを忘れてた(phpmyadminでやった)→ALTER TABLE `comment` ADD `access_cnt` INT NOT NULL AFTER `created_at`
-----------------------------memo------------------------------

2012年5月21日月曜日

2012年05月21日 講義068日目

2012年05月21日
講義068日目
------------------------------1H------------------------------
★smartyの復習
●VMwareでsmartyを使う
・smarty用のディレクトリをつくるなど
[nishi@localhost ~]$ cd sm.test.com/
[nishi@localhost sm.test.com]$ su -
パスワード:
[root@localhost ~]# vi /etc/httpd/conf.d/httpd-vhost.conf
<VirtualHost *:80>
    ServerName sm.test.com
    DocumentRoot /home/nishi/sm.test.com
    <Directory "/home/nishi/sm.test.com">
        AllowOverride All
        Options -Includes -ExecCGI
    </Directory>

[root@localhost ~]# /etc/init.d/httpd restart
httpd を停止中:                                            [  OK  ]
httpd を起動中:                                            [  OK  ]   

・hostsの編集
SwichHostsでVMwareにつながるように設定
・smartyのインストール
libsの設置
・Smartyを使う
templates
templates_c
・chmod 777
[root@localhost sm.test.com]# ls -l
合計 16
-rw-rw-r-- 1 nishi nishi   19  5月 21 10:26 index.php
drwxrwxr-x 4 nishi nishi 4096  5月 21 10:32 libs
drwxrwxr-x 2 nishi nishi 4096  5月 21 10:34 templates
drwxrwxr-x 2 nishi nishi 4096  5月 21 10:35 templates_c
[root@localhost sm.test.com]# chmod 777 templates
[root@localhost sm.test.com]# chmod 777 templates_c
[root@localhost sm.test.com]# ls -l
合計 16
-rw-rw-r-- 1 nishi nishi   19  5月 21 10:26 index.php
drwxrwxr-x 4 nishi nishi 4096  5月 21 10:32 libs
drwxrwxrwx 2 nishi nishi 4096  5月 21 10:34 templates
drwxrwxrwx 2 nishi nishi 4096  5月 21 10:35 templates_c
・displayでテンプレートを呼び出す
index.tpl
<div id="contentWrap">
<h1>テスト</h1>
</div>
------------------------------2H------------------------------
★smartyの復習

・index.php
<? php
require_once("./libs/Smarty.class.php");
$sm = new Smarty;
$sm->display("index.tpl");

・assign
phpとtplで情報の受け渡し
index.tpl
{$categorys.1}

index.php
$sm->assign("categorys", array("勉強","遊び","その他"));

・foreach
ループさせる
{foreach from=$categorys item=category key=k}
カテゴリー:{$category}<br>
{/foreach}

・{* コメント*}
コメント

・include
{include file="header.tpl"}
他の.tplファイルを読み込む

・fetch
ロジック次第で切り替えるときに使用
index.php
$sitemenu = $sm->fetch("sitemenu.tpl");
$sm->assign("sitemenu",$sitemenu);

index.tpl
<div id="sitemenu">
{$sitemenu}
</div>

sitemenu.tpl
<ul>サイトメニュー
{foreach from=$menuarr item=menu key=k}
  <li><a href="{$k}">{$menu}</a></li>
{/foreach}
</ul>

・直接テンプレートでセッションを使うとき
index.php
$_SESSION["nowtime"] = date();

index.tpl
現在の年月日時:{$smarty.session.nowtime}

・getとか使う場合
GETで渡ってきた値:{$smarty.get.id1}と{$smarty.get.id2}
<form action="/" method="get">
<input type="text" name="id1">
<input type="text" name="id2">
<input type="submit" value="送信">
</form>

・|htmlspecialcharsなどの関数を使う
{$smarty.get.id2|htmlspecialchars}

●smartyとは関係ないおまけ
・関数のスコープの外側でも参照できる定数を作る
$_SESSIONとかが定数

例)関数を作る
$_SESSION["nowtime"] = getNowDate();

function getNowDate(){
    $date = date("Y-m-d H:i:s");
    return $date;
}

・定数を定義する
//定数を定義するための関数
define(NOW_TIME, date("Y-m-d H:i:s"));

作られた定数を使う
function getNowDate(){
    $date = NOW_TIME;
    return $date;
}

・コーディング規約
用意されてる定数と違い、頭に$は付けない
大文字と_のみで作る
別ファイルでは使えないので、定数を設定したファイルを用意して読み込むのがいい
------------------------------3H------------------------------
★smartyテスト
------------------------------4H------------------------------
★symfony
●url直打ち対策
executeIndex()
        //URL直打ち対処
        $this->bbs_submit_check = rand();
        $this->setflash("bbs_submit_check",$this->bbs_submit_check);
executeSubmit()
        //URL直打ち対処
        if($this->getRequestParameter("bbs_submit_check") !=
           $this->getflash("bbs_submit_check") ||
           $this->getRequestParameter("bbs_submit_check") == ""
           )
        {
            $this->redirect("/");
        }
        $this->setflash("bbs_submit_check","");
indexSuccess

・replayにも直打ち対策を入れる

        if($this->getflash("reply_result_check") == $this->getRequestParameter("reply_result_check")
        && $this->getRequestParameter("reply_result_check") != "")
        {
         省略
        }

セッションをクリアする
$this->setflash("reply_result_check","");

sf.shonanbbs.com/reply/result/comment_id/89などで直打ちしてトップにリダイレクトする

------------------------------5H------------------------------
★symfony
●url直打ち対策
・executeConfrm()

        $hostname = sfConfig::get("sf_hostname");
        $ref = $this->getRequest()->getReferer();
        if($ref != $hostname."reply/confirm" && srtpos($ref, $hostname,"reply/index"!== false))
        {
            $this->redirect("/");
        }

sf.shonanbbs.com/reply/confirmを直打ちしてテスト

●プラグイン
・sfPageFlowのインストール
symfonyのCRUD機能を強化してくれる
https://github.com/tumf/Symfony1.0_sfPageFlowPlugin
フォルダ名が長いのでsfPageFlowPluginにリネーム
/pulginにコピー
・自動生成タスクの設置
data/tasks
  コマンド対処
  /dataに/tasksを設置
アドオン
  symfony側でのロジック
  symfonyをインストールした場所に設置
スケルトン
  作成される雛形
  symfonyをインストールした場所に設置
 
[root@localhost nishi]# cp sfPropel* /usr/share/pear/symfony/addon/propel/generator
[root@localhost nishi]# cp -rf generator/sf* /usr/share/pear/data/symfony/generator
上書きは許可
環境によってアドオンとスケルトンを置く場所は異なるので調べてから置く
symfony propel-generate-create backend member_add Member

------------------------------6H------------------------------
★symfony
●プラグイン
・data/tasks
#CREATE
symfony propel-generate-create アプリケーション名 モジュール名 モデル名
#EDIT
symfony propel-generate-edit アプリケーション名 モジュール名 モデル名
#LIST
symfony propel-generate-list アプリケーション名 モジュール名 モデル名
が使えるようになった
・プラグインの消去
ファイルを消去すればいい
・pageflow.ymlで設定を編集する
Processはactionのこと
Displayはtemplateのこと

firstState: ProcessInitialize←ここに最初にたどり着く
lastState:  DisplayResult←最後にここにたどり着く
・新規追加のリンクを有効にする
実際のurlと飛ばす先が違うのでルーティングで制御
routhing.ymlに
member_add
  url:   /member/add
  param: { module: member_add, action: initialize }
を追加
-----------------------------memo------------------------------

2012年5月18日金曜日

2012年05月18日 講義068日目

2012年05月18日
講義068日目
------------------------------1H------------------------------
★symfonyを使ってサイトを作成する
・各項目のリストを表示できるようにする
------------------------------2H------------------------------
・データベースのカラム名などを変更
symfony propel-build-schema
symfony propel-build-model
symfony cc
でschema.ymlのDBの内容を更新する
・マイアカウントモジュールをbackendに作成
backendのテンプレートが見えてしまう問題
frontに作るべきだったか?
admin_ynがyの時だけメニューが表示されるロジックを追加


☆あとでやること、気が付いたこと
・officeのカテゴリーが表示されるようにする
app.ymlに追加
・予約システムの見直し
ログインしてるアカウント(それともメニューに組み込むか?)に
自分が予約してる一覧が欲しい
・管理者ページでなくても予約とその解除が可能になるようにしなければならない?
・プロジェクト別にソートできるようなカラムを予約テーブルと使用中テーブルに作るといいかも
・メンバーが進行中のプロジェクトも一覧に必要か?
・プロジェクト別のメニューもあると使えるかも?(散漫になる可能性もあるけど)
・バリデーション
・url直打ち対策
・フォームを使う
------------------------------3H------------------------------
★symfonyを使ってサイトを作成する
●発表
・スケジュール管理、祝日決定のロジック作るのがめんどくさそう
google calenderと連動できればいいなーとか
・フラグの立て方を学ばねばならんなという感想
・フォルダ構成などはフレームワークの意図によって配置したほうが効率がいい
------------------------------4H------------------------------
★symfonyを使ってサイトを作成する
●発表
・symfonyの機能でカラム名をupdate_atにすると自動で更新時間を更新してくれる
・検索を実装したいという感想
・削除フラグで管理するべき
------------------------------5H------------------------------
★symfonyを使ってサイトを作成する
●発表
・jsファイルの読み込みはパーシャルにまとめてそれを読み込めばソースがすっきりする
------------------------------6H------------------------------
★symfony
●shonanbbsの拡張
・掲示板トップページにバリデーション
内容/名前が空のときは弾くように変更
①モジュール下のvalidateディレクトリの下に、
送信先のアクション名でymlファイルを作成
バリデーションのルール(必須、項目、数字のみ、等)を記述
fields:
  content:
    required:
      msg: 内容を入力してください。
  nickname:
    required:
      msg: 名前を入力してください。
②actions.class.phpにバリデーションに引っかかった際に、動作するアクションを作成する
handleErrorという名前から始まるメソッド
    public function handleErrorSubmit()
    {
        $this->request->setParameter("id",$this->getRequestParameter("comment_id"));
        $this->request->setParameter("nickname",$this->getRequestParameter("nickname"));
        $this->request->setParameter("content",$this->getRequestParameter("content"));

        $this->forward("default","index");
    }
③テンプレートにエラーメッセージを出すようにする
indexSuccess.phpの一行目に
<?php use_helper("Validation")?>
<?php echo form_error("nickname")?>
<?php echo form_error("content")?>
をエラーメッセージを出したい場所に記述する
①のためにapps/front/default/validate/submit.ymlを作成
②のためにapps/front/default/actions/actions.class.php内にhandleErrorSubmitメソッドを作成


・cssでクラスを指定してやればエラーの表示を操れる
.form_error {
    color: red;
}
・front/default/indexにバリデーションで引っかかったら取得する値を指定しておく
        //バリデーションに引っかかったら取得
        $this->nickname = $nickname = $this->getRequestParameter("nickname");
        $this->content = $content = $this->getRequestParameter("content");
・indexSuccess.phpを
内容<br>
<?php echo textarea_tag("content", $content ,array("rows"=>10, "cols"=>55))?><br>
<br>
<?php echo form_error("content")?>
名前<br>
<?php echo input_tag("nickname", $nickname ,array("size" => 20)) ?><br>
<?php echo form_error("nickname")?>
こんな感じに
input_tagの第二引数を""からfront/default/indexで取得した変数に変更
-----------------------------memo------------------------------
アマゾンのAPIを使ったサイト
画像を多用するサイトはサムネイルの扱いに注意

2012年05月17日 講義066日目

2012年05月17日
講義066日目
------------------------------1H------------------------------
★symfony
●symfonyを使ってサイトを作成する
・サイトのレイアウト、構成を表示させる
・内容は後で作っていく
------------------------------2H------------------------------
・backendの作成
/webにバックエンドフォルダの作成とbackend.php、backend_dev.phpのコピー
backendのフロントコントローラ(backend.php、backend_dev.php)の内容の編集
.htaccesの編集
symfonyのシンボリックリンクの作成
(デバック用の表示等のためだけではなく、フロントコントローラを新たに作成したら必須っぽいので作ってく)

------------------------------3H------------------------------
・backendの外見を大体作る
------------------------------4H------------------------------
・なんか色々がんばる
------------------------------5H------------------------------
・テンプレートのリンクを権限によって増やしたりする際に
<a href="logout">ログアウト</a>
<?php if($sf_user->hasCredential("admin")):?>
  <a href="adminyou">管理者用ページへ</a>
<?php end if;?>

というメモ
を参考にして、結果こうなった↓
            <li><a href="/member/"><?php echo $sf_user->getAttribute("username", sfConfig::get("sf_session_name"))?>さんの情報</a></li>
<?php if($sf_user->getAttribute("admin_yn", sfConfig::get("sf_session_name")) =="y"):?>
            <li><a href="/backend/">編集ページへ</a></li>
<?php endif;?>
------------------------------6H------------------------------
・ログイン機能作成
バリデーションとかはできてないのでセッションに値を入れるだけのやつになってる
htmlで作られたリンク→ブラウザ→フロントコントローラ
phpで作られたリンク→フロントコントローラ
になるので挙動が違う
appが違う場所へのリンク作成には注意
-----------------------------memo------------------------------

2012年5月17日木曜日

2012年05月16日 講義065日目

2012年05月16日
講義065日目
------------------------------1H------------------------------
★symfony
●symfonyを使ってサイトを作成する
・データベースの構成
------------------------------2H------------------------------
・仕様書の作成
------------------------------3H------------------------------
・suymfonyプロジェクトの作成
・データベースの作成
・データベースにテストのためのサンプルデータを作成
------------------------------4H------------------------------
・appとmodの作成
------------------------------5H------------------------------
・ORマッパの設定
・設定ファイルを編集し、各ページの表示確認
------------------------------6H------------------------------
・Criteriaを使用してデータベースの表示を確認
-----------------------------memo------------------------------

2012年05月15日 講義064日目

2012年05月15日
講義064日目
------------------------------1H------------------------------
★symfony
●部品化
・スロット
パンくずなどに使う場合が多い
layout.phpを編集
backend/config/view.ymlを読み込んでる部分を編集

<?php include_title() ?>

<!-- テンプレートにスロットがあれば読み込み、無ければデフォルトを読み込む -->
<?php if(has_slot("title")):?>
  <?php incleude_slot("title")?>
<?php else:?>
  <?php include_title() ?>
<?php endif;?>

切り替わるスロット部分を書く
backend/modules/comment/templates/listSuccess.php
<?php slot("title");?>
<title>管理画面 コメント一覧</title>
<?php end_slot();?>
・コンポーネント
は、またこんど
データベースの情報を元に動的に表示させたい部分を作る
●コメント一覧のcssを調整
・commentモジュールのテンプレートにテーブルタグにcssを反映させる
<table class="tblData">
・トランケートはヘルパーでやる
find ./ -name * php | xargs grep link_to
で探すとヘルパー関数の場所がわかる
------------------------------2H------------------------------
★symfony
●ヘルパーの作成
/lib/helperを作成
・MyUtilityHelper.php
<?php

function my_mb_truncate_text($text, $length = 30, $truncate_string = '...', $truncate_lastspace = false)
{
    mb_internal_encoding("utf-8");

    if ($text == '') {
        return '';
    }

    if (mb_strlen($text) > $length) {

        $truncate_text = mb_substr($text, 0, $length - strlen($truncate_string));

        if ($truncate_lastspace) {
            $truncate_text = mb_preg_replace('/\s+?(\S+)?$/', '', $truncate_text);
        }

        return $truncate_text.$truncate_string;

    } else {
        return $text;
    }
}

comment/listSuccess
一番上に
<?php use_helper("MyUtility")?>
を記述してヘルパーを読み込む
テーブルを表示させてる部分にヘルパーの関数を噛ませる
      <td><?php echo my_mb_truncate_text($comment->getNickname()) ?></td>
      <td><?php echo my_mb_truncate_text($comment->getContent()) ?></td>
・カテゴリーを読み込む
<tbody>の下あたりに
<?php $categorys = sfConfig::get("sf_categorys")?>
を記述
三項演算子でカテゴリー部分の表示エラーが出ないように""は「なし」と表示されるようにする
<td><?php echo ($comment->getCategoryId() != "")?$categorys[$comment->getCategoryId()]:"なし"; ?></td>
●自動生成されたテンプレートを編集する
・Nickname
object_textarea_tag

  <th>Nickname:</th>
  <td><?php echo object_input_tag($comment, 'getNickname', array (
  'size' => '30',
)) ?></td>
・Category
<th>Category:</th>
<?php echo object_input_tag($comment, 'getCategoryId', array (
  'size' => 7,
)) ?></td>

<?php $categorys = sfConfig::get("sf_categorys")?>
  <td>
  <?php echo select_tag("category_id", option_for_select($categorys,$comment->getCategoryId()))?>
</td>
・photo
  <th>Photo:</th>
  <td><?php echo object_textarea_tag($comment, 'getPhoto', array (
  'size' => '30x3',
)) ?></td>

・default.css
#content

#contentWrapper
・apps/backend/
・backend/modules/dafault/actions/actions.class.php
のホスト名きめ打ちのところをsetting.ymlの情報を元にするように変更

------------------------------3H------------------------------
★symfony

/backend/modules/comment/actions/actions.class.php
の、executeUpdateメソッド内
        $photo = $this->getRequest()->getFile('photo');

        $comment->save();
        if($photo["tmp_name"])
        {
            $filename = $comment->getId().".jpg";
            $this->getRequest()->moveFile("photo",sfConfig::get('sf_web_dir')."/images/comment/".$filename);
            $comment->setPhoto($filename);
            $comment->save();
        }
●サムネイルを表示させる
・editSuccess.php
  <th>Photo:</th>
  <td>
<?php if($comment->getPhoto()):?>
  <img src="/images/comment/<?php echo $comment->getPhoto()?>"width="100">
<?php endif;?>
  <br>
<?php echo input_file_tag("photo")?>
  </td>
・showSuccess.php
ヘルパーを使う
<th>Photo: </th>
<td>
<?php echo image_tag(sfConfig::get("sf_hostname")."images/comment/".$comment->getPhoto(),array("width" => 100))?>
</td>
</tr>
------------------------------4H------------------------------
★symfony
●symfonyを使ってサイトを作成する
・施設・備品管理システムの作成

・施設情報のCRUD(部屋情報)
施設名、部屋名、階などの情報
試用期間
・備品情報のCRUD
新規データベースの作成
データベース:mismanage
プロジェクト:sf.mismanage.com
備品名
個数
  使用個数
  残個数
平時の置き場所
(使用期間)
・共通情報
使用者
用途
登録者
作成日
更新日
------------------------------5H------------------------------
★symfony
●symfonyを使ってサイトを作成する
・下準備
データベースの作成
vhostとHostsファイルの編集
symfonyプロジェクトの作成
------------------------------6H------------------------------
★symfony
●symfonyを使ってサイトを作成する
・データベース構成と正規化
-----------------------------memo------------------------------

2012年5月14日月曜日

2012年05月14日 講義063日目

2012年05月14日
講義063日目
------------------------------1H------------------------------
★symfony
●ログアウトモジュールの作成
・backendのyaloutにlogoutへのリンクを作成
<?php echo link_to("ログアウト","/logout")?>
・setting.yml
no_script_nameをon
・コマンドでモジュールを作成
[nishi@localhost ~]$ cd sf.shonanbbs.com/
[nishi@localhost sf.shonanbbs.com]$ symfony init-mod backend logout
・/apps/backend/modules/actions/logout.php
        //認証済み解除
        $this->getUser()->setAuthenticated(false);
        //権限のクリア
        $this->getUser()->clearCredentials();
        //sessionの開放
        $this->getUser()->getAuttributeHolder()->removeNamespace(sfConfig::get('sf_session_name'));

        //ホームページに戻る
        return $this->redirect('/');
        //$this->forward('default', 'module');
・seting.ymlの変更
#all
のコメントアウトをはずす


------------------------------2H------------------------------
★symefony
●ログインに飛ばす処理をbackendに作る
・backend/modules/actions/action.class.php
    public function executeLogin()
    {
        $this->redirect("http://sf.shonanbbs.com/login");
    }
・front/modules/actions/action.class.php
バリデーション(エラーチェック)
<?php use_helper("Validation")?>

<?php echo form_tag('login/index')?>
↑で指定したactionにメソッドを書く
・apps/front/modules/validate/index.ymlの作成
fields:
  mailaddress:
    required:
      msg: メールアドレスを入力してください。
    sfEmailValidator:
      sfrict:        true
      email_error: このメールアドレスは無効です

  password:
    required:
      msg: パスワードを入力してください。
    sfStringValidator:
      min:          2
      min_error:    少なくとも2文字入力してください。
      max:          20
      max_error:    20文字以下で入力してください。
------------------------------3H------------------------------
★symefony
●バリデーション
・/apps/front/mudules/actions/action.class.php
executeIndex()をexecuteSubmit()に変更
    public function executeSubmit()
    {
        $this->mailaddress = $this->getRequestParameter('mailaddress');
        $this->password = $this->getRequestParameter('password');

        if($this->mailaddress !='' && $this->password != '')
        {
            //メールアドレスとパスワードを元にmemberテーブルのインスタンス取得
            $c = new Criteria;
            $c->add(MemberPeer::MAILADDRESS, $this->mailaddress);
            $c->add(MemberPeer::PASSWORD, $this->password);
            $member = MemberPeer::doSelectOne($c);
            //$member = MemberPeer::retrieveByPassword($this->mailaddress);

            if($member)
            {
                //ログイン状態にする
                $this->getUser()->setAuthenticated(true);
                $this->getUser()->clearCredentials();
                $this->getUser()->addCredential('member');

                //会員情報をセッションにセット
                $this->getUser()->setAttribute('member_id',$member->getId(),sfConfig::get('sf_session_name'));
                $this->getUser()->setAttribute('nickname', $member->getNickname(), sfConfig::get('sf_session_name'));
                $this->redirect('/backend');
            }

        }
        $this->redirect("/");
        //$this->forward('default', 'module');
    }
・新しくexecuteIndex()を作成
    public function executeIndex()
    {
        $this->mailaddress = $this->getRequestParameter('mailaddress');
        return sfView::SUCCESS;
・indexSuccessをエラーメッセージ表示箇所を変更
・パスワード部分も変更
<?php echo input_password_tag('password', "", array('size' => 50));?>
第二引数を""にして表示されないようにする
・/apps/front/mudules/actions/action.class.php
    //バリデーションに引っかかったら動く処理
    public function handleErrorSubmit()
    {
        $this->request->setParameter("mailaddress", $this->getRequestParameter('mailaddress'));
        $this->forward("login", "index");

    }
------------------------------4H------------------------------
★symfony
●カスタムバリデーター
・submit.yml
myLoginCheckValidator:の作成
mailaddress:内に
   myLoginCheckValidator:
     login_error: 一致するユーザがいませんでした。
を書き加える
・/lib/model/validatorフォルダの作成
・myLoginCheckValidator.class.php
<?php
class myLoginCheckValidator extends sfValidator
{
    public function execute(&$value, &$error)
    //$value,$errorはフォームから受け取ったデータ
    {
        //バリデート内での他のリクエストやユーザ情報の取得方法
        $request = sfContext::getInstance()->getRequest();
        $user = sfContext::getInstance()->getUser();

        $mailaddress = $request->getParameter("mailaddress");
        $password = $request->getParameter("password");

        $c = new Criteria;
        $c->add(MemberPeer::MAILADDRESS, $mailaddress);
        $c->add(MemberPeer::PASSWORD, $password);
        $member = MemberPeer::doSelectOne($c);

        //メールアドレスとパスワードが一致するレコードが無いなら
        if(!$member)
        {
            $error = this->getParameter("login_error");
            return false;
        }
        return true;

    }
}
?>
------------------------------5H------------------------------
★symfony
●404エラーを吐いたときに/に飛ばす
・backned/modules/default//action.class.php
    public function executeError404()
    {
        $this->redirect("/");
    }
・RewriteRule ^(backend/.*)$ backend/backend.php [QSA,L]

・backend/config/setting.yml
#    error_404_module:       default   # To be called when a 404 error is raised
#    error_404_action:       error404  # Or when the requested URL doesn't match any route

    error_404_module:       default   # To be called when a 404 error is raised
    error_404_action:       error404  # Or when the requested URL doesn't match any route
・frontにも適用させる
front/default/actions/action.class.phpにも
    public function executeError404()
    {
        $this->redirect("/");
    }
    を作成
front/config/setting.ymlも同様に変更
●[nishi@localhost sf.shonanbbs.com]$ symfony propel-generate-crud backend comment Comment
Commentテーブルのcrudを行う、commentモジュールをbackendに作る
/apps/backend/modules/comment/actions/action.class.phpが作成される
・管理者画面のエスケープ
backend/config/setting.yml
#    escaping_strategy:      bc        # Determines how variables are made available to templates. Accepted values: bc, both, on, off. The value off deactivates escaping completely and gives a slight boost.
#    escaping_method:   ESC_ENTITIES   # Function or helper used for escaping. Accepted values: ESC_RAW, ESC_ENTITIES, ESC_JS, ESC_JS_NO_ENTITIES.

    escaping_strategy:      both        # Determines how variables are made available to templates. Accepted values: bc, both, on, off. The value off deactivates escaping completely and gives a slight boost.
    escaping_method:   ESC_ENTITIES   # Function or helper used for escaping. Accepted values: ESC_RAW, ESC_ENTITIES, ESC_JS, ESC_JS_NO_ENTITIES.

・バリデーションエラー
#    validation_error_prefix:    ' &darr;&nbsp;'
#    validation_error_suffix:    ' &nbsp;&darr;'

    validation_error_prefix:    ''
    validation_error_suffix:    ''
------------------------------6H------------------------------
★symfony
●app.yml
/config/settings.php
all:
  .globals:
    categorys:
      1: 勉強について
      2: 遊びについて
      3: その他
をbackend/config/app.ymlにコピー
どちらからでも読み込めることを確認するためのテスト

●CRUDに際し、URL直打ちを回避する
/backend/comment/update
と直打ちしたら弾かれて管理画面のトップページへ飛ぶこと
http://sf,shonanbbs.com/backend/comment/create
http://sf,shonanbbs.com/backend/comment/edit/id/87
↑らのいずれかから、saveボタンを押して新規作成、更新ができること

    public function executeUpdate()
    {
        $create_url = sfConfig::get("sf_hostname")."backend/comment";
        $edit_url = sfConfig::get("sf_hostname")."backend/comment/edit/id";
        $ref = $this->getRequest()->getReferer();

        if(!(
        $ref == $create_url || strpos($ref, $edit_url) === 0))
        {
            $this->redirect("/");
        }
●部品化
・パーシャル
テンプレート単位の部品
・スロット
データ単位の部品
・コンポーネント
データベース、ロジック、テンプレート全てが入った部品
●メニューを部品化
・/backend/templates/_menu.phpを作成
/backend/templates/layout.phpの内容を_menu.phpに移動
・<div id="contentRight"></div>の中身を_menu.phpに移動
・layout.phpでincludeする
  <div id="contentRight">
<?php include_partial("global/menu")?>
  </div>
-----------------------------memo------------------------------

2012年5月11日金曜日

2012年05月11日 講義062日目

------------------------------1H------------------------------
★symfony
●画像
・image_tag()
<?php echo image_tag("comment/".$comment->getPhoto(),array("width" => 100))?>
●アクセス制御
・管理画面を作る
[nishi@localhost ~]$ cd sf.shonanbbs.com/
[nishi@localhost sf.shonanbbs.com]$ symfony init-app backend

[nishi@localhost sf.shonanbbs.com]$ symfony init-mod backend default
・/web/backendの作成
/web/backend/に
/web/backend.php
/web/backend_dev.php
を移動
・フロントコントローラを書き換える
<?php
#パスを/web/backendになるように変更↓
define('SF_ROOT_DIR',    realpath(dirname(__FILE__).'/../..'));
define('SF_APP',         'backend');
#本番環境にするには8,9行目を消して6,7行目のコメントをはずす
#define('SF_ENVIRONMENT', 'prod');
#define('SF_DEBUG',       false);
define('SF_ENVIRONMENT', 'dev');
define('SF_DEBUG',       true);

require_once(SF_ROOT_DIR.DIRECTORY_SEPARATOR.'apps'.DIRECTORY_SEPARATOR.SF_APP.DIRECTORY_SEPARATOR.'config'.DIRECTORY_SEPARATOR.'config.php');

sfContext::getInstance()->getController()->dispatch();
・.htaccessを移動
[nishi@localhost sf.shonanbbs.com]$ cd web
[nishi@localhost web]$ ls
backend  css  front_dev.php  images  index.php  js  robots.txt  sf  uploads
[nishi@localhost web]$ ls -a
.   .htaccess  css            images     js          sf
..  backend    front_dev.php  index.php  robots.txt  uploads
[nishi@localhost web]$ cp .htaccess backend/
[nishi@localhost web]$ ls -a backend
.  ..  .htaccess  backend.php  backend_dev.php
[nishi@localhost web]$
・.htaccessの書き換えてbackend用を作る
☆の行を書き換える
[nishi@localhost web]$ vi backend/.htaccess

  # uncomment the following line, if you are having trouble
  # getting no_script_name to work
☆RewriteBase /backend/

  # we skip all files with .something
  # comment the following 3 lines to allow periods in routes
  RewriteCond %{REQUEST_URI} \..+$
  RewriteCond %{REQUEST_URI} !\.html$
  RewriteRule .* - [L]

  # we check if the .html version is here (caching)
  RewriteRule ^$ index.html [QSA]
  RewriteRule ^([^.]+)$ $1.html [QSA]
  RewriteCond %{REQUEST_FILENAME} !-f

  # no, so we redirect to our front web controller
☆RewriteRule ^(.*)$ backend.php [QSA,L]
</IfModule>

# big crash from our front web controller
ErrorDocument 500 "<h2>Application error</h2>symfony application failed to start properly"
------------------------------2H------------------------------
★symfony
●backendを作成
・フロントコントローラが違う場合は参照フォルダを別で作る
・/web/backend/cssを作って管理画面用のdefault.cssを置く
・backendのview.ymlの書き換え
default:
  http_metas:
    content-type: text/html

  metas:
    title:        管理画面
    robots:       index, follow
    description:  SHONANBBS管理画面
    keywords:     BBS, 管理
    language:     ja

  stylesheets:    [default]

  javascripts:    []

  has_layout:     on
  layout:         layout

・layout.ymlを書き換える
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>

<?php include_http_metas() ?>
<?php include_metas() ?>

<?php include_title() ?>

<link rel="shortcut icon" href="/favicon.ico" />

</head>
<body>
<h1>symfony版SHONANBBS 管理画面</h1>
<hr>
<div id="content">

  <div id="contentLeft">
<?php echo $sf_data->getRaw('sf_content') ?>
  </div>

  <div id="contentRight">
  MENU
  <ul>
  <li><a href="/">掲示板トップ</a></li>
  <li><a href="/backend">管理画面トップ</a></li>
  <li><b>ユーザ管理</b>
    <ul class="submenu">
    <li><a href="/backend/member/add">新規追加</a></li>
    <li><a href="/backend/member/list">一覧</a></li>
    </ul>
  </li>
  <li><b>コメント管理</b>
    <ul>
    <li><a href="/backend/comment/list">一覧</a></li>
    </ul>
  </li>
  </ul>

  </div>

</div>

</body>
</html>
・管理画面のデバックモードの表示を良くする
シンボリックリンク作成
[nishi@localhost backend]$ ls
backend.php  backend_dev.php  css
[nishi@localhost backend]$ ln -s /usr/share/pear/data/symfony/web/sf ./sf
[nishi@localhost backend]$ ls
backend.php  backend_dev.php  css  sf
[nishi@localhost backend]$

frontでは/webにシンボリックリンクを作成する
backendにも作らないと色々と表示されないっぽい

[nishi@localhost backend]$ ln -s /usr/share/pear/data/symfony/web/sf ./sf
[nishi@localhost backend]$ ls
backend.php  backend_dev.php  sf←コレ!
[nishi@localhost backend]$
[nishi@localhost backend]$

------------------------------3H------------------------------
------------------------------4H------------------------------
★symfony
●先行教室見学
------------------------------5H------------------------------
★symfony
●管理画面
・ログインモジュールの作成
[nishi@localhost sf.shonanbbs.com]$ symfony init-mod front login
・/apps/backend/config/security.ymlの修正
権限を持っていなかったらログインモジュールに飛ばす処理を書く
all:
  is_secure: on
  credentials: [ member ]
・/apps/front/login/templates/indexSuccess.php
<?php use_helper("Validation")?>

<?php form_tag('login/index')?>
<div class="tb/Data">

<?php  if ($errormsg !=''):?>
<div><?php echo $errormsg;?></div>
<?php endif;?>
<table>
  <tr>
    <th>メールアドレス</th>
    <td<?php if ($sf_request->haserror('mailaddress')):?> style="background-color:#ffcccc;"<?php endif;?>>
      <?php echo input_tag('mailaddress', $mailaddress, array('size'=> 50));?>
      <?php echo form_error('mailaddress');?>
    </td>
  </tr>
  <tr>
    <th>パスワード</th>
    <td<?php if ($sf_request->haserror('password')):?> style="background-color:#ffcccc;"<?php endif;?>>
    <?php echo input_tag('password', $password, array('size' => 50));?>
    <?php echo form_error('password');?>
    </td>
  </tr>
</table>
</div>
<?php echo submit_tag('ログインする');?>
</form>
・/apps/front/modules/login/actions/actions.class.php
<?php use_helper("Validation")?>

<?php form_tag('login/index')?>
<div class="tb/Data">

<?php  if ($errormsg !=''):?>
<div><?php echo $errormsg;?></div>
<?php endif;?>
<table>
  <tr>
    <th>メールアドレス</th>
    <td<?php if ($sf_request->haserror('mailaddress')):?> style="background-color:#ffcccc;"<?php endif;?>>
      <?php echo input_tag('mailaddress', $mailaddress, array('size'=> 50));?>
      <?php echo form_error('mailaddress');?>
    </td>
  </tr>
  <tr>
    <th>パスワード</th>
    <td<?php if ($sf_request->haserror('password')):?> style="background-color:#ffcccc;"<?php endif;?>>
    <?php echo input_tag('password', $password, array('size' => 50));?>
    <?php echo form_error('password');?>
    </td>
  </tr>
</table>
</div>
<?php echo submit_tag('ログインする');?>
</form>

------------------------------6H------------------------------
★symfony
●管理画面にログインする
・/apps/front/modules/login/actions/action.class.php
    public function executeIndex()
    {
        $this->mailaddress = $this->getRequestParameter('mailaddress');

        $this->password = $this->getRequestParameter('password');

        if($this->mailaddress !='' && $this->password != '')
        {
            //メールアドレスとパスワードを元にmemberテーブルのインスタンス取得
            $c = new Criteria;
            $c->add(MemberPeer::MAILADDRESS, $this->mailaddress);
            $c->add(MemberPeer::PASSWORD, $this->password);
            $member = MemberPeer::doSelectOne($c);
            //$member = MemberPeer::retrieveByPassword($this->mailaddress);

            if($member)
            {
                //ログイン状態にする
                $this->getUser()->setAuthenticated(true);
                $this->getUser()->clearCredentials();
                $this->getUser()->addCredential('member');

                //会員情報をセッションにセット
                $this->getUser()->setAttribute('member_id',$member->getId(),sfConfig::get('sf_session_name'));
                $this->getUser()->setAttribute('nickname', $member->getNickname(), sfConfig::get('sf_session_name'));
                $this->redirect('/backend');
            }
        }
        return sfView::SUCCESS;
        //$this->forward('default', 'module');
    }
・apps/backend/templates/layout.php
ログインしたユーザの名前を表示するようにする
<h1>symfony版SHONANBBS 管理画面</h1>
<?php echo $sf_user->getAttribute('nickname', sfConfig::get('sf_session_name'))?>
さんがログインしています
<hr>
・エラーメッセージを表示
●isset()
apps/login/templates/indexSuccess.php
/apps
<?php  if (isset($errormsg)):?>
<div><?php echo $errormsg;?></div>
<?php endif;?>
-----------------------------memo------------------------------

2012年05月10日 講義061日目

2012年05月10日
講義061日目
------------------------------1H------------------------------
★symfony
●返信の作成
・default/templates/indexSuccess.php
のaタグで。commentテーブルのIDを渡すようにする
<br>
<a href="/reply/index/id/<?php echo $comment->getId()?>">返信する</a>
</div>

reply/actions/action.class.php
でIDを受け取る
------------------------------2H------------------------------
★symfony
●エラーチェック
・作りたいエラーチェックはvalidateフォルダにaction名.ymlファイルに記述する
required:
内容が入ってるかチェック
msg:
内容が無かった場合に表示したいメッセージ
・validate下のエラーチェックの内容を受けて動く処理
エラーチェックした後の処理をacction.class.phpに書く
  public function handleErrorConfirm()
  {
      //confrimアクション宛てに送られたリクエストを受け取って
      //indexアクションで引き継げるようにする
      $this->request->setParameter("id",$this->getRequestParameter("comment_id"));
      $this->request->setParameter("nickname",$this->getRequestParameter("nickname"));
      $this->request->setParameter("content",$this->getRequestParameter("content"));

      $this->forward("reply","index");
  }
------------------------------3H------------------------------
★symfony
●executeConfirm()
  public function executeConfirm()
  {
      $this->content = $this->getRequestParameter("content");
      $this->nickname = $this->getRequestParameter("nickname");
      $this->comment_id = $this->getRequestParameter("comment_id");

      return sfView::SUCCESS;
  }
●ヘルパー機能
・バリデーションのヘルパー機能を使う

<?php use_helper("Validation")?>
・メッセージを表示するform_error()
<?php echo form_error("nickname")?>
・エラーメッセージの矢印を編集
#    validation_error_prefix:    ' &darr;&nbsp;'
#    validation_error_suffix:    ' &nbsp;&darr;'
↓書き換える
    validation_error_prefix:    ''
    validation_error_suffix:    ''
表示されなくなった
------------------------------4H------------------------------
★symfony
●エラーチェック
・多重投稿のエラーチェック
セッションを使う関数$this->setflush();
ユニークなキーをセッションに作成
・confirmSuccess.phpに追加セッション内容をhiddenでresultに渡す
<input type="hidden" name="reply_result_check" value="<?php echo $sf_flash->get("reply_result_check")?>">

executeResult()
    public function executeResult()
    {
        if($this->getflash("reply_result_check") == $this->getRequestParameter("reply_result_check"))
        {
            $content = $this->getRequestParameter("content");
            $nickname = $this->getRequestParameter("nickname");
            $comment_id = $this->getRequestParameter("comment_id");

            //新たなデータでreplyテーブルにレコードを挿入する
            $reply = new Reply;
            $reply->setContent($content);
            $reply->setNickname($nickname);
            $reply->setCommentId($comment_id);
            $reply->save();


            //指定したアクションにリダイレクトする
            //$this->forward("default","index");
        }
        //URLごと遷移
        $this->redirect("/");
    }
    //validate下のエラーチェックの内容を受けて動く処理
------------------------------5H------------------------------
★symfony
●ヘルパー
・linkヘルパー
layout.yml
<div id="header">
さんこんにちは
 | <a href="/logout/">ログアウト</a>
 | <a href="/backend/">管理者用ページへ</a>
</div>

<div id="header">
<?php echo link_to("トップへ","/")?>
 |
<?php echo link_to("管理者用ページへ","/backend/")?>
</div>

リロードするとURLに/index.phpが付いてしまうので、
setting.ymlのdevのno_script_name:をonにする
・form_tag
<form action="/bbssubmit/" method="post" enctype="multipart/form-data">

<?php echo form_tag("/bbssubmit/","method=post multipart=ture")?>
・routhing.ymlの項目名に従わせる
ヘルパーのURL引数に「@~~」と書くとrouting.ymlの項目と連動
<?php echo form_tag("/bbssubmit/","method=post multipart=ture")?>

<?php echo form_tag("@bbssubmit","method=post multipart=ture")?>
・input_tag
<input type="text" name="nickname" size="20"><br>

<?php echo input_tag("nickname","",array("size" => 20)) ?>
第二引数にはデフォルトで入れておきたい文字列などを書いておくなどできる
・urlもinput_tagで書き換えてみる
<input type="text" name="url" size="60"><br>

<?php echo input_tag("url","",array("size" => 60))?><br>
・texterea_tag
<textarea name="content" cols="50" rows="10"></textarea><br>

<?php echo textarea_tag("content","",array("rows"=>10, "cols"=>55))?>
・select_tag
<select name="category_id">
<?php foreach($categorys as $k => $v):?>
<option value="<?php echo $k?>"><?php echo $v?></option>
<?php endforeach;?>
</select>

<?php echo select_tag("category_id", options_for_select($categorys))?><br>
oputions_for_selectで指定した配列を元にセレクトボックスを作る
oputions_for_select()
の第二引数キー値を与えると、その要素が最初に選択される
<?php echo select_tag("category_id", options_for_select($categorys, 2))?><br>
・submit_tag
<input type="submit" value="投稿する">

<?php echo submit_tag("投稿する")?>
●nl2br
/default/templates/indexSuccess.phpの投稿と返信のcontent
/reply/templates/indexSuccess.php
/reply/temptates/confirmSuccess.php
------------------------------6H------------------------------
★symfony
●画像のアップロードのヘルパー
・画像の保存するフォルダを作成
/web/uploads/tmp
/web/images/content
・eclipseでsshターミナルを右クリック
chmod 777 web/uploads/tmp
chmod 777 web/images/content
・input_file_tag
<?php echo input_file_tag("photo")?><br>
・executeSubmit()
ファイルを受け取る
$photo = $this->getRequest()->getFile("photo");
ファイルをDBに反映させる
        if($photo["tmp_name"])
        {
            $filename = $comment->getId().".jpg";
            $this->getRequest()->moveFile("photo",sfConfig::get('sf_web_dir')."/images/comment/".$filename);
            $comment->setPhoto($filename);
            $comment->save();

        }

        return sfView::SUCCESS;
    }
-----------------------------memo------------------------------