Archive for the ‘Symfony’ Category

symfony : はじめてのsfForm

この記事はSymfonyアドベントカレンダー2010の22日目です

はじめに…の前に

symfonyに関わるようになってから半年くらいたちます。
思いっきり、仕事で関わってます。
実際使い始めて、「書きやすい」「扱いやすい」「自分に合ってる」というかんじでしたね。
自社開発ではほとんどがsymfony(1.4)での開発となっております。

他のみなさんの記事は、Symfony2だったり高度な記事が多くてちょっとびびってますが、敢えて初心に戻って(私が割と混乱してた)symfony1.4のフォームについて書いてみたいと思います。

はじめに

symfony 1.4になってから、フォームまわりがsfFormクラスからの生成のみとなり、input_tagとかいったものが使えなくなりました。
DRY的考え方だと「フォームもDon’t Repeat Yourself」で理にかなってるのですが、おそらくなじめない方も少なからずいるんじゃないかなと思います。
私のサイトのアクセスログを見ていると、「symfony 1.4 input_tag」での検索がぼちぼち来ていますので、この変更に混乱してるかたも少なからずいらっしゃるんだろうな、と思いまして、input_tagが使えない1.4以降のフォーム周りの基本的な話をしてみようかと思います。

考え方

フォームも1つのクラスとして考えます。
クラスとして定義することにより、使い回すことを想定しています。
module、template、form classの関係は下記の図のようになります。
2010122201

実際の扱い

(sfFormクラスの派生の)BaseFormをベースとしたformのクラスを生成します。
ファイルの場所は基本、 lib/form/ 以下となります。
このクラスで、フォームの部品やvalidationの定義します。
これらの定義は、configure()メソッドで行います。

簡単な例:まずは1つのテキストボックスで

1つのテキストボックスを持つフォームのクラスを定義する場合、下記のようになります。
ファイル名 SimpleForm.class.php です。

class SimpleForm extends BaseForm
{
  function configure()
  {
    $this->setWidgets(array(
        'intext' => new sfWidgetFormInputText() ,
    ));
  }
}

setWidgetsで、引数にフォームのウィジェットを定義した配列を与えてあげます。

これを実際のフォームとして表示するには、
・moduleのaction class内でこのformのインスタンスを作る
・templateで表示処理を書く

module(action.class.php)ではこうします。

function executeIndex(sfWebRequest $request)
{
  $this->form = new SimpleForm() ;
}

これに対応した、template(IndexSuccess.php)での表示処理はこうなります。

<form action="do.php" method="POST">
<table border="1">
<?php echo $form ; ?>
<tr><td colspan="2"><input type="submit" value="ぽちっとな"></td></tr>
</table>
</form>

$form だけの場合、レイアウトはデフォルトのままになります。
表示結果はこうなります。
2010122203

自身でレイアウトしたい場合、inputタグ該当部分は以下のように render() を使います。

<?php echo $form['intext']->render() ; ?>

スタイルを設定したい場合などは、render()の引数に配列で与えます。

<?php echo $form['intext']->render(array('style'=>'width:300px;')) ; ?>

フォーム系タグとウィジェットの対応

使いたいタグと、指定するウィジェットは下記のようになります。

input-text

<input type="text" ...>

$w = new sfWidgetFormInputText();

input-password

<input type="password" ...>

$w = new sfWidgetFormInputPassword();

input-hidden

<input type="hidden" ...>

$w = new sfWidgetFormInputHidden();

textarea

<textarea>
</textarea>

$w = new sfWidgetFormTextarea();

select(プルダウン)

<select>
 <option value="1">select 1</option>
 <option value="2">select 2</option>
 ...
</select>

static $choicelist = array('1'=>'select 1','2'=>'select 2',...);
$w = new sfWidgetFormSelect(array('choices'=>$choicelist));

radio(ラジオボタンセレクト)

<input type="radio" value="1">choice 1
<input type="radio" value="2">choice 2
...

static $choicelist = array('1'=>'select 1','2'=>'select 2',...);
$w = new sfWidgetFormChoice(array('choices'=>$choicelist));

主に使うのはこのへんでしょうか。

バリデーターを使ってみる

Formクラスのconfigure()メソッド内で、setValidatorでセットします。

class SimpleForm extends BaseForm
{
  function configure()
  {
    $this->setWidgets(array(
        'intext' => new sfWidgetFormInputText() ,
    ));
    $this->widgetSchema->setNameFormat('data[%s]');
    $this->setValidators(array(
                                'intext'=>new sfValidatorString(),
                         )) ;
  }
}

setValidatorの引数に連想配列でvalidatorクラスをセットします。

2つめのsetNameFormatは、名前のフォーマットを指定します。
この場合、「 data[intext] 」のような形になります。
バリデーション処理でバインドするとき(後述)にここの名前を使います。

話を元に戻して。
sfValidator〜 (validatorスキーマ)では、引数でvalidationの設定を行います。
以下の場合は、intextが必須でなくなります。

'intext'=>new sfValidatiorString(array('required'=>false)),

以下のようにすると、intextが必須になり、抜けていた場合は「intextは必須です。」のメッセージを返すようになります。

'intext'=>new sfValidatiorString(array('required'=>true),
                                 array('required'=>'intextは必須です。')),

validationにはねられた場合のエラー表示は、template内で下記のようにします。

<?php echo $form['intext']->renderError(); ?>

validatorのスキーマは文字列や数値、日付以外にも、Eメールなどいろんな種類があります。
多いのでここでは説明を割愛します。詳しくは下記にまとまってます、
symfony Forms in Action | 付録 B – バリデーター | symfony | Web PHP Framework

実際にバリデーションを行う、action.class.phpでは、以下のようにします。

    $form = new SimpleForm();
    $form->bind($request->getParameter('data'));

    $v = $form->isValid() ;
    if ( $v ) {
      // validation 成功
      $intext = $form->getValue('intext') ;
    }
    else
    {
      // validation 失敗の処理
    }

流れとしてはこうです。
1.フォームのクラスを作る
2.バインドする (form class内でsetNameFormatした名前を当てる)
3.バリデーションする

また、バリデーションを設定すると、デフォルトでCSRFチェックを行います。
自分でフォームをレンダリングする場合、template内で以下のようにCSRF対策用トークンを追加してあげてください(hiddenで渡されます)。

<?php echo $form['_csrf_token']->render(); ?>

どうしてもvalidationに失敗してしまう場合、多分これが抜けてる可能性があります。

最後に

フォームに関しては公式のsymfony Forms in Action | symfony | Web PHP Frameworkにいいまとめがあるのですが、少し読みづらいかんじがしました。
「とりあえず動くもの」を示してみて、そこから入っていけるためのとっかかりになってくれればなあ、と思いまして、記事を書いてみました。

参考

Symfony Advent 2010について

Symfony Advent 2010では12月1日から12月24日までを使って日替わりでsymfonyでイイなと思った小さなtipsから内部構造まで迫った解説などをブログ記事にして公開していくイベントです。

CentOS 5.5でPHP5.2.x

yumで入れるとPHP 5.1.xになっちゃうので、symfony 1.4を動かせなかったり、いろいろ不都合が多くて、ね。

ちなみに。
さくらのVPSさくらインターネットさんの専用サーバ エントリーのOSのバージョンがまさにこれなんで、思いっきりぶちあたりました。
多分今後参照する人が増えると思うので、メモがてら。

対策としては2つあります。

(1)根性で野良ビルド

私はこれでやりました。ちなみに5.2.14。
慣れないと難しいけど最強な方法。
逆を言うと「–with-apxs2ってなにそれ?」って人は絶対にやっちゃだめ。

参考までに私のとこでの configure 設定例を載せておきます。
php -i した結果です。

コンパイル環境や開発用のライブラリをyumコマンドで前もっていれておく必要があります。

manaka(専用サーバのほう)

Configure Command => ‘./configure’ ‘–prefix=/usr’ ‘–with-apxs2’ ‘–with-mysql’ ‘–with-pdo-mysql’ ‘–enable-calendar’ ‘–with-curl’ ‘–enable-mbstring’ ‘–with-mcrypt’ ‘–with-ncurses’ ‘–with-gd’ ‘–with-t1lib’ ‘–with-zlib’ ‘–with-png-dir=/usr/lib’ ‘–with-jpeg-dir=/usr/lib’

nene(VPSのほう)

Configure Command => ‘./configure’ ‘–prefix=/usr’ ‘–with-libdir=lib64’ ‘–with-apxs2’ ‘–with-mysql’ ‘–with-pdo-mysql’ ‘–enable-calendar’ ‘–with-curl’ ‘–enable-mbstring’ ‘–with-mcrypt’ ‘–with-ncurses’ ‘–with-gd’ ‘–with-zlib’ ‘–with-png-dir=/usr/lib’ ‘–with-jpeg-dir=/usr/lib’

VPSのほうは64bitなんで、’–with-libdir=lib64’が要ります。これ注意ね。

(2)パッケージを利用する

野良ビルドがわからない人向け。(できればこのほうをおすすめしたい)
yumでリポジトリを明示的に指定してする方法です。
「centOS 5.5 PHP 5.2」で検索するとこちらの方が圧倒的に多いですね。

doctrineでちょい複雑なクエリをつくってみる

3つくらいのテーブルを結合した結果を出力したいとき。
たとえば、こーんなSQLの結果が欲しいとき。

SELECT 
p.id , p.pcs , p.price , u.text , y.name
FROM
Price as p , Update as u , User as y
WHERE
p.shop_id = $shopid
and p.item_id = $itemid
and p.id = u.id
and u.user_id = y.id
ORDER BY p.create_time desc
LIMIT 10

こんなかんじにかきます。

    $q_plistshop =
      Doctrine::getTable('Price')
      ->createQuery('p')
      ->addFrom('Update as u')
      ->addFrom('User as y')
      ->select('p.id,p.pcs,p.price,u.text,y.name')
      ->where('p.shop_id =  ' . $shopid )
      ->andWhere('p.item_id = ' . $itemid )
      ->andWhere('p.id = u.id')
      ->andWhere('u.user_id = y.id')
      ->addOrderBy('p.create_time desc')
      ->limit(10) ;
    $this->plistshop = $q_plistshop->execute(array(),Doctrine::HYDRATE_NONE);

一見、 $q_plistshop->fetchArray() でいけそうだけど(うまくハイドレーションできんぞ?とかで)怒られる。
いろいろ調べた結果、「Doctrine::HYDRATE_NONE」するとうまくいくっぽい。
この場合、$this->plistshop[数字]じゃないととれないので注意。
あと、勝手に列の順番を並べ替えられたりする(アルファベット順?)のでそのへんも注意。

……まてよ?

p.id as id1 , p.pcs as pcs , ... 

というふうに明示的に名前指定すればハイドレーション関係で怒られずにすむかもしれない。
Doctrineがこのへんで混乱してたようなメッセージ出してた気がするので。

ぶっちゃけ、よくわからん。
このへん、も少し勉強する必要ありそうですね。

参考

symfonyでメールを送る(かなり強引編)

プラグインとか使おうとして挫折したので力業編。
お世辞にも美しくないですがこれで動いてるので。
正直言って「よい子は真似しちゃだめだよ」レベルです :D

なお、mailsendSuccess.php は HTML ではなくplain textで書きます。
単にrequire してるので、$this->foo = $bar ; とかしないで $foo = $bar でいい。
それと、そもそもmailsendSuccess.php って名前は不適切かもしれない。

function Mailsend()
{
    ob_start();
    require '../apps/アプリ名/modules/モジュール名/templates/mailsendSuccess.php';
    $body = ob_get_contents() ;
    ob_end_clean();
    ob_start();         // symfony側にout bufferを渡す

    // $body = "テスト" ;
    $mailto = $this->rgdb->getEmail() ;
    $header  = "From: =?ISO-2022-JP?B?" . base64_encode(mb_convert_encoding("テストさん","iso-2022-jp","utf-8")) . "?= <info@example.com>\n" ;
    $header .= "Mime-Version: 1.0\n" ;
    $header .= "Content-Type: text/plain; charset=iso-2022-jp\n" ;
    $header .= "Content-Transfer-Encoding: 7bit\n" ;
    $subject = "=?ISO-2022-JP?B?" . base64_encode(mb_convert_encoding("お知らせ","iso-2022-jp","utf-8")) . "?=" ;

    mail($mailto,$subject,mb_convert_encoding($body,"iso-2022-jp","utf-8"),$header,'-f info@example.com') ;
}

symfony 1.4 ではまったことメモ

多分何人か同じ過ちを犯すと思われるので(笑)
なかにはsymfony関係ねー、ってのもありますがそこはご愛敬ってことで勘弁を。

(1)とりあえず…symfonyの最初の画面が拝めないです。なんというか、/path/to/symfony/web がない。

$ ./symfony generate:project myproject
$ ./symfony generate:app frontend
$ ./symfony generate:module frontend default

最悪、これで frontend の default で、web フォルダにアクセスすれば、 symfonyの画面が見えるはず。

(2)途中に web とか入るのがださいです
→ Apacheの DocumentRoot を、 /path/to/symfony/web/ とすればいいです。

(3)input_tag を使おうとすると undefined function になる
→これはエラーメッセージではなく、正しくは以下の内容です。
「えーマジinput_tag!?キモーイ」
「FormHelperが許されるのは1.3までだよねキャハハハハh」
元ネタ
…そんなわけで、1.4からFormHelperがdeprecatedになっちゃったので、sfFormだけです。頑張りましょう。
symfony Forms in Action | symfony | Web PHP Framework あたりの説明が役に立つと思います。

(4)devではちゃんと動いてたのにprodにした途端、画面が真っ白になったり、動かなくなったりする。
→とりあえず、 symfony cc してみましょう。
参考:dev環境からprod環境に変えると動かなくなる時の対処方法 « symfonyで開発日記

(5)/backend/ としたいのに /backend.php/ でしか動かせない
→ ApacheのMultiviewの設定。 .htaccess に Options MultiView を追加するなどすればOKです。

あとで追加予定。

symfonyの初歩の初歩(参考サイトまとめ)

もはや、個人的メモ。
OpenPNE3に繋げるためにも避けられないしー。

気づいたら&気が向いたら、少しづつ増やすかも。

○ポータル系
symfonyの日本語情報サイト

○今日のtwitterから。symfonyのガイドとか。

●2010-05-08 18:18:32 by YoruFukurou
メモ > The Definitive Guide to symfonyの翻訳: http://symfony.xrea.jp/ ←ちょっと離れてたら忘れてたw さっきからこれ探してた。
RT @hidenorigoto: http://symfony.sarabande.jp/ こちらもどうぞ RT @sayama_yuki: メモ > The Definitive Guide to symfonyの翻訳: http://symfony.xrea.jp/

○Doctorine
「Propel使って良いのは小g(ry …」とかいう雰囲気ぽいのと(←ぇ?)、いま一つ理解しきれてないので。

OpenPNE3プラグイン開発勉強会、の復習

手嶋屋さん主催のOpenPNE3プラグイン開発勉強会に行ってきました。
勉強会というよりは自習会+サポートというかんじでの進め方でした。
OpenPNE3.4プラグイン開発チュートリアルを教材に、ひたすらコードを書く!(笑)というかんじでした。

ちなみに私ですが、今日はパート8まで進めました。

進めていく上で、Symfonyをちゃんと理解してない部分も多々あったので、進めながら参照したところを(復習がてら)貼っておきます。

実は今回、本気でSymfonyを触ったわけだったりします。
仕事でCakePHPを使ってましたが、流儀の違いさえ飲み込めれば(それが一番難しいんでしょうがw)理解ははやいかなと思います。

※追記
OpenPNEプラグインの作り方は下記も参照
OpenPNE3プラグインの作り方#6|OpenPNE(バックナンバーもここから)

※追記2
今日の参加者それぞれの進捗状況が公開されました。
OpenPNE3プラグイン開発勉強会終了|SNS構築の手嶋屋

debianにSymfonyいれてみる

メモ。
PEARで入れるほうが楽そーなので、そちらの方法で。

1.PEARを入れる

$ aptitude install php-pear
$ which pear
$ pear upgrade PEAR

2番目のwhichはインストールされたか確認するため。

2.PEARからSymfonyを入れる

$ pear channel-discover pear.symfony-project.com
$ pear install symfony/symfony-1.4.2
$ which symfony

参考:The symfony framework Installation | symfony | Web PHP Framework
ちなみにおすすめできない方法のようです。
望ましいやりかたは、このへんから。
Getting Started with symfony | symfony | Web PHP Framework

とりあえずインストールだけなら以上あたりから。
この続きは、またあとで。