WEBアプリケーション研究室 開発ノート TOP

WEBアプリケーション研究室 開発ノート 2009年01月

スポンサーサイト

-------- --:--

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

    このエントリーをはてなブックマークに追加

actionで設定した変数をlayout.phpで使用することは出来ません。
使用するにはスロットを使います。
もともとは例えばサイドバーの内容をaction毎に切り替えたりする場合に使います。
まずlayout.phpに


<?php if (has_slot('slot')): ?>
<?php include_slot('slot') ?>
<?php else: ?>
ここにデフォルトのものを入れる。
actionの変数はここでは使えません。
<?php endif; ?>
そして、この内容を上書きたいactionのテンプレートで

<?php slot('slot') ?>
ここに内容を書く。
ここでは当然actionの変数が使えます。
<?php end_slot() ?>
これでこのaction実行時にはこの内容が表示されます。
layout.phpにデフォルトのスロット(else以下)を設定しなければ、slotが存在しなければ何も出ないので、これを使えばactionの変数をlayout.phpで使えるます。

    このエントリーをはてなブックマークに追加

「action内でforward元のmodule名、action名を取得する」 で書きましたが、もう一つやり方を見つけました。
forwardを繰り返すとContextの中にActionのインスタンスがActionStackとして保存されていきます。


$action =
sfContext::getInstance()
->getActionStack()
->getFirstEntry()
->getActionInstance();

これでインスタンスを取得できます。こっちの方がスマートというか、作成者の意図したやり方っぽいと思います。たぶん。

    このエントリーをはてなブックマークに追加

MySqlでテストしていて気付いたのですが、O/Rマッパーにdoctrineを使用して、スキーマから全てを生成、挿入しなおすコマンド


symfony doctrine-build-all-reload
を実行するとデータベースを一回ドロップして生成しなおします。その際、DEFAULT CHARSETをまったく指定しないでDBを作ってしまうので、MySql側の設定をデフォルトままにしておくとlatin1でCreateしてしまいます。ちょっとコードをたどってみたのですが今のところMySql側の設定をいじれない場合symfony doctrine-build-all-reloadをあきらめるか、手動でALTER DATABASEするしかなさそうな感じです。せめてpropelのsqldb.mapみたいな機能があれば自動でできそうですが。
schema.ymlの全てのテーブルに

User:
options:
charset: utf8
columns:
username: string(255)
password: string(255)
などと設定する手もありますが、DB自体にDEFAULT CHARSETが指定されてないと何かの拍子にlatin1のテーブルを作ってしまう可能性もあるので微妙な気もします。
まあ、開発の初期段階しか使わないコマンドなので特に問題ない気もしますが。

[symfony 1.2.2]

    このエントリーをはてなブックマークに追加

app/config/settings.yml内に


all:
.settings:
escaping_strategy: on
escaping_method: ESC_SPECIALCHARS
と書くと出力する変数を全部エスケープしてくれます。漏れが出ないので、お勧めのやり方です。あるデータだけエスケープしたくない時は

<?php echo $sf_data->getRaw('name') ?>
で出来ますが、foreachで配列をまわして同じテーブルの内容を繰り返し出力するような時、エスケープしたい項目と、したくない項目があり困りました。
下のようにして何とか実現しました。

<?php foreach($sf_data->getRaw('sample_cases') as $key=>$sample): ?>
<?php echo $sample_cases[$key]->getComment()//エスケープするデータ ?>
<?php echo $sample->getComment()//エスケープしないデータ ?>
<?php endforeach ?>


3/19日加筆
getRawValueというメソッドがありました。

<?php foreach($sample_cases as $sample): ?>
<?php echo $sample->getComment()//エスケープするデータ ?>
<?php echo $sample->getRawValue()->getComment()//エスケープしないデータ ?>
<?php endforeach ?>
これだけでOKです。こういうメソッドが無い分けないですよね。失礼しました。

5/19日加筆
当たり前ですがgetRawValueを使うとescaping_strategy: offにしたときにエラーが出ます。
$sf_data->getRaw('sample_cases')だと普通に動きます。offにすることは無さそうだけど、なんか気持ち悪いですね。

[symfony 1.1.6]

    このエントリーをはてなブックマークに追加

↓の場所にクラスを作ったら読み込まれませんでした。


~/lib/sd/model/test.class.php

↓のように変えたら読み込まれたのでmodelがまずいみたいです。

~/lib/sd/db/test.class.php


[symfony 1.1.6]

    このエントリーをはてなブックマークに追加

propelで複数の接続を使うには制約があります。
http://www.symfony-project.org/snippets/snippet/194

symfonyではDBの接続をconfig/databases.ymlに設定します。
ここに複数の設定を書けばプログラムから複数の接続を使えます。


all:
database1:
class: sfPropelDatabase
param:
phptype: mysql
hostspec: localhost
database: mysql_databse
username: my_username

database2:
class: sfPropelDatabase
param:
phptype: sqlite
database: ../data/sqlite_database.db

スキーマはconfigフォルダの*schema.xmlと名前がついたものはすべて読み込まれるので
database1-schema.xml
database2-schema.xml
を作ってそれぞれ頭に接続を指定します。この時モデル(ORMクラス)を作成するパスをpackageで指定すると、管理がしやすくなります。

database1-schema.xml
database1:
_attributes: { package: lib.model.database1}
table1:
id:
.......

database2-schema.xml
database2:
_attributes: { package: lib.model.database2}
table2:
id:
.......

これで
symfony propel-build-model
すれば適正なモデルがそれぞれ
lib/model/database1/
lib/model/database2/
に作成されます。ただ、問題は
symfony propel-build-sql
symfony propel-insert-sql
です。これらのタスクはconfig/propel.iniを見に行きます。接続毎に違うiniファイルを見に行かせることができません。最初の接続のsqlを流し込んだ後、手動でiniファイルを入れ替えて、またsqlを流し込むという作業が必要です。

ちなみにdoctrineを使用すればもっと簡単に複数の接続を使えるようです。公式のチュートリアルでも複数の接続を使う時はdoctrineを使うように進めています。

また、もう一つ問題があります。接続名ですが上記のような設定をしても動きますが、pluginでDBにテーブルを作るようなもの、例えばsfGuardPluginなどは接続名にpropelを使用しています。スキーマファイルを書き換えてやれば動きますが、アップデイトのたびに変えてやらなければならないので、メインのDBの名前はpropelにしておいたほうが無難です。

1.2のdoctrineのマニュアルを読んでいたら次のような記述を見つけました。

Though Propel requires at least one connection named propel, Doctrine does not require that the connection be named doctrine so you can name it whatever you like.
Propelは最低でも一つのpropelという名前の接続が必須でしたが、Doctrineはdoctrineという名前の接続が必須ではありませんので、好きな名前をつけられます。



[symfony 1.1.6]

    このエントリーをはてなブックマークに追加

なかなか時間がなくて試せなかったsymfony1.2系を試してみました。
どうせ試すならdoctrineをと思いやってみたところ


symfony doctrine-build-all

SQLSTATE[HY000] [2002] Can't connect to local MySQL server through socket ''

というエラーが出ました。
PDOになったのでsocketを指定してやらなければいけなくなったのか、それとも、試したサーバーがPHPをソースから入れて、MySqlはパッケージで入れてるからなのか原因はわかりませんが、接続先のunix_socketを指定してやらなければならないようです。PDOのdsnにunix_socketを指定する書き方は

mysql:dbname=name;host=localhost;unix_socket=/var/lib/mysql/mysql.sock

です。これで、うまく接続できました。

[symfony 1.2.2]

    このエントリーをはてなブックマークに追加

admin generatorでコンポーネントを使えます。
コンポーネントはロジックを組み込めるので、自由度が格段にアップします。
ざっと探してみた感じマニュアルにないので、つかっていいのかどうか微妙ですが。
generator.ymlのdisplayに次のように書きます。


generator:
class: sfPropelAdminGenerator
param:
model_class: Job
theme: gomo

edit:
display: [name, name_s, ~test]

パーシャルは_(アンダーバー)ですが~(チルダ)を頭につけます。
ちなみにコンポーネントはモジュールフォルダのactionsに
components.class.php
というクラスを作り、そこにアクションを書きます。

class moduleComponents extends sfComponents
{
public function executeTest()
{

}
}

templatesはパーシャルと一緒で_ではじめます。
_test.php

[symfony 1.1.6]

    このエントリーをはてなブックマークに追加

POSTやGETで渡されたデータをアクションで取得するにはいくつかの方法があります。
どれが何かわからなくなったので整理しておきます。


$this->getRequestParameter($name, $defualt);
$this->getRequest()->getParameter($name, $defualt);
$this->getRequest()->getParameterHolder()->get($name, $defualt);
は同じもので、両方ともPOSTとGETとsymfonyによってURLに埋め込まれた変数をまとめて取得します。
ちなみに一番下の

$this->getRequest()->getParameterHolder()->get($name, $defualt);
が大元で上の二つはこのメソッドを呼び出しています。
URLに埋め込まれた変数とは

http://example.com/module/action/key1/value1/key2/value2
この
key1=value1
key2=value2
で、単独でを取得するには

$this->getRequest()->getUrlParameter($name, $defualt);
を使います。

この他、RequestにはGET、POSTそれぞれ単独で取得するメソッドがあります。

$this->getRequest()->getGetParameter($name, $defualt);
$this->getRequest()->getPostParameter($name, $defualt);
全部まとめて配列でも取れます。

$this->getRequest()->getGetParameters();
$this->getRequest()->getPostParameters();
//全部まとめて取得
$this->getRequest()->getParameterHolder()->getAll();




[symfony 1.1.6]

    このエントリーをはてなブックマークに追加

admin generatorで


edit:
fields:
status: { type: なんとか}

と指定するフォームのタイプはObjectヘルパーが呼び出されて使用されます。
Objectヘルパーはその名のとおりOMクラスのインスタンスが渡されてフォームが生成されるので、データベースに無いような決まった値、例えば状態を0と1であらわしたりするようなカラムをラジオボタンで生成したい時、うまくいきません。つまり、object_radioヘルパーはありません
1.2からはFormクラスベースになったらしいので出来るのかな?まだ、試してないのでなんともいえませんが、1.1系で実現するにはパーシャルフィールドを使えばいけそうです。

edit:
display: [,,,,,, _radio_status]
fields:
radio_status: { name: 状態 }

等と設定してtemplates/_radio_status.phpに

echo radiobutton_tag('job[status]', '0', $job->getStatus() == 0)
echo label_for ('job_status_0', '非表示')
echo radiobutton_tag('job[status]', '1', $job->getStatus() == 1)
echo label_for ('job_status_1', '表示')

これだけだとupdateされません。
dispayに無い項目はupdateのプロセスから外されます。
actionをちょっといじってupdateするように変更します。

class jobActions extends autojobActions
{
protected function updateJobFromRequest()
{
$status = $this->getRequest()->getParameter('job[status]');
if(isset($status))
{
$this->job->setStatus($status);
}
parent::updateJobFromRequest();
}
}


[symfony 1.1.6]

    このエントリーをはてなブックマークに追加

javascriptやstylesheetをview内で読み込むのはヘルパーを使って


use_stylesheet('/path/to/stylesheet')
use_javascript('/path/to/javascript')

と読み込めます。これは、何度呼び出しても一回しか読み込まないので便利です。
ただ、同一モジュールの全てのアクションで同じCSSを読み込みたいときなど、action内にかけたら便利です。actionに書くときは以下のように書きます。

sfContext::getInstance()->getResponse()->addStylesheet('/path/to/stylesheet');
sfContext::getInstance()->getResponse()->addJavascript('/path/to/javascript');


[symfony 1.1.6]

    このエントリーをはてなブックマークに追加
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。