忍者ブログ
[PR]
×

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



2024/04/26 14:00 |
Symfony1.2 10日目その2
現在の投稿画面は必要な入力欄が並んでいるだけの殺伐とした構成になっています。
装飾を行いましょう。


まず、デフォルトではスキーマのカラム名がそのまま入力項目名として表示され、「Category id」や「Is public」等になっています。
ヴィジェットのsetLabels()メソッドで入力項目名を変更することができます。
JobeetJobForm.class.phpに追加。

lib/form/doctrine/JobeetJobForm.class.php
1
2
3
4
5
6
<?php
$this->widgetSchema->setLabels(array(
  'category_id'    => 'Category',
  'is_public'      => 'Public?',
  'how_to_apply'   => 'How to apply?',
));

>それぞれのフィールドに対して、symfonyは~ラベル|フォームラベル~(<label>タグに使われる)を自動的に生成します。
>ラベルはlabelオプションで変更できます。

チュートリアルだとこんなふうにわかりにくい表記がされているせいで、<label for="**">を変更するのか?とも読めてしまうのですが、単に左側の文言を変更するだけです。
これまで'Category id'と表示されていてIDなのに<select>?とか思わされていたわけですが、これで左辺の分類が'Category'となってわかりやすくなりました。

次に入力欄に説明を付加します。
setHelp()メソッドが用意されています。

lib/form/doctrine/JobeetJobForm.class.php
1
2
3
<?php
  $this->widgetSchema->setHelp('is_public', 
'Whether the job can also be published on affiliate websites or not.');

これまで'Public?'とだけ表示されていた謎のチェックボックスに、ヘルプメッセージが表示されるようになります。


setLabels()とsetHelp()ってなんか不平等だな、setLabel()やsetHelps()は無いのか、といえばどちらも有ります。
1
2
3
4
5
6
7
<?php
$this->widgetSchema->setHelps(array(
  'category_id'    => 'カテゴリを選択',
  'is_public'      => '公開するのであればチェック',
  'how_to_apply'   => '申込方法を記入',
));
$this->widgetSchema->setLabel('is_public', '公開フラグ');
といった書き方も可能です。


フォームのテンプレートを修正します。
ここら辺は3日目に作ったままで中がどうなってるかとか全然覚えてねえよ。


apps/frontend/modules/job/templates/newSuccess.php
1
2
3
<?php use_stylesheet('job.css') ?>
<h1>Post a Job</h1>
<?php include_partial('form', array('form' => $form)) ?>

下2行は元々入っているはずなので、CSSを付け足します。
リロードするとスタイルシート読み込みの行が増えているのがわかります。


フォームテンプレートはinclude_partial()されている中の_form.phpに書かれています。
このフォームテンプレート部分だけ分けることにより、新規登録画面とエディット画面でフォームを共用できるようになっているのですが後述。
現在のテンプレートは自動生成と5日目による修正を受けてこんなふうになっています。

apps/frontend/modules/job/templates/_form.php
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
32
33
<?php include_stylesheets_for_form($form) ?>
<?php include_javascripts_for_form($form) ?>
<form action="<?php 
  echo url_for('job/'.($form->getObject()->isNew() ? 'create' : 'update')
    .(!$form->getObject()->isNew() ? '?id='.$form->getObject()->getId() : ''))
  ?>" method="post" 
  <?php $form->isMultipart() and print 'enctype="multipart/form-data" ' ?>
>
 
<?php if (!$form->getObject()->isNew()): ?>
<input type="hidden" name="sf_method" value="put" />
<?php endif; ?>
 
  <table>
    <tfoot>
      <tr>
        <td colspan="2">
          &nbsp;<a href="<?php echo url_for('job/index') ?>">Cancel</a>
          <?php if (!$form->getObject()->isNew()): ?>
            <?php echo link_to('Delete', 
              'job/delete?id='.$form->getObject()->getId()
              ,array('method' => 'delete', 'confirm' => 'Are you sure?'))
            ?>
          <?php endif; ?>
          <input type="submit" value="Save" />
        </td>
      </tr>
    </tfoot>
    <tbody>
      <?php echo $form ?>
    </tbody>
  </table>
</form>

チュートリアルのフォームテンプレートでさくっと上書きします。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php include_stylesheets_for_form($form) ?>
<?php include_javascripts_for_form($form) ?>
 
<?php echo form_tag_for($form, '@job') ?>
  <table id="job_form">
    <tfoot>
      <tr>
        <td colspan="2">
          <input type="submit" value="Preview your job" />
        </td>
      </tr>
    </tfoot>
    <tbody>
      <?php echo $form ?>
    </tbody>
  </table>
</form>

ずいぶんわかりやすくなりました。
まあ面倒な削除ボタンなどを削除したせいではありますが。
あと、Previewとか書いてあるのにボタンを押したら何故か即座に登録されます。

form_tag_for()は自動的にフォームタグを作成してくれる便利な関数です。
@jobなのでルーティングのjob:に対応付けけられますが、何故'job/new'や'job/edit'ではなく'job/create'や'job/update'に正しくルーティングされるのかはよくわかりません。

あとひとつ問題があって、対となる閉じタグを作成する関数がありません。
勿論機能的には明らかに不要ですが、IDE使うと<form>タグが足りないってエラーが出っぱなしになって気持ち悪いんだよね。

include_stylesheets_for_form()include_javascripts_for_form()は現時点では何の役に立っているのかさっぱりわかりません。
削除しても出力が全く変化しないし、ググってもチュートリアルとdiffのコピペしか見つからず、使用法が全く見あたらねえ。

echo $formとするとフォームの中身を全部纏めて勝手に<th><td>タグ付きで出力されますが、テーブルとか使いたくない、<ul><li>でやりたいんだ、みたいな場合に備えて中身を個別に出力する方法もあります。
囲み記事にも書いてありますが、
1
2
<?php
    print($form['company']->renderLabel());

といった書き方ができます。
まあ今回は不要なのでとりあえずパス。


Symfonyにおけるフォームの流れは以下のようになっています。

・新規登録
 new→(create→processForm→)edit
・更新
 edit→(update→processForm→)edit

processFormはcreateやupdateの内部で呼ばれて投稿された値を保存しているだけなので、表には出てきません。
権限もprotectedになっています。
またprocessFormは保存に成功したらeditにリダイレクトするようになっているので、createやupdateは見えないようになっています。

アクションには3日目の最後あたりで作成したexecuteEdit()やらexecuteUpdate()が存在していますが、記事を取得するために
Doctrine::getTable('JobeetJob')->find($request->getParameter('id')
的なことを行っています。

5日目にルーティングを設定したので、
$this->getRoute()->getObject();
で記事を取得できるようになりました。
よくわかりませんが。

わざわざ引数からテーブルを探してこなくても、ルーティングから内容を取得できるようになったのでそちらを使用するようにします。
jobActions::executeNew()jobActions::processForm()以外は中身が少しづつ違うので、チュートリアルに従って修正。

apps/frontend/modules/job/actions/actions.class.php
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
<?php
    /*
     * フォーム新規作成
     */
    public function executeNew(sfWebRequest $request){
      $this->form = new JobeetJobForm();
    }
    /*
     * フォームの作成画面からセーブ
     */
    public function executeCreate(sfWebRequest $request){
      $this->form = new JobeetJobForm();
      $this->processForm($request, $this->form);
      //失敗したら新規作成画面に戻る
      $this->setTemplate('new');
    }
    /*
     * フォームのエディット
     */
    public function executeEdit(sfWebRequest $request){
      $this->form = new JobeetJobForm($this->getRoute()->getObject());
    }
    /*
     * フォームのエディット画面からセーブ
     */
    public function executeUpdate(sfWebRequest $request){
      $this->form = new JobeetJobForm($this->getRoute()->getObject());
      $this->processForm($request, $this->form);
      //失敗したらエディット画面に戻る
      $this->setTemplate('edit');
    }
    /*
     * 削除
     */
    public function executeDelete(sfWebRequest $request){
      $request->checkCSRFProtection();
      $job = $this->getRoute()->getObject();
      $job->delete();
      $this->redirect('job/index');
    }
    /*
     * フォーム、投稿された値を保存する
     */
    protected function processForm(sfWebRequest $request, sfForm $form){
        //値をバインド
        $form->bind(
            $request->getParameter($form->getName())
            ,$request->getFiles($form->getName())
        );
        //バインドに成功したら
        if ($form->isValid()){
          //セーブしてエディット画面に移動
          $job = $form->save();
          $this->redirect($this->generateUrl('job_show', $job));
    
        }
    }

jobActions::processForm()は、まず投稿された値をJobeetJobFormクラスにバインドし、その後$form->isValidでバリデータを実行しています。
バリデートに成功したらそのままセーブし、jobActions::executeEdit()にリダイレクトします。
バリデートに失敗したらそのまま呼び出し元のメソッドに戻り、登録画面やエディット画面に戻ります。

ルーティングから取得した内容をフォームオブジェクトに渡せば、エディット画面のデフォルト値にそのまま表示されます。
入力後にバリデーションで失敗した場合には、入力値がそのまま引き継がれて表示されます。
さらにこの間、エスケープ処理などは全て自動で行ってくれるのでこちら側では一切考慮する必要がありません。
非常に便利ですね。

どのオブジェクトをどのメソッドにどうやって結びつければいいか、がわかればの話ですが。
さっぱりわかりません。
PR


2010/10/25 22:27 | Comments(0) | TrackBack() | PHP

トラックバック

トラックバックURL:

コメント

コメントを投稿する






Vodafone絵文字 i-mode絵文字 Ezweb絵文字 (絵文字)



<<PHP技術者認定初級試験ベータ試験 合格発表 | HOME | 買ったものリスト 2010/10/24>>
忍者ブログ[PR]