PHP - Symfony

Last-modified: 2011-02-16 (水) 17:17:45

前提条件

ここで説明する内容は、以下の環境で動作確認を行っている。

  • Fedora Core 7
  • Apache/2.2.4
  • PHP 5.2.2
  • PostgreSQL 8.2.4-1.fc7
  • symfony 1.0.6

Symfony とは

PHP5用のWebアプリケーションフレームワーク。

インストール

# pear channel-discover pear.symfony-project.com
# pear install symfony/symfony

あとは、↓ここを参照

Hello World

プロジェクトの作成

$ mkdir /home/naka/Work/symfony/myproject
$ cd /home/naka/Work/symfony/myproject
$ symfony init-project myproject

以下のようなディレクトリが自動的に作られる。

[naka@localhost myproject]$ ls -l
合計 48
drwxr-xr-x 2 naka naka 4096 2007-08-10 13:03 apps/
drwxr-xr-x 2 naka naka 4096 2007-08-10 13:03 batch/
drwxrwxrwx 2 naka naka 4096 2007-08-10 13:03 cache/
drwxr-xr-x 2 naka naka 4096 2007-08-10 13:03 config/
drwxr-xr-x 4 naka naka 4096 2007-08-10 13:03 data/
drwxr-xr-x 2 naka naka 4096 2007-08-10 13:03 doc/
drwxr-xr-x 3 naka naka 4096 2007-08-10 13:03 lib/
drwxrwxrwx 2 naka naka 4096 2007-08-10 13:03 log/
drwxr-xr-x 2 naka naka 4096 2007-08-10 13:03 plugins/
-rwxrwxrwx 1 naka naka  389 2007-08-10 13:03 symfony*
drwxr-xr-x 5 naka naka 4096 2007-08-10 13:03 test/
drwxr-xr-x 6 naka naka 4096 2007-08-10 13:03 web/

アプリケーションの作成

$ cd /home/naka/Work/symfony/myproject/
$ symfony init-app myapp

appsディレクトリの下に以下のようなディレクトリが自動的に作られる。

drwxr-xr-x 7 naka naka 4096 2007-08-10 13:06 myapp/

Webサーバの設定

symfonyアプリケーションを公開するために、PATHエイリアスやディレクトリの設定を行う。

DocumentRoot の設定をいじりたいので、VirtualHostに書く。

<VirtualHost *:80>
    ServerAdmin invalid@example.com
    DocumentRoot "/home/naka/Work/symfony/myproject/web"
    ServerName symfony.example.com
    ErrorLog logs/symfony.example.com-error_log
    CustomLog logs/symfony.example.com-access_log common
    DirectoryIndex index.php
    Alias /sf  /usr/share/pear/data/symfony/web/sf
    <Directory " /usr/share/pear/data/symfony/web/sf">
    AllowOverride All
    Allow from All
   </Directory>
    <Directory " /home/naka/Work/symfony/myproject/web">
    AllowOverride All
    Allow from All
   </Directory>
</VirtualHost>

クライアント側の Hostsに、

192.168.10.128 symfony.example.com

サーバ側の Hostsに、

127.0.0.1 symfony.example.com

と書いておく。

これで、http://symfony.example.com/index.php にアクセスすると、

 Congratulations! You have successfully created your symfony project.

のメッセージが表示される。これで、Symfonyによる雛型が完成。

モジュールのセットアップ

$ cd /home/naka/Work/symfony/myproject
$ symfony init-module myapp mymodule

これで、いくつかのモジュールが自動的に作成される。

[naka@localhost myproject]$ ls -l apps/myapp/modules/
合計 4
drwxr-xr-x 7 naka naka 4096 2007-08-10 13:32 mymodule/
[naka@localhost myproject]$ ls -l apps/myapp/modules/mymodule/
合計 20
drwxr-xr-x 2 naka naka 4096 2007-08-10 13:32 actions/
drwxr-xr-x 2 naka naka 4096 2007-08-10 13:32 config/
drwxr-xr-x 2 naka naka 4096 2007-08-10 13:32 lib/
drwxr-xr-x 2 naka naka 4096 2007-08-10 13:32 templates/
drwxr-xr-x 2 naka naka 4096 2007-08-10 13:32 validate/

デフォルトページの設定

indexSuccess.php

$ cd /home/naka/Work/symfony/myproject/apps/myapp/modules/mymodule/templates/
$ vi indexSuccess.php
 hello world!

actions.class.php

$ cd /home/naka/Work/symfony/myproject/apps/myapp/modules/mymodule/actions/
$ vi actions.class.php
<?php
class mymoduleActions extends sfActions
{
  public function executeIndex()
  {
  }
}
?>

# $this->forward() を消す(コメントアウトでもよい)

確認

 http://symfony.example.com/index.php/mymodule

「hello world!」と表示されればOK。

ディレクトリ構造を変更したい場合

そのまま使用することが推奨されているが、変更することは可能。

デフォルト値は、

 /usr/share/pear/data/symfony/config/constants.php

で定義されており、これを変更する場合は、プロジェクト内のconfigで上書きする。

/home/naka/Work/symfony/myproject/apps/myapp/config/config.php

SF_ROOT_DIR は、index.php などのコントローラ内でも定義されているので、
書き換える必要がある。

phpdoc

モジュールは必ず phpdocに合わせた形で生成する。これにより、自動的にドキュメントが生成されるようになる。

フロントコントローラ、モジュール、アクション、ビュー

http://symfony.example.com/index.php/mymodule/myaction

フロントコントローラ「index.php」は、モジュール「mymodule」と「myaction」を受け取り、適切な処理を実行する。

INFO_PATH?指定方法は「ルーティング」と呼ばれる。詳細はここ

モジュールの作成

これは、hello world のところで書いた通り。別のモジュールを作成したい場合は、

$ cd /home/naka/Work/symfony/myproject
$ symfony init-module myapp mymodule2

アクションの作成

1つのファイルに複数のアクションを定義する場合の命名規則

// mymodule/actions/action.class.php
class mymoduleActions extends sfActions
{
  public function executeIndex()
  {
  }
  public function executeRegister()
  {
  }
}

アクションごとにクラスファイルを作成する場合の命名規則

// mymodule/actions/indexAction.class.php
class indexAction extends sfActions
{
  public function execute()
  {
  }
}

各々の処理の実行「前」に、共通の処理を実行する場合

以下のメソッドを入れておく。

public preExecute()
{
}

各々の処理の実行後に、共通の処理を実行する場合

以下のメソッドを入れておく。

public postExecute()
{
}

リダイレクトとフォワード

// リダイレクト
$this->redirect('/mymodule2/index');
$this->redirect('http://www.example.com/');
// フォワード
$this->forward('mymodule2', 'index');

ページ内へ値を出力する

$this は、現在のページオブジェクト?を意味すると考える。

たとえば、

$this->setVar('str', 'hello world'); // または
$this->str = 'hello world';

とすると、ビューの中に、

<?php echo $str ?>

と書かれていれば、そこに埋め込まれる。

アクションの結果からビューを決定する

実行されるメソッドからの戻り値で、対応するビューが決定される。

  • 成功
    return sfView::SUCCESS;
  • エラー
    return sfView::ERROR;
  • 特定のビューへ
    return 'MyResult';
  • ビューは無い。(どんなレスポンスになる?)
    return sfView::NONE;
  • ヘッダだけを返す
    return sfView::HEADER_ONLY;
  • ビューは無いが、変数を返す。
    return sfView::RENDER_VAR;

アクションクラス内のexecute以外のメソッド

共通コードは、まとめる。

protected function hoge()
 {
 }

ビューの作成

view.yml

このファイルは、レイアウトファイルに埋め込まれるパラメータ定義を記述する(METAタグやタイトルなど)。

apps/shop/config/view.yml ここにある。

apps/shop/modules/main/config/view.yml に書くと、モジュール main の設定が上書きされる。

layout.php

/home/naka/Work/symfony/demosite/apps/shop/templates/layout.php これがデフォルトのレイアウト。

これが全ての画面のベースとして使用される。アクションからの出力は、

<?php echo $sf_data->getRaw('sf_content') ?>

こんな風にしてページ内に埋め込まれる。

アクションクラスの中で、

$this->setLayout("hoge");

とすると、hoge.php がレイアウトとして使用される。

<?php echo $sf_data->getRaw('sf_content') ?>

このようにしてページ内に出力される。

レイアウトを全く使用しない場合は、

textplain: none

または

$this->setLayout(false);

とする。

設定ファイル

環境ごとに設定を変える(settings.yml)

まず、設定のデフォルト値として、

/usr/share/pear/data/symfony/config/settings.yml このファイルが使用される。

製品、開発、テスト、カスタム、全て、において、設定を変える場合には、以下のようにする。

/home/naka/Work/symfony/demosite/shop/config/settings.yml を修正する。

# 製品
prod:
# 開発
dev:
# テスト
test:
# カスタム
hoge:
# 全てに共通
all:

設定されている値は、SfConfigクラスで管理されている。
これは、アクションのメソッド内に以下のように書くことで確認できる。

$config = sfConfig::getAll();
while(list($key, $val) = each($config)){
  echo $key . " => " . $val . "<br>";
}
return sfView::NONE;

SfConfigクラスにコード内からアクセスすることで、設定値を操作できる。

sfConfig::set('key', $val);
$param = sfConfig::get('key');

パラメータ名は、以下の規則で決められている。

  • sf_ (apps/shop/config/settings.yml)(アプリケーションの環境に関する設定)
  • app_ (apps/shop/config/app.yml)(アプリケーション固有の設定)
  • mod_(module名)_ (apps/shop/modules/main/config/module.yml)(モジュールごとの設定)

上に示したファイルパスはユーザが設定する場合のパス名であり、
デフォルト値は、/usr/share/pear/data/symfony/config/ の下にある。

以下に設定ファイルの例を示す。

# app.yml
all:
  a:
    b: 123

この場合、以下のように取得できる。

echo sfConfig::get('app_a_b');

しかし、次のように書かれている場合、

# app.yml

all:

 a:
   b:
     c:
       d:
         e: hoge
 echo sfConfig::get('app_a_b_c_d_e'); //  ×

これでは取得できない。階層は b までで、それ以下は配列として格納される。以下のようにすると「hoge」が取得できる。

$conf = sfConfig::get('app_a_b');

foreach ($conf as $c){
  foreach ($c as $d){
    foreach ($d as $e){
      echo $e;
    }
  }
}

yml ファイルは、PHPとしてパースされるので、PHPのコードとして記述することもできる。

<?php
return array(
'all' => array(
  'a' => array(
    'b' => array(
      'c' => array(
        'd' => array(
          'e' => 'hoge'
          )
        )
      )
    )
  )
);
?>

これは、以下の設定ファイルと同じである。

all:

 a:
   b:
     c:
       d:
         e: hoge

自動的に読み込んで定義するクラスを配置するパス(autoload.yml)

autoload.yml に書かれたパスにあるクラスファイルは自動的に読み込まれる。
このファイルは、/usr/share/pear/data/symfony/config/autoload.yml にある。

ユーザが独自に定義するクラスは以下のディレクトリに配置しておく。

  • demosite/lib/
  • demosite/lib/model
  • demosite/apps/shop/lib/
  • demosite/apps/shop/modules/main/lib

php.ini の上書きとチェック(php.yml)

php.ini の設定を上書きすることができる。

/usr/share/pear/data/symfony/config/php.yml

set:
  hoge : off
check:
  foo : off

set のところに書かれた「hoge」は上書きされる。

check のところに書かれた「foo」は、off でない場合は、例外が発生する。

モジュールの設定(module.yml)

/home/naka/Work/symfony/demosite/apps/shop/modules/main/config に置く。

アクセス制限の設定(security.yml)

/home/naka/Work/symfony/demosite/apps/shop/config/security.yml に置く。

以下のような感じで記述する。詳細は「アクセス制御」のところで。

upload:
  is_secure:   on
  credentials: member

生成モジュールの設定(generator.yml)

入力値のバリデーション(validate.yml)

「バリデーション」のところで説明。

http://develop.ddo.jp/symfony/book/jp/1.0/configuration_practice.html#validate に書かれている内容と、試した内容が違うので、要確認。

ビューの設定(view.yml)

「ビューの作成」のところで説明済み。

ファイル構造の設定(config.php)

// symfony directories
$sf_symfony_lib_dir  = '/usr/share/pear/symfony';
$sf_symfony_data_dir = '/usr/share/pear/data/symfony';

プロジェクトを別の環境でも使用する可能性がある場合は、ここを書き換える必要がある。

なお、この設定は、/usr/share/pear/data/symfony/config/constants.php での設定内容を上書きする。

ヘルパー

  • url_for()
  • link_to()
  • link_to(image_tab('hoge'), 'main/index?hoge=aaa')
  • link_to('hoge', '@hoge') (routing.yml 内にルール hoge がある場合)
  • link_to('hoge', 'main/index?hoge=aaa', 'post=true') (POSTで送信するフォーム形式でレンダリングされる)
  • link_to(image_tab('hoge'),'main/index?hoge=aaa', 'confirm=OK?')
  • link_to(image_tab('hoge'),'main/index?hoge=aaa', 'popup=true')
  • link_to(image_tab('hoge'),'main/index?hoge=aaa', Array('popup' => Array(.....))) (ウィンドウを開く)
  • link_to(image_tab('hoge'),'main/index', Array('query_string' => 'hoge=aaa')) (PATH_INFOでなくQueryStringを使う)
  • button_to(image_tab('hoge'), 'main/index?hoge=aaa')
  • image_tag('hoge.png', Array('size' => '200x100'))
  • javascript_include_tag('hoge') (/js/ パスと 拡張子は省略できる)
  • 'absotule=true' (絶対パスで出力する)

認証とセッション管理

actionクラス内からの $this->getUser()

var_dump($user);

とすると、object(myUser)#16 (8) { ... と表示される。

myUserクラスは /usr/naka/Work/symfony/demosite/apps/shop/lib/の下に配置されており、以下のような継承となっている。

myUser ← myBasicSecurityUser ← sfUser + sfSecurityUserインタフェース

myUserクラスで使用できるメソッドは以下の通り。

// sfBasicSecurityUserクラス
public function clearCredentials()
public function listCredentials()
public function removeCredential($credential)
public function addCredential($credential)
public function addCredentials()
public function hasCredential($credentials, $useAnd = true)
public function isAuthenticated()
public function setAuthenticated($authenticated)
public function setTimedOut()
public function isTimedOut()
public function getLastRequestTime()
public function initialize($context, $parameters = null)
public function shutdown()
// sfUserクラス
public function getContext()
public function setCulture($culture)
public function getCulture()
public function getParameterHolder()
public function getAttributeHolder()
public function getAttribute($name, $default = null, $ns = null)
public function hasAttribute($name, $ns = null)
public function setAttribute($name, $value, $ns = null)
public function getParameter($name, $default = null, $ns = null)
public function hasParameter($name, $ns = null)
public function setParameter($name, $value, $ns = null)
public function shutdown()
// sfSecurityUserインタフェース
public function addCredential($credential);
public function clearCredentials();
public function hasCredential($credential);
public function isAuthenticated();
public function removeCredential($credential);
public function setAuthenticated($authenticated);

credentials

意味は、「証明書、証明物」。ロールのようなもの。

使い方は以下の通り。

  • addCredential($c) (credentialを追加)
  • addCredentials($c1, $c2) (credentialを複数追加)
  • hasCredential($c) (credentialを持っているか?)
  • removeCredential($c) (credentialを取り除く)
  • clearCredentials() (すべてのcredentialを取り除く)

アクセス制限

上記の credential を使う。

モジュールの設定ファイル、/home/naka/Work/symfony/demosite/apps/shop/module/security.yml (デフォルトでは無いので作る)に、例えば以下のように記述する。

Commit:
  is_secure: on
  credentials: admin

すると、Commitメソッドの実行は、credential「admin」を持つユーザしか実行できなくなる。ちなみに、AND, OR も使える。

credentials: [ admin, superuser ]    # AND
credentials: [[ admin, superuser ]]  # OR
credentials: [[ admin, superuser ], owner] # (adnin or superuser) and owner

もし、未認証ユーザがアクセスすると($user->setAuthenticated(true) されていない。isAuthenticated() == false)、demosite/apps/shop/config/settings.yml に指定したモジュール/アクションに飛ばされる。

login_module: main
login_action: index

認証済みであっても、credentialがadminでない場合(hasCredential('admin') == false)は、settings.yml で指定したモジュール/アクションに飛ばされる。

secure_module: main
secure_action: index

セッション変数

sfUserクラスがセッション管理のために使用される。

actionクラス内からは、$this->getUser() で取得できる。

テンプレート内では、$sf_user 変数を使う。

セッション変数は以下のメソッドで設定・取得できる。

  • setAttribute('hoge','aaa')
  • getAttribute('hoge')

セッション変数内には、どのような形式(文字列、配列、連想配列、オブジェクト)でも格納することができる。

その他のセッション変数用メソッドは以下のようなものがある。

  • hasAttribute('hoge'); // hoge があるか?
  • getAttributeHolder()->remove('hoge'); // hogeを取り除く

1リクエスト内で値を受け渡す(forward()とか?)

sfRequestクラス内の、getAttribute(), setAttribute(), などを使う。このクラス内にもパラメータホルダー?がある。

セッションクラスの拡張

セッションクラスは、factories.yml 内の user: のところで定義されている(デフォルトは、class: myUser)
。myUserクラスは、demosite/apps/shop/lib の下に置かれている。デフォルトは、空になっており、これを拡張することができる。

全く別のクラスを使用したい場合には、factories.yml の user: のところを変更する必要がある。

セッションのタイムアウト

demosite/apps/shop/config/settings.yml で以下のように記述する。(数値は秒)

default:
  .settings:
    timeout:     1800

セッション管理機構

PHPのセッション管理機能をそのまま使用している(当然か)。

/usr/share/pear/data/symfony/config/php.yml で、session.auto_start を off に設定している。

セッションIDの再発行

Symfonyでは、ログインに成功したタイミングでセッションIDが再発行されない。
再発行するには、通常のPHPのアプリケーションと同じように、以下のようにする。

session_regenerate_id();

session.auto_start

php.ini や /usr/share/pear/data/symfony/config/php.yml(こっちが優先)に、session_auto_start の設定がある。デフォルトでは off となっているが、myUserクラスを取得した段階で、セッションが開始されるので、auto_startしているのと、それほど違いはないのかもしれない。

セッション管理は、デフォルトでは、/usr/share/pear/symfony/storage/sfSessionStorage.class.php が使われる。これは、/usr/share/pear/data/symfony/config/factories.yml で、定義されている。

$this->getUse()したとき、sfBasicSecurityUserクラスがイニシャライズされ、そこに、

$storage = $this->getContext()->getStorage();

というコードがある。ここで、新規にstorageが生成される場合は、セッションIDが発行される
sfSessionStorageクラスについて、まだコードが読みきれていないので、ここまで。

プラグイン

ショッピングカート

symfony book 記載の方法ではうまくいかなかったが、↓こんな感じでうまくいった。

プロジェクトのルートディレクトリで実行する。

$ symfony plugin-install http://plugins.symfony-project.com/sfShoppingCartPlugin

すると、

demosite/plugins/sfShoppingCartPlugin

が生成される。

開発手順

準備

プロジェクトとアプリケーションを作成しておく。

$ symfony init-project demosite
$ symfony init-app shop

データベースまわり

DBを作る

とりあえず PostgreSQL で、demodb というDBを作成。ID/PWは、postgres, postgres。

postgresのパスワードは以下のようにして変更。

myproject=# alter user postgres with password 'postgres';

セキュリティの観点からの考察は置いといて、とりあえず以下のように設定。

/var/lib/pgsql/data/postgresql.conf で、

listten_addresses = 'localhost'
port = 5432

/var/lib/pgsql/data/pg_hba.conf で、

#  host all all 127.0.0.1/32 ident sameuser
#  host all all ::1/128 ident sameuser
host all all 127.0.0.1/32 password

(identによる認証をコメントアウトして、パスワード認証を追加)

synfonyからDBを使えるようにする (database.xml、proepl.ini)

/home/naka/Work/symfony/demosite/config/database.yml

ここに以下のように書く。(demodb は、作成したDB名)

all:
  propel:
    class: sfPropelDatabase
    param:
      phptype: pgsql
      host: localhost
      database: demodb
      username: postgres
      password: postgres
/home/naka/Work/symfony/demosite/config/propel.ini

デフォルトでは

propel.database            = mysql
propel.database.createUrl  = mysql://localhost/
propel.database.url        = mysql://localhost/demodb

と書かれている部分を、以下のように書き換える。(demodb は、作成したDB名)

propel.database            = pgsql
propel.database.createUrl  = pgsql://postgres:postgres@localhost/
propel.database.url        = pgsql://postgres:postgres@localhost/demodb

あと、以下の1行も追加。

propel.disableIdentifierQuoting=true

synfonyにテーブル情報を教える(schema.xml)

まず、

$ symfony propel-build-schema

これにより、 /home/naka/Work/symfony/demosite/config/schema.yml の雛型が生成される。このファイルを以下のように書く。

---
propel:
  users:
    _attributes:
    loginid:
      type: longvarchar
      required: true
    passwd:
      type: longvarchar
      required: true

「type」に指定するのは一般的な型であり、以下のコマンドを実行すると、自動的に変換される。

このように書いたら、

$ symfony propel-build-sql

これで、/home/naka/Work/symfony/demosite/data/sql/ の下に、SQL文が生成される。

これを実行する。

$ symfony propel-insert-sql

DROP&CREATEしようとするので、最初の実行時はエラーが出る。2度目からは出なくなる。

モデルを作成する

以下のコマンドをたたく。

$ symfony propel-build-model

すると、/home/naka/Work/symfony/demosite/lib の下にファイルが生成される。

[naka@fc7 lib]$ ls -lR
.:
合計 4
drwxr-xr-x 4 naka naka 4096 2007-08-10 23:58 model/
./model:
合計 16
-rw-r--r-- 1 naka naka  141 2007-08-10 23:58 Users.php
-rw-r--r-- 1 naka naka  167 2007-08-10 23:58 UsersPeer.php
drwxr-xr-x 2 naka naka 4096 2007-08-10 23:58 map/
drwxr-xr-x 2 naka naka 4096 2007-08-10 23:58 om/
./model/map:
合計 4
-rw-r--r-- 1 naka naka 752 2007-08-10 23:58 UsersMapBuilder.php
./model/om:
合計 20
-rw-r--r-- 1 naka naka 6305 2007-08-10 23:58 BaseUsers.php
-rw-r--r-- 1 naka naka 8843 2007-08-10 23:58 BaseUsersPeer.php

作成するテーブル1つにつき、phpファイルが5個生成される。らしい。
この例では、テーブル「users」を作ったが、BaseUsers,php、BaseUsersPeer.php、Users.php、UsersPeer.php、UsersMapBuilder.php が生成された。

BaseUsers.php は、テーブル「users」のカラム名と同じ名前のパラメータとそのパラメータへのアクセサメソッドを持つクラスである。

BaseUsersPeer.php は、目的とするデータを抽出するためのメソッドを持つクラスである。

Users.php と UsersPeer.php は、それぞれ、BaseUsers.php と BaseUsersPeer.php のクラスを継承したクラスを定義しており、メソッドなどを追加する場合は、こっちのファイルを書き換える。schema.yml を書き換えてから、 symfony propel-build-model を実行すると、Base系は上書きされるが、それを継承したクラスは上書きされずに残る。

UsersMapBuilder.phpは、ランタイム用にデータベースモデルを構築するためのクラスファイルである。

(参考:http://codezine.jp/a/article/aid/837.aspx?p=2

バリデーション

/home/naka/Work/symfony/demosite/apps/shop/modules/main/validate/login.yml を以下のように作成する。(動作する例なので、チェック内容に意味はない)

fields:
  loginid:
    required: Yes
      msg: id is required.
    sfStringValidator:
      min: 2
      min_error: IDは2文字以上です
      max: 10
      max_error: IDは10文字以下です

ここでは、「sfStringValidator」を使用しているが、バリデーションの種類には以下のものがある。

  • sfCallbackValidator
  • sfCompareValidator
  • sfDataValidator
  • sfEmailValidator
  • sfFileValidator
  • sfHtmloValidator
  • sfNumberValidator
  • sfRegexValidator
  • sfStringValidator
  • sfUrlValidator

メモ(未分類)

propelってなに?

ORマッパーのひとつ。 (http://symfony.jp/index.php?propel

デバッグモード

index.php の中で、define('SF_ENVIRONMENT', 'dev'); とする。

アプリケーション名を指定しない状態で、PATH_INFOを取れる?

とりあえず、こんな感じで、ごまかしてる。httpd.conf 内での、mod_rewriteの設定。

RewriteEngine on
RewriteCond %{REQUEST_URI} !^/css/
RewriteCond %{REQUEST_URI} !^/js/
RewriteCond %{REQUEST_URI} !^/images/
RewriteCond %{REQUEST_URI} !^/sf/
RewriteCond %{REQUEST_URI} !^/ejrparts/ [OR]
RewriteCond %{REQUEST_URI} ^/main/
RewriteRule ^/(.+)$ /index.php/$1

DocumentRoot に指定した、/home/naka/Work/symfony/demosite/web 直下に、.htaccess があり、適切な Rewriteルールが書かれていた。これが動作しなかったのは、httpd.conf で、全体のAllowOverride が None となっていたため。上記のルールを消して、AllowOverride All として再起動したら、.htaccessが機能して、期待通りの動作をするようになった。

アクションクラスのメソッド内で取得可能なフレームワークのコアオブジェクト。

$request     = $this->getRequest();
$userSession = $this->getUser();
$response    = $this->getResponse();
$controller  = $this->getController();
$context     = $this->getContext();

アクションから直接コンテンツを出力する

echo "<html>hoge</html>";
return sfView::NONE;

または

return $this->renderText("<html>hoge</html>");

X-JSONヘッダでJSONを返す

$output = '<"name","hoge"],["addr","tokyo">';
$this->getResponse()->setHttpHeader("X-JSON", '('.$output.')');
return sfView::HEADER_ONLY;

ビューを指定する

特定のテンプレートを指定したい場合は以下のようにする。

$this->setTemplate('menu');
return sfView::SUCCESS;

とすると、menuSuccess.php が使用される。

return sfView::ERROR;

としてreturnすると、 menuError.php が使用される。

404へリダイレクト

$this->forward404();

エラーページは、/home/naka/Work/symfony/demosite/apps/shop/config/setting.yml で、

error_404_module error
error_404_action error404

と書いておくと、errorモジュールのerror404メソッドが呼ばれる。
このモジュールは、同じアプリケーション(この例では、shop)の下に作成しておく。

条件付きフォワード/リダイレクト

  • forwardIf()
  • forwardUndless()
  • forward404If()
  • forward404Unless()
  • redirectIf()
  • redirectUnless()

$this はどのオブジェクトを指している??

  1. アクションクラス内
    sfActions (action/sfActions.class.php)
  2. テンプレート内
    sfPHPview (view/sfPHPview.class.php)。※これを直接使うことはほとんどない?

アクションクラス内で、リクエスト関連のパラメータにアクセスする

アクションクラスの $this は、

自作アクション ← sfActions  ← sfAction ← sfComponent

というようにクラスを継承している。以下に示す getRequest()メソッドは、sfComponentクラス内で定義されている。

$req = $this->getRequest();
echo $req->getMethod() . "<br>"; //  sfRequest::GETもしくはsfRequest::POST
echo $req->getMethodName() . "<br>"; // メソッド名)(GET/POSTなど)
echo $req->getHttpHeader('Host') . "<br>"; // リクエストヘッダ
echo $req->getCookie('symfony') . "<br>"; // Cookie
echo $req->isXmlHttpRequest(); // Ajaxか
echo $req->isSecure() . "<br>"; // SSLか
echo $req->hasParameter('hoge') . "<br>"; // 指定したパラメータがあるか
echo $req->getParameter('hoge') . "<br>"; // パラメータ取得
echo $req->getParameterHolder()->getAll() . "<br>"; // 全パラメータ(Array)
echo $req->getUri(). "<br>"; // REQUEST_URI
echo $req->getPathInfo() . "<br>"; //PATH_INFO
echo $req->getReferer() . "<br>"; // リファラー
echo $req->getHost() . "<br>"; // Host
echo $req->getScriptName() . "<br>"; // フロントコントローラ
echo $req->getLanguage() . "<br>"; // array
echo $req->getCharsets() . "<br>"; //array
echo $req->getAcceptableContentType() . "<br>"; // array
return sfView::NONE;

その他のメソッドは、sfWebRequest.class.php を参照。

$ grep "function get" /usr/share/pear/symfony/request/sfWebRequest.class.php

テンプレート内で利用できる変数

/usr/share/pear/symfony/view/sfPHPView.class.php 内で、

$context = $this->getContext();
$shortcuts = array(
  'sf_context' => $context,
  'sf_params'  => $context->getRequest()->getParameterHolder(),
  'sf_request' => $context->getRequest(),
  'sf_user'    => $context->getUser(),
  'sf_view'    => $this,
);

こんな風に書いてある。テンプレート内では以下の変数を使用する。

$sf_context

 <?php echo $sf_context->getActionName() ?>

/usr/share/pear/symfony/util/sfContextg.class.php で定義されている。

$sf_params

 <?php echo $sf_params->getDefaultNamespace() ?>

/usr/share/pear/symfony/util/sfParameterHolder.class.php で定義されている。

$sf_request

 <?php echo $sf_request->getMethod() ?>

/usr/share/pear/symfony/request/sfRequest.class.php で定義されている。

$sf_user

<?php echo $sf_user->getCulture() ?>

/usr/share/pear/symfony/user/sfUser.class.php で定義されている。

$sf_view

<?php echo $sf_view->getExtension() ?>

/usr/share/pear/symfony/view/sfView.class.php で定義されている。

$sf_data

 <?php echo $sf_data->getRaw('sf_content') ?>

$sf_data は、sfOutputEscaperArrayDecorator クラスのインスタンスである。

これは、以下のようにすると分かる。

var_dump($sf_data instanceof sfOutputEscaperArrayDecorator