カテゴリー : Symfony

[Symfony2] DB の Master/Slave(マスタースレーブ)構成について

Symfony2 での DB の Master/Slave 構成について調べたのでメモ。

symfony1系には sfDoctrineMasterSlavePlugin があるのですが、Symfony2でも同じようなものがないかなと思っていたら、ありました。

Doctrine の DBAL2.16 から実装された MasterSlaveConnection を使えばできるみたいです。

lib/Doctrine/DBAL/Connections/MasterSlaveConnection.php at master from doctrine/dbal – GitHub はてなブックマーク - lib/Doctrine/DBAL/Connections/MasterSlaveConnection.php at master from doctrine/dbal - GitHub
 

DBAL2.16 以上が使えないようでしたら、下記記事を参考に「データベース接続ごとのEntityManagerを明示的に切り替えるような方法」で対応するしかなさそうです。

Symfony2を利用してのDBのMaster/Slave構成について – Google グループ はてなブックマーク - Symfony2を利用してのDBのMaster/Slave構成について - Google グループ

複数のエンティティマネージャと連携する方法 | Symfony2日本語ドキュメント はてなブックマーク - 複数のエンティティマネージャと連携する方法 | Symfony2日本語ドキュメント

以上です。

PHPFog + Symfony2 でステージング環境を作る方法:Symfony Advent Calender 2011 JP – 13日目 –

こんにちは!「Symfony Advent Calendar JP 2011」 13日目です。

昨日の @77webさんからバトンタッチで、今日は「PHPFog + Symfony2 でステージング環境を作る方法」をご紹介します。

続きを読む

[Doctrine] SQLを直接実行する方法 [Symfony1.4]

Symfony1.4にて、SQLを直接実行する方法を調べたのでメモ。

以下の記事を参考にしました。

・参考:DoctrineでSQLを直接実行する – ゆっくり*ゆっくり

以上です。

[Doctrine] サブクエリ(副問合せ)を使う方法 [Symfony1.4]

Symfony1.4にて、Doctrineでサブクエリ(副問合せ)を使う方法を調べたのでメモ。

Doctrineでサブクエリを使う : アシアルブログ

The symfony Cookbook | データをDoctrineで読み取る | symfony | Web PHP Framework

なるほど、createSubquery()を使えばいいんですね。

MySQLのサブクエリについてはこちら。

MySQL :: MySQL 5.1 リファレンスマニュアル :: 12.2.8 サブクエリ構文

以上です。

[Symfony1.4] 認証(authentication)と承認(authorization)のチェックは security.yml で設定する

Symfony1.4にて、ログイン認証していないユーザは特定のアクションを実行できないような処理をするのに、preExecute に認証チェックをしていました。

認証チェックが必要なモジュールのアクションファイルに全てに下記のような preExecute メソッドを記述していたのですが、認証・承認の処理はsecurity.ymlで設定を変更すれば一括でできるみたいです…。

/**
 * アクション実行前にログイン認証が通っているか確認
 * 認証が通っていない場合、ログインページにリダイレクト
 **/
public function preExecute() {
	if (!$this->getUser()->isAuthenticated()) {
		$this->redirect('@user_login');
	}
}

認証・承認の処理の設定ですが以下のように、security.yml を変更します。

■ /project/apps/frontend/config/security.yml

# You can find more information about this file on the symfony website:
# http://www.symfony-project.org/reference/1_4/en/08-Security
 
#default:
#  is_secure: false

all:
  is_secure:   true
  credentials: login

security.yml を修正後、忘れずに symfony cc します。

これでウェブサイトにアクセスすると認証していない場合、ログイン処理のページにリダイレクトされます。

ログイン処理に対応するモジュールとアクションを settings.yml に書いていない場合、デフォルトが ‘action’ => ‘login’, ‘module’ => ‘default’ となっているみたいで500エラーが返ってきました。

500 | Internal Server Error | sfConfigurationException
Unable to find a matching route to generate url for params “array ( ‘action’ => ‘login’, ‘module’ => ‘default’,)”.

ログイン処理に対応するモジュール、アクションの設定は以下のように書きます。

(この場合、UserLoginモジュールのLoginアクションにログイン処理をさせています。)

■ /project/apps/frontend/config/settings.yml (一部のみ抜粋)

all:
  .actions:
    login_module:  UserLogin
    login_action:   Login

これで認証前にログインページ以外のページにアクセスしても、ログイン処理の画面が表示されるようになりました。

ログイン処理はこれで大丈夫なのですが、これでは新規ユーザ登録のページにアクセスした場合にもログイン処理のページが表示されてしまいます。

これは使えないので、新規ユーザ登録の処理をしているモジュールの認証チェックを外してやります。

モジュール以下のディレクトリに新たに /config/security.yml を作成します。

■ /project/apps/frontend/modules/UserRegister/config/security.yml

all:
  is_secure:   false

また、モジュール内の特定のアクションに対して認証チェックをする、しないという切り分けを設定することもできます。

例えば、NewアクションとCompleteアクションは認証チェックをしないで、Confirmアクションには認証チェックをするという場合は以下のように書きます。

new:
  is_secure:   false
confirm:
  is_secure:   true
complete:
  is_secure:   false

security.yml 、settings.yml を編集後は、symfony cc をするのをお忘れなく。
 

以上です。
 

【参考】

The symfony Reference Book | security.yml 設定ファイル | symfony | Web PHP Framework

security.yml 設定ファイル | 日本Symfonyユーザー会

settings.yml 設定ファイル | 日本Symfonyユーザー会

symfony book 日本語ドキュメント ユーザー証明の管理方法

[Symfony1.4] PostValidatorで個別のフィールドにバリデーションエラーを設定する方法

Symfony1.4にて、PostValidatorで個別のフィールドにバリデーションエラーを設定する方法を調べたのでメモ。

・参考:postValidatorから個別のフィールドにエラーを設定 – ゆっくり*ゆっくり はてなブックマーク - postValidatorから個別のフィールドにエラーを設定 - ゆっくり*ゆっくり

最初は、単純に sfValidatorError を使って、バリデーションエラーメッセージを表示させていたのですが、この書き方だとGlobalErrorになります。

// ログインIDの重複チェックをするバリデータ
class ValidatorSameLoginId extends sfValidatorBase{
	protected function doClean($value){
		// DBから同じログインIDのレコードを取得
		$user = UserTable::getInstance()->getOneByLoginId($value['login_id']);
		// 同じログインIDのレコードが既に存在する場合、バリデーションエラー
		if($user != false){
			throw new sfValidatorError($this, '同じログインIDが既に登録されています', array('value' => $value));
		}
		return $value;
	}
}

これを単一のフィールドに対するエラーであるNamedErrorにするには、

if($user != false){
	throw new sfValidatorError($this, '同じログインIDが既に登録されています', array('value' => $value));
}

の部分を、sfValidatorErrorSchema を使って以下のように書き換えると、個別のフィールドにバリデーションエラーを表示させることができます。

symfony API » sfValidatorErrorSchema Class | symfony | Web PHP Framework はてなブックマーク - symfony API » sfValidatorErrorSchema Class | symfony | Web PHP Framework

class ValidatorSameLoginId extends sfValidatorBase{
	protected function doClean($value){
		// DBから同じログインIDのレコードを取得
		$user = UserTable::getInstance()->getOneByLoginId($value['login_id']);
		// 同じログインIDのレコードが既に存在する場合、バリデーションエラー
		if($user != false){
			throw new sfValidatorErrorSchema($this, array(
				'login_id' => new sfValidatorError($this, '同じログインIDが既に登録されています'),
			));
		}
		return $value;
	}
}

以上です。

[Symfony1.4] メール配信処理の実装

Symfony1.4にて、メール配信処理を実装しました。

参考にした公式サイトのリンクをメモ。

Practical symfony | 16日目: メーラー | symfony | Web PHP Framework

The More with symfony book | メール | symfony | Web PHP Framework

A Gentle Introduction to symfony | 第11章 – Eメール | symfony | Web PHP Framework

実用的な「クラスとしてメールメッセージを使う」を特に参考にしました。

クラスとしてメールメッセージを使う | A Gentle Introduction to symfony | 第11章 – Eメール | symfony | Web PHP Framework

以上です。

[Symfony1.4] 同じテーブルのカラムへの複数リレーションを持たせる方法

Symfony1.4にて、schema.yml を作成しているときに、同じテーブルのカラムへの複数リレーションを持たせるのに苦労したのでメモ。

本の情報を登録したユーザと変更したユーザの情報を持つために、registry_user_id と edit_user_id というレコードを Book テーブルに持たせています。

それぞれ、User テーブルのid とリレーションを持たせたいのですが、下記のように書くと、後ろの edit_user_id しかリレーションを持てません。

Book:
  actAs:
    Timestampable: ~
    Sluggable: ~
  columns:
    .
    .
    registry_user_id:
      type:             integer
      notnull:          true
    edit_user_id:
      type:             integer
    .
    .
  relations:
    User:
      onDelete:         CASCADE
      local:            registry_user_id
      type:             one
      alias:            RegistryUser
      foreign:          id
      foreignType:      one
    User:
      onDelete:         CASCADE
      local:            edit_user_id
      type:             one
      alias:            EditUser
      foreign:          id
      foreignType:      one

これを下記のように、クラス名を直接指定するのではなく、それぞれに名前を持たせて class: User と指定すればOKです。

    RegistryUser:
      onDelete:         CASCADE
      class:            User
      local:            registry_user_id
      type:             one
      foreign:          id
      foreignType:      one
    EditUser:
      onDelete:         CASCADE
      class:            User
      local:            edit_user_id
      type:             one
      foreign:          id
      foreignType:      one

以上です。

[Symfony1.4] テンプレートの変更:setTemplate

Symfony1.4にて、テンプレートの変更について調べたのでメモ。テンプレートの変更には、setTemplateメソッドを使います。

■ テンプレートファイルのパスを直接指定する方法

$this->setTemplate('テンプレートファイルの絶対パス、または、相対パス');

■ アクションに対応するテンプレートを指定する方法

$this->setTemplate('Edit');

この場合、Editアクションに対応するテンプレートを呼び出しています。

■ return sfView::SUCCESS

アクションの処理が全て終わったら、何も書かれていない場合、sfView::SUCCESS がreturnされる。

他にも、sfView::NONE, sfView::ERROR などがある。

■ テンプレートについて調べるときに読む記事。

(公式)

A Gentle Introduction to symfony | 第6章 – コントローラーレイヤーの内側 | symfony | Web PHP Framework

Practical symfony | 14日目: フィード | symfony | Web PHP Framework
 

(ブログ記事など)

例外発生時のテンプレートの変更 – ゆっくり*ゆっくり

symfonyでsymfuldaze

WEBアプリケーション研究室 開発ノート [symfony] 特定のテンプレートを強制的に表示
 

[エラー] Invalid row key specified: ~ , referred to in ~

Symfony1.4にて、フィクスチャーファイルからデータベースにデータを入れようとしたらエラー。

# php symfony doctrine:data-load

■ エラー内容

Invalid row key specified: (user) , referred to in (rental) Rental_4

MySQLの外部キー制約のため、関連付けのある部分に値がを入れておらず、エラーになっていました。

mysql> show create table rental;
+--------+--| Table  | Create Table
---------------------------------------+
| rental | CREATE TABLE `rental` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `user_id` bigint(20) DEFAULT NULL,
  `rented_at` datetime DEFAULT NULL,
  `returned_at` datetime DEFAULT NULL,
  `delete_flag` tinyint(1) NOT NULL DEFAULT '0',
  `created_at` datetime NOT NULL,
  `updated_at` datetime NOT NULL,
  `slug` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `rental_sluggable_idx` (`slug`),
  KEY `user_id_idx` (`user_id`),
  CONSTRAINT `rental_user_id_user_id` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci |
+--------+----------------------------+

ここの設定のせいで、外部キーがあるカラムをNULLにできませんでした。

CONSTRAINT `rental_user_id_user_id` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE CASCADE

■ 解決方法

MySQLにログインして、下記のコマンドで外部キーを削除します。

・参考:MySQL :: MySQL 5.1 リファレンスマニュアル (オンラインヘルプ) :: 9.4.4 FOREIGN KEY 制約

ALTER TABLE tbl_name DROP FOREIGN KEY fk_symbol;

あと、関連付けのあるカラムのfixtureファイルの書き方なんですが、以下のように書いてはいけません。

Rental:
  Rental_1:
    User:               [User_1]
    rented_at:          '2011-01-01'
    returned_at:
    delete_flag:        0
  Rental_2:
    User:
    rented_at:
    returned_at:
    delete_flag:        0

Rental_2 の User: のように書くと、Userに対応するオブジェクトを探しに行って、なくてエラーになるそうです。

代わりに、User: の部分を user_id: と書けばOKです。もしくは、値を入れないので user_id: そのものを書かないという選択肢もあります。

以上です。