Caution: You are browsing the legacy symfony 1.x part of this website.

symfony 1.2では何が新しくなったの?

1.2
Symfony version
1.4
Language

このチュートリアルでsymfony 1.2のための簡単に技術的な内容について紹介します。 すでにsymfony 1.0や1.1で作業をしたことがあり、symfony 1.2の新しい機能について学びたい開発者のためのチュートリアルです。

最初に、symfony 1.1がPHP 5.1、symfony 1.0がPHP 5.0で動作していたのに対してsymfony 1.2はPHP 5.2.4かそれ以降に対応していることに注意してください。

もし、symfony 1.0か1.1からアップグレードしたいのであれば、symfonyをインストールしたディレクトリにあるUPGRADEファイル(/installation/1_2/upgrade)ファイルを読んでください。 ここにsymfony 1.2にプロジェクトを安全にアップグレードするために必要とされる情報のすべてがあります。

Propel

Propelはバージョン1.3にアップグレードされました。 このバージョンではCreoleに代わりPDOがサポートされいたり、多くの新しい機能が含まれています。 新しい機能とはオブジェクトインスタンスプーリング、マスタースレーブコネクション、入れ子集合のサポート、そしてよりよい日付関連のハンドリングなどです。

databases.yml設定ファイルはPDO構文を使うようになりました。

dev:
  propel:
    param:
      classname: DebugPDO
 
all:
  propel:
    class: sfPropelDatabase
    param:
      dsn:        mysql:dbname=example;host=localhost
      username:   username
      password:   password
      encoding:   utf8
      persistent: true
      pooling:    true
      classname:  PropelPDO

トランザクションAPIはわずかに変更がありました。 それは->begin->beginTransaction()に、そして->rollback()->rollBack()に変更されたことです。 ::doSelectRSメソッドは::doSelectStmtに変更されました。

さらなるアップグレードの詳細についてはPropelの公式サイトにあるcomplete documentationを読んでください

Doctrine

Doctrineはsymfony 1.2の第1級市民です。 symfony 1.2では Propelプラグインと Doctrineプラグインの両方をバンドルしているということです。 全ての組み込まれた機能はPropelとDoctrineの両方で利用できます。 よりふさわしいORマッパーを自由に選んでください。

リクエスト

ブラウザからのPUTDELETEリクエストをPOSTメソッドと特別なsf_methodパラメーターを追加することでシミュレーションが可能になりました。

<form action="#" method="POST">
  <input type="hidden" name="sf_method" value="PUT" />
 
  <!-- // ... -->
</form>

form_tag()ヘルパーは GETPOSTと異なるメソッドのために自動的にhiddenタグを生成します。 そのため、formの開始タグは次のようにform_tag()ヘルパーを使うことで生成できます。

<?php echo form_tag('#', array('method' => 'PUT')) ?>

link_to()ヘルパーはCSRFへの保護機能が有効になっている場合、CSRFトークンを埋め込むようになりました。 checkCSRFProtection()メソッドを使うことでリンクがクリックされたときにトークンをチェックすることができます。

public function executeDelete($request)
{
  $request->checkCSRFProtection();
}

トークンが存在しなかったり有効でない場合は、checkCSRFProtection()は例外を投げます。

フォーム

フォームの入れ子

symfony1.1ではPropelでのフォームの主な制限の1つとして組み込まれたフォームからオブジェクトを自動保存することができないことでした。 symfony1.2では実装されるようになりました。 これはPropelのフォームを保存するとき、symfonyによって自動的に主となるオブジェクトと関連する入れ子になったフォームの全てをオブジェクトを保存してくれるということです。

新しいsfFormメソッド

新しいsfForm::renderFormTag()メソッドはform開始タグを現在のフォームのために生成します。 また、フォームがマルチパートを必要とする場合はenctype属性も追加しますし、メソッドがGETまたはPOST以外の場合はhiddenタグを追加します。

<?php echo $form->renderFormTag('@article_update', array('method' => 'PUT')) ?>

sfFormPropelクラスは関連するオブジェクトに基づくHTTPメソッドを自動的に変更するためにrenderFormTag()を再定義します。 つまり、オブジェクトが新しければ、メソッドはPOSTでありオブジェクトがすでに存在すればメソッドはPUTになるでしょう。

sfForm::hasErrors()メソッドはフォームにエラーがあるはtrueを返し、そうでない場合はfalseを返します。 このメソッドはフォームに値が結びつけられていない場合はfalseを返します。 このメソッドはテンプレートでとても役に立ちます。

<?php if ($form->hasErrors()): ?>
  The form has some errors you need to fix.
<?php endif; ?>

sfForm::renderUsing()メソッドのおかげで、特定のウィジットスキーマのフォーマッターを使ってレンダリング処理が行えるようになりました。 これによってテンプレートにおいて直接フォーマッターを使うことができるようになります。

// in a template, the form will be rendered using the "list" form formatter
echo $form->renderUsing('list');

sfForm::renderHiddenFields()メソッドはhiddenウィジットのためのHTMLを返します。 フォームのフィールドをテンプレート内で見えないようにしたいときに役に立ちます。

<form action="<?php echo url_for('@some_route') ?>">
  <?php echo $form->renderHiddenFields() ?>
  <ul>
    <?php echo $form['name']->renderRow() ?>
  </ul>
  <input type="submit" />
</form>

sfForm::getStylesheets()sfForm::getJavaScripts()メソッドはフォームのレンダリング処理に必要なスタイルシートとJavaScriptファイルを返します。 フォームの中が、またはより一般的に各ウィジット(詳しくはウィジェットの項目を確認してください)の中で上記メソッドを上書きこれらのファイルを定義することができます

テンプレート中ではinclude_javascripts_for_form()include_stylesheets_for_form()ヘルパーを利用できます。 これら両方とも引数としてフォームオブジェクトを渡します。

<?php include_javascripts_for_form($form) ?>
<?php include_stylesheets_for_form($form) ?>

sfFormはより簡単にテンプレート内でフォームのフィールドを繰り返しやすくできるようにIteratorCountableインターフェースを実装しています。

<ul>
  <?php foreach ($form as $field): ?>
    <li><?php echo $field ?></li>
  <?php endforeach; ?>
</ul>

前処理で値をクリーンアップする

オブジェクトを更新して、Propelによって値が利用される前に値をクリーニングできる前処理の方法が追加されました。

もし値のための前処理を行いたいのであれば、updateXXXColumn()メソッドをXXXがPropelカラムのPHP名である部分のフォームに追加する必要があります。

このメソッドは 処理された値かクリーンアップされた値の配列から値をとりのぞくためにfalseを返さなければなりません。

class UserForm extends sfFormPropel
{
  // ...
 
  protected function updateProfilePhotoColumn($value)
  {
    // ユーザーがprofile_photoを投稿しなかった場合、
    // 古い値を維持したいので複数の値から
    // その値を削除する
    if (!$value)
    {
      return false;
    }
 
    // 古い写真を削除する
    // 写真をディスクに保存する
 
    // 値を新しいファイルの名前に変更する
    return $filename;
  }
}

バリデーター

sfValidatorSchemaCompare

sfValidatorSchemaCompare定数は変更されました。 コードに変更は必要ありません。 しかしこれからは、すばらしいショートカットを使うことができます。 次の2つの例が実装例です。

// symfony 1.1 と 1.2での記述方法
$v = new sfValidatorSchemaCompare('left', sfValidatorSchemaCompare::EQUAL, 'right');
 
// symfony 1.2での記述方法
$v = new sfValidatorSchemaCompare('left', '==', 'right');

sfValidatorChoice

sfValidatorChoicesfValidatorChoiceManyにある multiple オプションと同じふるまいをするためにmultipleオプションを持つようになりました。

sfValidatorPropelChoicesfValidatorPropelChoiceManyにあるmultipleオプションと同じふるまいをするためにmultipleオプションを持つようになりました。

sfValidatorDateRange

symfony 1.2は日付の期間をバリデートするための新しいsfValidatorDateRangeバリデーターを備えています。

sfValidatorFile

sfValidatedFileクラスはファイルを保存するときにもう少し柔軟に対応できるようになりました。

このコンストラクターは新しい引数をとることができ、ファイルを保存するときに利用するパスを渡すことができます。

それで、ファイルを保存するとき、次のようにすることができます。

  • これまでのように絶対パスでファイル名を渡す

    $file->save(sfConfig::get('sf_uploads_dir').'/filename.pdf');
  • 相対パスを渡す(symfonyはパスを先頭に加えることで絶対パスを作成します)

    $file->save('filename.pdf');
  • nullを渡す。この場合ファイル名はgeneratedFilename()メソッドによって自動的に生成されます。

    $file->save();

さらに、 save() メソッドは(引数のパスに相対的な)保存されたファイルのファイル名を返すようになりました。

sfValidatedFileオブジェクトはsfValidatorFileバリデーターによって生成されるので、新しいpathオプションは後者のクラスに追加されsfValidatedFileコンストラクターにただ渡されるだけです。

$this->validatorSchema['file'] = new sfValidatorFile(array('path' => sfConfig::get('sf_uploads_dir')));

sfFormPropelはこれらの新しい改良部分をPropelオブジェクトに関連するファイルの保存を自動化することで活用することができます。 それが新しいsaveUploadedFile()メソッドです。

そのため、もしfileカラムを持つPropelオブジェクトがあり、フォームクラスでfileバリデーターを定義するときパスを渡しているならsymfonyはあなたの代わりに全ての処理を行ってくれます。

  • もしフォームにファイルがアップロードされていないのなら

    • 何もせずにデータベースにも変更を加えません
  • もしファイルがアップロードされたなら

    • 古いファイルを削除
    • 新しいファイルを保存
    • fileカラムにファイル名をセット(与えられたパスへの相対)

それで、関連するアクションにおいて、ただ$this->form->save()とするだけで自動的にオブジェクトを保存しファイルを保存します。

標準では、symfonyはハッシュと推測した拡張子を追加してユニークなファイル名を生成します。 もしファイル名を変更したいならgenerateXXXFilename()メソッドをオブジェクト内に作成するだけです。 XXXの部分はカラムのPHP名が入ります。 このメソッドはsfValidatedFileオブジェクトに与えられています。

public function generateFileFilename(sfValidatedFile $file)
{
  return $this->getId().$file->getExtension($file->getOriginalExtension());
}

もちろん さきほど説明したようにupdateXXXColumn()をこのふるまいをオーバーライドするために作成し、 あなた自身でファイルのアップロードの処理をマージすることも可能です。

sfValidatorI18nChoiceCountrysfValidatorI18nChoiceLanguage

symfony 1.1ではsfValidatorI18nChoiceCountrysfValidatorI18nChoiceLanguageバリデーターはcultureオプションが必須でした。 このcultureはこれらのバリデーターで使われていないので、cultureオプションは廃止予定です。 後方互換性のためにまだ残っていますが、もう使う必要はありません。

メッセージに関連するrequiredinvalidの標準エラーコードの設定

2つの新しいメソッドがsfValidatorBaseクラスに追加され、標準時のrequiredinvalideエラーコードのためのメッセージを定義できるようになりました。

sfValidatorBase::setRequiredMessage('This field is required');
sfValidatorBase::setInvalidMessage('The value provided for this field is invalid');

ウィジェット(Widgets)

ウィジェットオプション

全てのウィジェットは新しいdefaultオプションを持ちます。 このオプションはウィジェットの標準の値をセットします。

$widget = new sfWidgetFormInput(array('default' => 'default value'));
$widget->setDefault('default value');
echo $widget->getDefault();

ウィジェットのスキーマに標準の値をセットすることもできるようになりました。

$widget = new sfWidgetFormSchema(...);
$widget->setDefaults(array('name' => 'default value'));
$widget->setDefault('name', 'default value');
var_export($widget->getDefaults());

フォームの標準の値で上書きしないときこれらの標準に設定した値はそのことを考慮します

すべてのウィジェットは新しいlabelオプションを持ちます。 このオプションは各ウィジェットにラベルを設定します。

$widget = new sfWidgetFormInput(array('label' => 'Enter your name here'));
$widget->setLabel('Enter your name here');
echo $widget->getLabel();

ウィジェットのJavaScriptとスタイルシート

ウィジェットではgetJavascripts()getStyleSheets()メソッドでレンダリングする必要があるJavaScriptとスタイルシートを宣言することができます。

class MyWidget extends sfWidgetForm
{
  public function getJavaScripts()
  {
    return array('/path/to/a/file.js');
  }
 
  public function getStylesheets()
  {
    return array('/path/to/a/file.css' => 'all', '/path/to/a/file.css' => 'screen,print');
  }
}

getJavaScripts()メソッドはJavaScriptファイルの配列を返さなければなりません。 getStylesheets()メソッドはファイル名をキーとし、メディアを値とする配列を返さなければなりません。

新しいwidget

symfony 1.2には新しいwidgetが備わっています。

  • sfWidgetFormDateRange
  • sfWidgetFormFilterInput
  • sfWidgetFormFilterDate
  • sfWidgetFormI18nSelectCurrency
  • sfWidgetFormSelectCheckbox

sfWidgetFormChoiceファミリー

新しいchoiceウィジェットファミリーも追加されました。

  • sfWidgetFormChoice
  • sfWidgetFormChoiceMany
  • sfWidgetFormPropelChoice
  • sfWidgetFormPropelChoiceMany

標準で、これらのウィジェットはSelect系のウィジェットの複製のように動作します。 しかし、それらはsfWidgetFormSelectsfWidgetFormSelectsfWidgetFormSelectRadioそしてsfWidgetFormSelectCheckBoxウィジットの上部にあるラッパーです。 レンダリングのためにこれらの1つを使います。 標準ウィジェットを変更するためにはいくつかのオプションを利用できます。

  • expanded:
    • もしfalseなら、ウィジェットはselectタグになります。
    • もしtrueでmultipleがfalseなら、ウィジェットはradioタグのリストになります。
    • もしtrueでmultipleがtrueなら、ウィジェットはcheckboxタグのリストになります。
  • rendered_options: ウィジェット(selectradiocheckbox)を作成するとき、これはレンダリング処理されるウィジェットに渡したいオプションです。
  • renderer_class: 標準クラスの代わりに利用するクラス
  • renderer: 直接オブジェクトを渡すこともできます(これは前述のオプションを上書きします)

オプションを利用したサンプルです。

$widget = new sfWidgetFormPropelSelect(array('model' => 'Article'));
 
// は次と同等である
$widget = new sfWidgetFormPropelChoice(array('model' => 'Article'));
 
// ラジオボタンを使うようにレンダリングを変更する
$widget->setOption('expanded', true);
 
// 複数の選択肢を作る
$widget = new sfWidgetFormPropelChoiceMany(array('model' => 'Article'));
 
// チェックボックスリストを使うようにレンダリングを変更する
$widget->setOption('expanded', true);

フォームを生成されたPropelのためにこれらの新しいウィジェットは標準で利用できます。

レスポンス

sfWebResponse::getCharset()

getCharset()はレンスポンスの現在の文字セットを返します。 コンテントタイプの設定を変更することでこの文字セットは自動的に更新されます。

sfWebResponse::getStylesheets()sfWebResponse::getJavascripts()

もしsfWebResponse::ALLを最初の引数として渡せばgetStyleSheets()getJavascripts()メソッドは現在は全てのスタイルシートとJavaScriptをポジションで指定された順番で返します。

$response = new sfWebResponse(new sfEventDispatcher());
$response->addStylesheet('foo.css');
$response->addStylesheet('bar.css', 'first');
 
var_export($response->getStylesheets());
 
// 出力
array(
  'bar.css' => array(),
  'foo.css' => array(),
)

sfWebResponse::ALLはポジションの引数のための標準の値でもあります。

PrototypeとScriptaculous

symfony 1.2においてバンドルされていたPrototypeとScriptaculousライブラリとヘルパー(JavascriptHelper)はコアプラグインに移動しました。

コアプラグインは本物のプラグインのようにふるまいますが、symfonyプラットフォームによって操作されます。 (コア)プラグインなので、新しいsfProtoculousPlugin(PrototypeとScriptaculousの組み合わせの名前で非公式でよく使われる)のJavaScriptとCSSファイルが作成され、これらは本当のプラグインアセットとして動作します。 これらは (1.0や1.1のときに配置されていた)web/sfディレクトリではなくweb/sfProtoculousPluginディレクトリに配置されることになります。 prototype_web_dir設定はその新しいディレクトリ(web/sfProtoculousPlugin)を指し示すようにもなります。

さらに、いろいろなJSフレームワークによって利用される基本的なJavascriptヘルパーがコア部分にJavascriptBaseHelperとして抽出されます。

新しい追加機能として、javascript_tag()slot()のように動作するようになります。次のような使い方ができます。

<?php javascript_tag() ?>
alert('All is good')
<?php end_javascript_tag() ?>

テスト

sfBrowser::info()

多くの機能テストをモジュールのために書くとき、何が行われているかについての視覚的な情報が役に立つことがあります。 symfony 1.2ではinfo()メソッドがあなたのテストをカテゴライズするのに役立つテキストを出力します。

$browser->
  info('First scenario')->
  // ... some tests
  info('Second scenario')->
  // ... some more tests
;

デバッキングテスト

機能テストで問題が発生するとき、ブラウザーに送信されたHTMLは原因を診断するために役に立ちます。 symfony 1.2では流暢なインターフェーススタイルを邪魔することなく生成されたHTMLを表示することができます。

$browser->
  get('/a_uri_with_an_error')->
  with('response')->debug()->
  // some tests that won't be executed
;

debug()メソッドはレスポンスヘッダーとコンテンツを出力し、ブラウザのフローを遮ります。

テスター

sfTestFunctionalBaseクラスは実際のテストをsfTesterクラスに委任するようになりました。 symfony 1.2はいくつかの組み込みテスタークラスがあります。

  • request: sfTesterRequest
  • response: sfTesterResponse
  • user: sfTesterUser
  • view_cache: sfTesterViewCache

全ての古いテストブラウザのメソッドはテスタークラスのメソッドに移動されました:

メソッドの名前 テスタークラス 新しいメソッドの名前
isRequestParameter sfTesterRequest isParameter
isRequestFormat sfTesterRequest isFormat
isStatusCode sfTesterResponse isStatusCode
responseContains sfTesterResponse contains
isResponseHeader sfTesterResponse isHeader
checkResponseElement sfTesterResponse checkElement
isUserCulture sfTesterUser isCulture
isCached sfTesterViewCache isCached
isUriCached sfTesterViewCache isUriCached

テスタークラスも新しいメソッドが用意されました。

テスタークラス 新しいメソッドの名前
sfTesterRequest hasCookie
sfTesterRequest isCookie
sfTesterRequest isMethod
sfTesterUser isAuthenticated
sfTesterUser hasCredential
sfTesterUser isAttribute
sfTesterUser isFlash

以下が新しいテスターの使い方です。

$browser->
  get('/')->
  with('request')->isParameter('module', 'foo')->
  with('request')->isParameter('module', 'bar')
;

with()メソッドを呼び出すことで呼び出し可能なメソッドにあるテスターオブジェクトを返します。

もし、複数のメソッドをテスターオブジェクトで呼び出したいなら、それらをblock内におくことができます。

$browser->
  get('/')->
 
  with('request')->begin()->
    isParameter('module', 'foo')->
    isParameter('module', 'bar')->
    isMethod('get')->
    isFormat('html')->
  end()->
 
  with('response')->begin()->
    isStatusCode(200)->
    checkElement('body', 'foo')->
    isHeader('Content-Type', 'text/html; charset: UTF-8')->
    isRedirected(false)->
  end()
;

sfTesterを継承するクラスを作成し登録することによって独自のテスターを追加することができます。

$browser->setTester('my_tester', 'myTesterClassName');

既存のテスタークラスも標準のクラス名を上書きすることで拡張することができます。

$browser->setTester('request', 'myTesterRequest');

フォームがあるページのテストを改善するために、select()deselect()メソッドをテストブラウザに追加しました。 現在はチェックボックスの選択/非選択とラジオボタンの選択処理をサポートしており、これは同じnameのラジオボタンが非選択になる原因かもしれません。

$browser->
  select('aRadioId')->
  select('aCheckboxId')->
  deselect('anotherCheckbox');

Cookie

クッキーは sfBrowsersfTestBrowserクラスにおいてもサポートされるようになりました。

クッキーを sfBrowserクラスにあるsetCookie()removeCokie()そしてclearCookies()メソッドを使うことでリクエストとリクエストの間で扱うことができます。

$b->
  setCookie('foo', 'bar')->
  removeCookie('bar')->
  get('/')->
  // ...
 
  clearCookies()->
  get('/')->
  // ...

また、sfTesterRequestクラスからhasCookie()isCookie()メソッドでCookieをテストすることができます。

$b->
  get('/')->
  with('request')->begin()->
    hasCookie('foo')->
    hasCookie('foobar', false)->
    isCookie('foo', 'bar')->
    isCookie('foo', '/a/')->
    isCookie('foo', '/!z/')->
  end()
;

hasCookie()メソッドは第2引数でクッキーがセットされてない状態をテストするための真偽値をとります。

isCookie()メソッドの第2引数はcheckElementResponseメソッドの第2引数のようにふるまいます。 それは文字列、正規表現もしくは否定正規表現だったりします。

ブラウザークラスは自動的に各Cookieのexpire値ごとにCookieを消します。

リクエスト

リクエストテスターからisMethod()メソッドを使ってあなたの機能テストのリクエストに使われるHTTPメソッドをテストすることもできます。

$b->
  setField('login', 'johndoe')->
  click('Submit')->
  with('request')->isMethod('post');

リンク

リンクになっているクリックやボタンをシミュレーションするとき、click()メソッドという名前を使います。 しかし、同じ名前で2つの異なるリンクやボタンを差別化することができません。

symfony 1.2では click()メソッドではオプションを第3引数に渡します。

positionというオプションをクリッックしたいしたいリンクを変更するときに渡します。

$b->
  click('/', array(), array('position' => 1))->
  // ...
;

標準で、symfonyはページにある項目の最初のリンクをクリックします。

methodオプションでクリックしたいリンクやフォームのメソッドを変更することもできます。

$b->
  click('/delete', array(), array('method' => 'delete'))->
  // ...
;

これはリンクがJavaScriptで動的に生成されるフォームで変換される場合に役立ちます。 _with_csrtオプションを渡すことでlink_to()ヘルパーによってCSRFトークンの生成をシミュレートすることもできます。

$b->
  click('/delete', array(), array('method' => 'delete', '_with_csrf' => true))->
  // ...
  call('/delete', 'delete', array('_with_csrf' => true))->
  // ...
;

フォーム

新しいフォームフレームワークを使うなら、投稿されたフォームから生成されたエラーをテストすることができるようになりました。

$browser->
  click('save', array(...))->
  with('form')->begin()->
    hasErrors()->
    isError('name', 'Required.')->
    isError('name', '/Required/')->
    isError('name', '!/Invalid/')->
    isError('name')->
    isError('name', 1)->
  end()
;

また、debug()メソッドでフォームをデバッグすることもできます。

$browser->
  click('save', array(...))->
  with('form')->debug()->
  // some tests that won't be executed
;

もしエラーがあればサブミットされた値と全てのエラーを出力します。

Propel

Propelプラグインにはpropelテスターが附属しています。このテスターは標準では登録されていません。

$browser->setTester('propel', 'sfTesterPropel');

このテスターはPropelモデルをテストするためのcheck()メソッドを提供します:

$browser->
  post('...', array(...))->
  with('propel')->begin()->
    check('Article', array(), 3)->
    check('Article', array('title' => 'new title'))->
    check('Article', array('title' => 'new title'))->
    check('Article', array('title' => 'new%'))->
    check('Article', array('title' => '!new%'), 2)->
    check('Article', array('title' => 'title'), false)->
    check('Article', array('title' => '!title'))->
  end()
;

最初の引数はモデル名になり、第2引数はCriteriaオブジェクトか条件を表した配列になります。 そして第3引数は次のどれかでなければなりません。

  • true: Criteriaが返す最低でも1つのオブジェクトをチェックする
  • false: Criteriaがオブジェクトを返さないことをチェックする
  • 返されるオブジェクトの数をチェックするための数値

カバレッジ

実行したテストのコードカバレッジを出力するための新しいtest:coverageタスクが用意されました。

$ ./symfony test:coverage test/unit/model/ArticleTest.php lib/model/Article.php

最初の引数はファイルかテストのディレクトリです。第2引数はあなたがカバーしたいファイルかディレクトリになります。

もし、どの行がカバーされていないかを知りたいなら、次のように--detailedオプションを追加するだけです。

./symfony test:coverage --detailed test/unit/model/ArticleTest.php lib/model/Article.php

ロガー

symfony 1.2では新しいロガーが組み込まれました。 それがsfVarLoggerです。 このロガークラスは後で利用するために全てのメッセージを配列でロギングします。 ログをとって、それらを次のように使うことができるようになります。

$log = new sfVarLogger();
$log->log('foo');
 
var_export($log->getLogs());
 
// outputs
array(
  0 => array(
    'priority'      => 6,
    'priority_name' => 'info',
    'time'          => 1219385295,
    'message'       => 'foo',
    'type'          => 'sfOther',
    'debug_stack'   => array()
  )
)

各ログはprioritypriority_nametimemessagetypeそしてdebug_stackというキーを持つ連想配列です。

debug_stack属性はxdebug_loggingオプションがtrueにセットされているときだけセットされます。 オプションがセットされているときはxdebugのスタックトレースを配列をして保持しています。

sfVarLoggerはまたsfWebDebugLoggerクラスの基礎となるクラスでもあります。 そのため、sfWebDebugLoggerxdebugLoggingオプションはxdebug_loggingに名前が変更されました。

Webデバッグツールバー

Webデバッグツールバーはカスタマイズができるようになりました。ツールバーはパネルで構成されています。 パネルはsfWebDebugPanelを拡張したオブジェクトであり、ツールバー上に表示するために必要とされる情報を 提供してくれます。

標準では、次のようなパネルが自動的に登録されています。

名前 クラス名
symfony_version sfWebDebugPanelSymfonyVersion
cache sfWebDebugPanelCache
config sfWebDebugPanelConfig
logs sfWebDebugPanelLogs
time sfWebDebugPanelTimer
memory sfWebDebugPanelMemory
db sfWebDebugPanelPropel

ウェブデバッグツールバーをdebug.web.load_panelsイベントリスナーを利用することでカスタマイズできます。 このリスナーで追加された新しいパネルを追加したとき、すでに存在するパネルを削除したときや別のものに置き換えることができます。

sfWebDebugPanelLogsパネルはdebug.web.filter_logsイベントを通知することで表示されるログをフィルター処理します。 たとえば、sfWebDebugPanelPropelsfWebDebugPanelTimerは全てのPropelに関連するログやログパネルからタイマーログを取り除くためにこのイベントに接続します。

ウェブデバッグツールバーに表示される全体の時間は$_SERVER['REQUEST_TIME'](以前はsfConfig::get('sf_time_start') で計算していましたが、もやはこれは存在しません)で計算しています。 これは表示される時間はsymfony1.0や1.1よりもより長くなっていることを意味します。

タスク

取り込まれているPhingタスクが失敗するなら、Phingに依存しているPropelタスクははっきりとしたエラーメッセージを出力します。

CLIタスクの中にはアプリケーション名を引数として必要としているものがあります。 なぜならそれらはデータベースに接続する必要があるからです。 アプリケーション上でカスタマイズされる設定ファイルが必要なため私たちはアプリケーションが必要なのです。 そして全てのsymfonyの設定システムはアプリケーションレベルが基礎となっています。

これらのタスクにとって、引数はオプションである"application"オプションになってとりのぞかれました。 もし、"application"オプションを提供しないならsymfonyはプロジェクトのdatabases.ymlファイルからデータベース設定を取得してくるようになりました。

次のタスクの用法はこれらに従って変更されました。

  • propel:build-all-load
  • propel:data-dump
  • propel:data-load

note

これはsfDatabaseManagerが今ではプロジェクト設定やアプリケーション設定を取得するようになったので可能になりました。 興味深いこととで、sfDatabaseConfigHandlerは今では静的か動的な設定ファイルの配列に基づく設定を返すから動作するのです(exeute()evaluate()メソッドをごらんください)

デバッグのために、propel;build-modelpropel:build-allそしてpropel:build-all-loadタスクは--traceオプションを指定すれば生成されるスキーマをとりのぞきません。

propel:insert-sql

propel:insert-sqlタスクは全てのデータをデータベースからとりのぞきます。 情報を破壊するので、タスクの実行前にユーザーにたずねるようになりました。 propel:build-allpropel:build-all-loadタスクもpropel:insert-sqlタスクと同じことがあてはまります。

もし、これらのタスクをバッチ処理で使いたいなら確認のための質問を避けたいでしょう。 そのときはno-confirmationオプションを渡してください:

$ php symfony propel:insert-sql --no-confirmation 

symfony 1.2より前では、propel:insert-sqlタスクはpropel.iniからのデータベースの情報を読み込むことしかしませんでした。 symfony 1.2ではdatabases.ymlから読み込むことができるようになりました。 そのため、モデルに複数の異なる接続先を設定したいならこのタスクはそれらを考慮するようになりました。 この新しい機能のおかげで、もし指定した接続先からのSQLだけを読み込みたい場合に--connection オプションを指定することができるようになりました:

$ php symfony propel:insert-sql --connection=propel 

また--env--applicationオプションも次のように特定の設定を選択するために使うことができます。

$ php symfony propel:insert-sql --env=prod --application=frontend 

タスクのために利用可能な新しいメソッド

sfTask基底クラスはタスクで利用できる3つの新しいメソッドを提供するようになりました。

  • logBlock(): スタイル化されたブロックでメッセージをログします(標準のスタイルはINFO、COMMENT、ERRORです)
  • ask(): ユーザーに質問を行い回答を返します。
  • askConfirmation(): 確認をユーザーに行い、ユーザーが確認すればtrueをそうでなければfalseを返します。

propel:generate-module

propel:generate-crutpropel:generate-moduleに名前が変更されました。 古いタスク名はエイリアスとしてまだ利用することができます。

propel:generate-moduleタスクのnon-atomic-actionsオプションはとりのぞかれ次のような新しいオプションが追加されました。

  • singular: The singular name for the actions and templates
  • plural: The plural name for the actions and templates
  • route-prefix: The route prefix to use
  • with-propel-route: Whether the related routes are Propel aware

propel:generate-module-for-route

新しいpropel:generate-module-for-routeタスクはルーティングの定義に基づくモジュールを作成します。

php symfony propel:generate-module-for-route frontend articles

app:routes

いまではsymfonyは(以下のような)ルーティングを自動生成でき、app:routesタスクは現在のアプリケーションに設定されているルーティングのリストを表示します:

php symfony app:routes frontend

もしルーティングの内容を詳しく知りたいなら、次のようにルート名を追加するだけです。

php symfony app:routes frontend articles_update

plugin:install-assets

通常プラグインはタスクでインストールされるとき正しくコアプラグインがそうであるようにwebディレクトリにシンボリックリンクが作成されます。

これと同じことを手動で行うためには以下のようにします。

symfony plugin:publish-assets --only-core

目標はプロジェクトの生成とアップグレードタスクがあなたに代わってこれを行うことです。

ルーティング

ルーティングのオプション

ルーティングタスクは2つのオプションをとります。

  • generate_shortest_url: 可能なかぎり最も短いURLを生成することができるかどうか
  • extra_parameters_as_query_string: クエリストリングとして外部パラメータを生成するかどうか

標準では、symfony 1.0、1.1と互換性を保つためにfactories.ymlにおいてfalseがセットされています。

ルーティングの基礎部分でこれらのオプションの有効無効を設定することもできます。

articles:
  url:     /articles/:page
  param:   { module: article, action: list, page: 1 }
  options: { generate_shortest_url: true }

できるだけ最短のURLを生成しようとするので、もし、pageの値として1を渡すなら、生成されるURLは/articlesになるでしょう:

echo url_for('@articles?page=1');
// /articles
// would have been /articles/1 in symfony 1.1
 
echo url_for('@articles?page=2');
// /articles/2

extra_parameters_as_query_stringの例は以下のようになります。

articles:
  url:     /articles
  options: { extra_parameters_as_query_string: true }

ルーティングは外部パラメータを受け取り、クエリストリングとしてそれらを追加します。

echo url_for('@articles?page=1');
// /articles?page=1
// would not have matched the route in symfony 1.1
 
echo url_for('@articles?page=2');
// /articles?page=2

sfRoute

sfPatternRoutingクラスはフラットな連想配列の代わりにsfRouteオブジェクトの配列でルーティングを保持しています。

標準では、symfonyは組み込みのsfRouteオブジェクトを使います。 しかし次のように特定のclassエンティティをrouting.yml設定ファイルで変更することができます。

foo_bar:
  url:   /foo/:bar
  class: myRoute
  param: { module: foo, action: bar }

全てのルーティングのロジックはsfRouteクラスに含まれています。 これはあなた自身で用意したもので解析ロジックと生成ロジックを上書きすることができるということです。

tip

より簡単に標準の挙動をカスタマイズできるようにsfRouteクラスは古いsfPatternRougintクラスよりさらにモジュール化されました。 "コンパイレーション"フェーズはより小さなメソッドにリファクタリングされ、コードはよりシンプルになり、"本当の"トークナイザーに基づいています。

PHPコードであなたのルーティングに接続するなら、sfRouteインスタンスをconnect()preprendRoute()appendRoute()そしてinsertRouteBefore()メソッドの第2引数として渡さなければなりません:

$route = new myRoute('/foo/:bar', array('module' => 'foo', 'action' => 'bar'));
$routing->connect('foo_bar', $route);

リクエストがあった場合、一致しているルーティングオブジェクトはリクエストの属性として保存され、getRoute()メソッドをとおしてアクションから取得することができます。

public function executeIndex()
{
  $route = $this->getRoute();
}

sfRouteコンストラクターは各ルーティングをカスタマイズできるようにその最後の引数としてオプションの配列をとります。 routing.yml設定ファイルで、optionsキーを次のように使います。

article:
  url:     /article/:id-:slug
  options: { segment_separators: [/, ., -] }

sfRequestRoute

symfonyは別の組み込みルーティングであるsfRequestRouteを持っており、これによってHTTPメソッドをあなたのルーティングに強制することができます。

article:
  url:          /article/:id
  requirements: { sf_method: get }
  class:        sfRequestRoute

もし、sf_methodを必要とせず指定しなければ、symfonyはgetheadリクエストを強制します。

sfRoutingparse()メソッドが第2引数としてコンテキストをとるため可能になっています。 リクエストがルーティングを呼び出すとき、次のようなコンテキストを渡します。

  • method: HTTPメソッド名
  • format: リクエストのフォーマット
  • host: ホスト名
  • is_secure: リクエストがHTTPSで呼び出されたかどうか
  • request_uri: 完全なリクエストURI
  • prefix: 生成されたルーティングに付け加えられるプレフィックス

前述のルーティング設定で、articleへのルーティングはHTTPメソッドがgetの場合のみ一致します。 同じurlを異なるメソッドを必要とするようにルーティングを設定するなら、次のようにルーティングを生成するときsf_methodパラメーターを渡すことができます。

<?php echo link_to('Great article', '@article?id=1&sf_method=get')) ?>

sfObjectRoute

symfony 1.2 はsfRequestRouteを継承する別のルーティングクラスであるsfObjectRouteを実装しています。

sfObjectRouteはPHPオブジェクトにルーティングを結びつけます。 sfObjectRouteはオブジェクトやオブジェクトの集まりやルーティングに関連するコレクションを取得するためのPHPのクラスにメソッドを呼び出せるようにしたりします。

article:
  url:     /article/:id
  class:   sfObjectRoute
  options: { model: Article, type: object, method: getById }

URLがルーティングに一致するとき、sfObjectRoute::getObject()メソッドで、Article::getById()メソッドによって関連する呼び出されるオブジェクトを取得することができます。

同じことがオブジェクトの集まりにもあてはまります。

articles:
  url:     /articles/newest
  class:   sfObjectRoute
  options: { model: Article, type: list, method: getNewest }

sfPropelRoute

sfPropelRoutesfObjectRouteをPropelモデルのルーティングに結びつけるために拡張されます。

アクションにおいて、sfObjectRoute::getObject()sfObjectRoute::getObjects()メソッドを利用することで関連するオブジェクトやオブジェクトの集まりを取得することができます。

public function executeList($request)
{
  $this->articles = $this->getRoute()->getObjects();
}
 
public function executeShow($request)
{
  $this->article = $this->getRoute()->getObject();
}

ここにArticlePropelオブジェクトのための例があります。

article:
  url:     /article/:id
  param:   { module: article, action: show }
  class:   sfPropelRoute
  options: { model: Article, type: object }
 
articles:
  url:     /articles
  param:   { module: article, action: list }
  class:   sfPropelRoute
  options: { model: Article, type: list, method: getPublishedArticleCriteria }

メソッドが定義されていないのであれば、sfPropelRouteは利用できるルーティングの変数に基づいてCriteriaオブジェクトを構築することでオブジェクトを取得します。

sfPropelRouteにはsfRouteを上回る2つの主な利点があります:

  • リクエストがありルーティングがURLに一致するとき、一致するsfPropelRouteオブジェクトはアクションにて利用することができ、関連するArticleオブジェクトはgetObject()メソッドを呼ぶことで利用することができます。 さらに、オブジェクトがデータベースに存在しないなら、自動的に404エラーページにリダイレクトします。 これはアクションでの決まりきった指示を減らすことができるということです。

  • このルーティングへのリンクを作成するとき、新しいurl_for()を使うことができ、次のようにArticleオブジェクトに直接引数を渡すことができます:

    <?php echo url_for('article', $article) ?>

    その他のパラメーターを渡すなら(例えばHTTPメソッドを強制したいような場合)、次のように配列を使うことができます。

    <?php echo url_for('article', array('sf_subject' => $article, 'sf_method' => 'get')) ?>

    もちろん、次のように完全なパラメーターもまだ利用することができます。

    <?php echo url_for('article', array('id' => $article->getId(), 'slug' => $article->getSlug())) ?>

    もしくは次のように内部URLを使うこともできます。

    <?php echo url_for('@article?id='.$article->getId().'&slug='.$article->getSlug()) ?>

    sfPropelRouteはArticleオブジェクトを自動的にパラメーターの配列に変換します。

sfPropelRouteはプライマリキーだけでは動作しません。 いろいろなカラムを用いて動作させることができます。 次の例では、slugカラムをルーティングパターンに追加することができます。

article:
  url:     /article/:id/:slug
  param:   { module: article, action: show }
  class:   sfPropelRoute
  options: { model: Article, type: object }

しかし、データベースに存在しない情報をパターンに含めたい場合もあるでしょう。 このような場合、methodオプションに渡すことができます。

post:
  url:     /post/:id/:year/:month/:day/:slug
  param:   { module: article, action: show }
  class:   sfPropelRoute
  options: { model: Article, type: object, method: getObjectForRoute }

getObjectForRoute()は最初の引数としてパラメータの配列を受け取りArticleオブジェクトを返さなければなりません。

class ArticlePeer extends BaseArticlePeer
{
  static public function getObjectForRoute($parameters)
  {
    $criteria = new Criteria();
    $criteria->add(self::ID, $parameters['id']);
 
    return self::doSelectOne($criteria);
  }
}

sfPropelRouteはパラメーターを解析されるルートを上書きするためのsetListCriteria()メソッドも提供します。 ルーティングによって返されるオブジェクトを洗練させたいときに特に役立ちます。 たとえば、次のように他のパラメーターに基づく検索などです:

public function executeList($request) 
{ 
  $this->filters = new ArticleFormFilter(); 
  if ($request->isMethod('post')) 
  { 
    $this->filters->bind($request->getParameter('article_filters')); 
    if ($this->filters->isValid()) 
    { 
      $this->getRoute()->setListCriteria($this->filters->getCriteria()); 
    } 
  } 
 
  $this->articles = $this->getRoute()->getObjects(); 
} 

sfRouteCollectionsfObjectRouteCollectionそして sfPropelRouteCollection

symfonyは"collection"ルートクラスも実装しています。

これらのクラス(sfRouteCollectionsfObjectRouteCollectionsfPropelRouteCollection)は定義に基づいた標準的なルーティングを作成します。

articles:
  class:   sfPropelRouteCollection
  options: { model: Article, module: article }

標準では、このルーティングは以下の7つのルーティングを生成します:

  • list: articles GET /articles.:sf_format
  • new: articles_new GET /articles/new.:sf_format
  • create: articles_create POST /articles.:sf_format
  • edit: articles_edit GET /articles/:id/edit.:sf_format
  • update: articles_update PUT /articles/:id.:sf_format
  • delete: articles_delete DELETE /articles/:id.:sf_format

複数のオプションで生成されるルーティングをカスタマイズすることができます:

  • model: モデルクラス名を指定
  • actions: (上記の7個のリストから)生成されるアクションのリストを指定
  • module: モジュール名
  • prefix_path: 各ルーティングのために追加するプレフィックス
  • column: プライマリキーとするカラム名(標準ではid)
  • with_show: showメソッドを追加するかどうか
  • segment_names: neweditのためのセグメント名
  • model_methods: オブジェクトのコレクションを取得するために使うメソッド
  • requirements: 標準の必須条件(標準ではid\d+を要求します)
  • route_class: 利用するためのルートクラス (標準では sfObjectRouteのためにはsfObjectRouteCollection sfPropelRouteCollectionのためにはsfPropelRouteを利用)
  • collection_actions: コレクションアクションとして追加するためのアクションのリスト
  • object_actions: オブジェクトアクションとして追加するためのアクションのリスト

ここにオプションを指定した場合の別の例があります。

articles:
  class:   sfPropelRouteCollection
  options:
    model:              Article
    module:             article
    prefix_path:        /foo
    methods:            [ list, edit, update ]
    segment_names:      { list: nouveau, edit: edition }
    collection_actions: { filter: post }
    object_actions:     { publish: put }

URLヘルパー

link_to()url_for()

もし、POSTPUTまたはDELETEHTTPメソッドでサブミットされなければならないリソースへのリンクを作成したいとき、link_to()ヘルパーでmethodオプションを渡すことでリンクをフォームに変換することができます。

<?php echo link_to('@article_delete?id=1', array('method' => 'delete')) ?>

POSTDELETEそしてPUTメソッドのために、settings.ymlでCSRFの保護機能が有効になっているならばlink_to()ヘルパーはCSRFトークンも埋め込みます。

古いpostオプションはまだ有効ですが廃止される予定です。

// 次は廃止される予定です
<?php echo link_to('@some_route', array('post' => true)) ?>
 
// 次で同じ実装になります
<?php echo link_to('@some_route', array('method' => 'post')) ?>

ulf_for()link_to()ヘルパーは新しい特徴をサポートするようになりました。 内部URIの代わりに、ルーティング名とパラメーターの配列もとることができます。

echo url_for('@article', array('id' => 1));
echo link_to('Link to article', '@article', array('id' => 1));

何も変更を加えなくてもこれまでの設定は動作します。

コンフィギュレーション

symfony 1.2より前は、全てのプラグインはpluginsディレクトリにインストールされていました。 そして、全ての組み込みプラグインは自動的に読み込まれていました。

symfony 1.2では、あなたのプロジェクト内で利用したいプラグインを有効にする必要があります。 ProjectConfigurationクラスでこれを行うことができます。 Doctrineプラグインを有効にし、Propelプラグインを無効にする方法は次のとおりです:

public function setup()
{
  $this->enablePlugins('sfDoctrinePlugin');
  $this->disablePlugins('sfPropelPlugin');
}

複数のプラグインを一度に追加する場合はプラグイン名の配列を渡します:

public function setup()
{
  $this->enablePlugins(array('sfDoctrinePlugin', 'sfGuardPlugin'));
}

setPluginsメソッドを用いることでプラグインの読み込まれる順番を変更することができます:

[php] public function setup() { $this->setPlugins(array('sfDoctrinePlugin', 'sfCompat10Plugin')); }

1.0と互換性のあるプラグインを有効にするためには、設定で次のように有効にする必要があります。

public function setup()
{
  $this->enablePlugins('sfCompat10Plugin');
}

標準では、symfonyはPropelプラグインだけが有効です。

全てのインストールしたプラグインも有効にすることができます。

public function setup()
{
  $this->enableAllPluginsExcept('sfDoctrinePlugin');
}

上の例のようにしてDoctrineプラグイン以外の全てのプラグインを有効にすることができます。 1.0または.1.1からアップグレードする場合は、この行によってsymfony 1.0と1.1のときのようにsymfonyを動作させることができます。

プラグインのコンフィグレーション

プラグインにはプラグインを設定するクラスのためオプションが存在します。 これらのプラグイン設定クラスはプラグインのためにオートローディングを設定し、sfProjectConfigurationでインストールされています。 symfony 1.2タスクはプラグインクラスが使用するアプリケーション名をもはや必要としません。 プラグインはcommand.*イベントに接続することで以前はできなかったことができるようになりました。

フィルター

symfonyはモデルに基づくフィルター(検索フォーム)をpropel:build-filtersタスクで生成することができるようになりました。:

$ php symfony propel:build-filters

このタスクは標準ではlib/filter/ディレクトリにフィルター(検索フォーム)クラスを生成します。

Articleモデルをフィルタリング処理するためには、以下のようにアクションでコードを書く必要があります。

$this->filters = new ArticleFormFilter();
if ($request->isMethod('post'))
{
  $this->filters->bind($request->getParameter('article_filters'));
  if ($this->filters->isValid())
  {
    $this->articles = ArticlePeer::doSelect($this->filters->getCriteria());
  }
}

そして、以下が関連するテンプレートのコードです:

<form action="<?php echo url_for('@articles_filter') ?>" method="post">
  <table>
    <?php echo $filters ?>
    <tr>
      <td colspan="2">
        &nbsp;<a href="<?php echo url_for('@articles') ?>">Reset</a>
        <input type="submit" value="Filter" />
      </td>
    </tr>
  </table>
</form>

もし、永続的にリクエスト間でフィルターを保持したいなら、以下のようなちょっとした動作例のように行います:

public function executeList($request)
{
  $this->filters = new ArticleFormFilter($this->getUser()->getAttribute('article_filters'));
  if ($request->isMethod('post'))
  {
    $this->filters->bind($request->getParameter('article_filters'));
    if ($this->filters->isValid())
    {
      $this->getUser()->setAttribute('article_filters', $this->filters->getValues());
    }
  }
 
  $criteria = $this->filters->buildCriteria($this->getUser()->getAttribute('article_filters'));
  $this->articles = ArticlePeer::doSelect($criteria);
}

テンプレートの例外処理

キャッチできないあらゆる発生した例外をレンダリング処理するとき、symfonyは現在のリクエストフォーマットを考慮するようになりました。 プロジェクトまたはアプリケーションのconfig/errorディレクトリにテンプレートを追加することで各フォーマットの出力をカスタマイズできます。

たとえば、XMLリクエストで発生したキャッチできない例外はアプリケーションがデバッグモード時はconfig/error/exception.xml.phpを、デバッグモードでない場合はconfig/error/error.xml.phpをレンダリング処理します。

プロジェクトディレクトリ内にカスタマイズした500エラーテンプレートを用意していれば、それを新しいディレクトリに手動で移動する必要があります。

  • symfony 1.1 ではconfig/error500.phpからconfig/error/error.html.php
  • symfony 1.0 ではweb/errors/error500.phpからconfig/error/error/html/php

ちょっとした改善

symfony 1.2ではあちらこちらで多くの改善がなされています。ここにそのいくつかを紹介します。

アクション

アクションでは、generateUrl()を呼ぶことで直接ルーティングオブジェクトを使うことでURLを生成することができるようになります。

public function executeIndex()
{
  $this->redirect($this->generateUrl('homepage'));
}

generateUrl()メソッドにはルーティング名、パラメーターの配列、絶対的URLを生成するかどうかをコンストラクターの引数として渡すことができます。

標準で、redirectIf()redirectUnless()メソッドをアクションの中で使うとき、symfonyはHTTPレスポンスのステータスを自動的に302に変更します。

これらの2つのメソッドは追加のおpションを持つようになり、この標準のステータスコードを変更できるようになりました。

$this->redirectIf($condition, '@homepage', 301);
$this->redirectUnless($condition, '@homepage', 301);

この機能はすでにredirect()メソッドにおいて実装されています。

YAML

YAMLパーサーはキーのマージを完全にサポートしました(サンプルについてはhttp://yaml.org/type/merge.htmlをごらんください)。

$yaml = new sfYamlParser();
 
var_export($yaml->parse(<<<EOF
default_param: &default_param
  datasource: propel
  phptype:    mysql
  hostspec:   localhost
  database:   db
  username:   user
  password:   pass
 
param:
  <<: *default_param
  username:   myuser
  password:   mypass
EOF
));
 
// 出力
array(
  'default_param' => array(
    'datasource' => 'propel',
    'phptype'    => 'mysql',
    'hostspec'   => 'localhost',
    'database'   => 'db',
    'username'   => 'user',
    'password'   => 'pass',
  )
 
  'param' => array(
    'datasource' => 'propel',
    'phptype'    => 'mysql',
    'hostspec'   => 'localhost',
    'database'   => 'db',
    'username'   => 'myuser',
    'password'   => 'mypass',
  )
)

sfParameterHolder

sfParameterHolderhas()メソッドはよりその本来の正しい動作になるように変更されました。

もし値がnullだった場合はtrueを返すようになりました:

$ph = new sfParameterHolder();
$ph->set('foo', 'bar');
$ph->set('bar', null);
 
$ph->has('foo') === true;
$ph->has('bar') === true; // symfony 1.0もしくは1.1ではfalseを返す

sfparameterHolder::has()メソッドは多くのコアクラスの中でhasParameter()hasAttribute()メソッドで利用されています。

image_tag()ヘルパー

symfony 1.0と1.1では image_tagヘルパーはファイル名からimgタグのalt属性を生成しています。 これからはsf_compat_10が有効になっているときにだけこのように動作します。 これからは(x)htmlバリデーターが使っているセットされていないalt属性を簡単に見つけることができます。 さらに、新しいalt_titleオプションによってaltをセットし、タイトル属性を同じ値にすることができます。 これはクロスブラウザーでのツールチップとして利用できます。

ビューコンフィグレーション

symfony 1.2では、module.ymlpartial_view_classを設定することでパーシャルを処理するために使用されるビュークラスを変更することができるようになりました。 このクラスはsfPartialViewを拡張したものでなければなりません。 同じことがview_class設定でも行えます。 symfonyは自動的にPartialViewpartial_view_classの値に適用しようとします。

# module.yml
all:
  partial_view_class: my

ファクトリ

sfViewCacheManagerクラスはfactories.ymlで設定できるようになりました。

view_cache_manager:
  class: sfViewCacheManager

ビュー

標準のsf_cache_namespace_callable設定でsfViewCacheManager::generateCacheKey()を上書きすることができます。 symfony1.2では、collableは追加の引数のビュークラスインスタンスで呼び出されるようになりました。

イベント

symfony 1.2には新しいイベント機能が実装されています。

  • user.change_authentication: ユーザーの認証ステータスが変更されたときに通知します。 このイベントは変更が発生したあとに引数としてauthenticatedフラグをとることができます。
  • debug.web.load_panels(例. ウェブデバッグツールバーパラグラフ)
  • debug.web.filter_logs(例. ウェブデバッグツールバーパラグラフ)

I18N

内部的に、sfCulterUnfoクラスはこれらかはSingletonとしてのみ利用できるようになります。 getInstance()メソッドをバイパスすることが可能で、新しいオブジェクトを直接インスタンス化することができるとしても廃止される予定です。 Singletonとして利用するために、1つのリクエストごとに1つのカルチャーについての情報をインスタンス化するためパフォーマンスは向上し、設定クラスの中でカルチャーをグローバルに上書きすることができるということです。

sfCulterInfo::getCountries()sfCulterInfo::getCurrencies()そしてsfCultureInfo::getLanguages()メソッドは 戻り値を制限するためのオプションの引数をとることができるようになりました。

// will only return the FR and ES countries in english
$countries = sfCultureInfo::getInstance('en')->getCountries(array('FR', 'ES'));

sfCulterInfo::getCurrencies()メソッドは通貨名の配列を返します。 以前のバージョンのsymfonyでは、通貨記号と名前の配列を返していました。 以前のような動作をさせるためには、次のように第2引数にtrueを渡すだけです。

$currencies = sfCultureInfo::getInstance('en')->getCurrencies(null, true);

1つだけの国、言語、通貨の翻訳を取得するために、getCountry()getCurrency()getLanguage()メソッドをsfCultureInfoクラスから使うことができるようになりました。

インクルードパスの管理

symfony 1.2はPHPのinclude_path設定を簡単に行えるようにするために静的メソッドであるsfToolkit::addIncludePath()メソッドを追加します。 このメソッドは2つのパラメーターを受けつけます。 それは単一のパスかパスの配列と、ポジションを意味する文字列("front", "back"のどちらか)です。 第2引数は標準では"front"です。

// an example from sfPropelPlugin 
sfToolkit::addIncludePath(array( 
  sfConfig::get('sf_root_dir'), 
  sfConfig::get('sf_symfony_lib_dir'), 
  realpath(dirname(__FILE__).'/../lib/vendor'), 
)); 

アドミンジェネレーター

symfony1.2のためにアドミンジェネレーターは書き直されました。 そして新しいアドミンジェネレーターはフォームフレームワークに基づいています。 ジェネレータでモジュールを生成するためには、propel:generate-adminタスクを次のように利用します。

$ php symfony propel:generate-admin backend Article

標準では、モジュールのためにRESTルーティングを追加します。 あなた自身でルーティングを作り、それをモデルクラス名の代わりに引数として渡すこともできます。

$ php symfony propel:generate-admin backend article

設定はgenerator.ymlで行います。 全ての設定はconfigキーの下に存在します。

generator:
  class: sfPropelGenerator
  param:
    model_class:           DemoCategory
    theme:                 admin
    non_verbose_templates: true
    with_show:             false
    singular:              ~
    plural:                ~
    route_prefix:          categories
    with_propel_route:     1
 
    config:
      actions: ~
      fields:  ~
      list:    ~
      filter:  ~
      form:    ~
      edit:    ~
      new:     ~

editnewの新しいフォームのための異なる設定を持つことができるようになり、これらはform設定から継承されています。

nameエントリーはlabelに名前が変更されました。

古いアドミンジェネレータは後方互換性が保たれています。そのため、propel:init-adminタスクを実行することで利用し続けることができます。