酔っぱらいスクリプターの備忘録。よく消える(意味ねぇ
Archive for 3月, 2010
Name Scopeってしゅごいねー Yii Framework触るぜ日記(10)
3月 30th
「しゅごいねー」は不朽の名作『赤ちゃんと僕』のミノル君からパクりました。
YiiにはName Scopeという便利機能があります。
cakeとかSymfonyにもあるのかな?Railsからパクったらしいです。
例えば
class model
{
public function scopes()
{
return array(
'scope1'=>array(
'condition'=>'status=:status',
'params'=>array(':status'=>'public',
'order'=>'created',
),
'scope2'=>array(
'limit'=>10,
),
);
}
こんな感じで設定しておけば、
$models = $model->scope1()->scope2()->findAll();
上記みたく書いたらscope1の条件とかscope2のlimitが反映されて検索してくれる。
さらに、リレーション時にも使えて
$model->scope1->with('comment:scope3')->findAll();
こんな感じでリレーションcommentで使うmodelにscope3が設定されてると、それが反映されて以下略、みたいな。
このName Scopeの素晴らしさはそれだけではなく、引数も扱えるんですよ。
class model{
function scopeHoge( $category ){
$this->getDbCriteria()->mergeWith(array(
'condition'=>'category='.$category,
));
return $this;
}
これで下記のように書けばcateogryが3のモノを取ってくる。
$model->scopeHoge(3)->findAll();
便利ですよね。
思わずRails先生の方向いて手をあわせました。
でも一個だけ弱点があって。。。
引数を取れる関数バージョン時とリーレションでの適用を同時に使えないんですよ。
$model->scope1()->with('comment:scopeHoge(3)')->findAll();
いや、引数取れないんだしいいじゃん!って話もあるんですけどね。
リレーションで使うName Scopeは素直にscopes関数で設定してあげましょう。
出来れば命名規則(プリフィックスでscopeとか)でもいいから関数対応してほしいナ。
あと、注意点としてwith()の返り値はmodel(CActiveRecode)じゃなくてCActiveFinderという別モノなので、with()からNameScopeにはチェイン出来ません。
かならず『モデル->スコープ->with->find』という流れにするように気を付けましょう(・∀・)コレで10分ハマッタ!
ヨッパゲついでに小話2 Yii Framework触るぜ日記(9)
3月 25th
ビール数杯と焼酎数杯でペロンペロンです。
こんなだと女の子に嫌われるゾ!
だからって酒飲まないのは負けみたいだし強くなろうね(・∀・)
さて、酔いついでに最近貯めていたYii PHP frameworkの小話を保存する。
Model名
Model名はYiiの公式サイトでは頭文字を大文字にする事を推奨ます。
と、あるんですがコレ、推奨じゃなくて必須(?)です。
便利なリレーションのwith()で入れ子にした際に一文字目を大文字で探されます。
$posts=Post::model()->with(
'author.profile',
'author.posts',
'categories')->findAll();
こんな感じでやった際に、author.profileのprofileなんかはProfile.phpで探されます。
(この例だとpostsもPosts.phpで探します)
ワイ、途中で全部大文字にしたがな!
Yii-userエクステンション
Yii-userエクステンション便利そうなんで使ってみました。
その際の注意点を。
まず・・・action名を省略して引数を持ったURLでアクセスするとurlManagerの設定(?)によってはエラーになります。
恐らくpathに設定してたせいですが…。
考えるのも面倒だったので下記の2箇所を修正しました。
これは新規登録時とパスワード忘れた時用のメールに記載されるURLです。
RegistrationController.phpの48行目の’/user/activation’を’/user/activation/activation’に。
RecoveryControllerも変更(確か・・・コレ・・・だったよーな・・・)。
あと、typoとか翻訳ファイル(元にはないけど/messages/jのファイル)に抜けがあるんで気をつけた方がいいです。
modules/user/models/RegistrationForm.php
こちらに、「users’s」ってのがありますが、これはtypoで正解は「user’s」のハズです(翻訳ファイルもそーなってる)。
あとは翻訳ファイルに
‘Manage Profile Field’を追加
‘This users\’s email adress already exists.’を追加
‘Update’を追加
これで使える気がします。
他にもあれば教えて下さい!
俺使ってるんで!
その他
あった気がしたけど・・・アタマが回らないので。
えー、今(2010/03/25)にYii PHP Framework試すならバージョン1.1.0がオススメです。
1.1.1だとbeforeFindがマトモに動かないのでちょっと厳しいかなと思います。
1.1.2で修正予定らしいのでそれが出たらそれで。
そんな感じです。
こーゆー感じなのでグダグダな感じなのでYii Framework触るぜ日記はいつ終わるかわかりません。
だけど、これだけ書いたら今度こそリセットしたくないなーとは思いました!
いつかYiiの情報が日本語で溢れる日を夢見て、今日もあと2,3杯呑んで寝るとします(・∀・)
アクション毎にCSSとかJavaScriptを使う Yii Framework触るぜ日記(8)
3月 25th
愚痴っただけでも何なので。
このページではhoge.cssを使いたい!
とかfoo.jsを読み込みたい!
ってのがあるんですよ。
ね。
そんなときの解決方法。
protected/view/layouts/main.phpを見てみると、な~んも書いてない。
「オレ、ここで指定されたCSSとかJavaScriptはくよ!」
そんな雰囲気がまったくない。
・・・あれ~っと思いつつAPIを見てるとそれらしきもの発見。
CClientScriptがそれです。
CWebApplicationのAPIに【clientScript: manages client scripts (javascripts and CSS).】
と書かれている。
CSSって書かれるし・・・。
ダメ元で試したら、やり方は簡単でした(さすがYii!)。
Controllerの当該actionで下記のように書くだけ。
Yii::app()->getClientScript()->registerCssFile( '/css/hoge.css' );
これで書いたactionの時のみ/css/hoge.cssを読み込みます!
CClientScriptのAPIを見れば他にどんな事ができるか一目瞭然です。
layouts/main.phpには何ら特別な記述されてないのにっ! 不思議!!
ソースを読もうかと思ったけどお酒が回ってるので諦めました。
まとめ
今日のお寿司は美味しかったです(・∀・)ひゃっほーい!
あれ? Yii Framework触るぜ日記(7.5)
3月 24th
日記というかただの愚痴なんで7.5です。
もしくはbug reportingですかね(・∀・)
CActiveRecode.phpのquery()のトコが気になる。
Yii PHP framework 1.1.0
private function query($criteria,$all=false)
{
$this->beforeFind();
$this->applyScopes($criteria);
$command=$this->getCommandBuilder()->createFindCommand($this->getTableSchema(),$criteria);
return $all ? $this->populateRecords($command->queryAll()) : $this->populateRecord($command->queryRow());
}
だったのが
Yii PHP framework 1.1.1
では
private function query($criteria,$all=false)
{
$this->applyScopes($criteria);
if(empty($criteria->with))
{
if(!$all)
$criteria->limit=1;
$this->beforeFind();
$command=$this->getCommandBuilder()->createFindCommand($this->getTableSchema(),$criteria);
return $all ? $this->populateRecords($command->queryAll()) : $this->populateRecord($command->queryRow());
}
else
return $this->with($criteria->with)->query($criteria,$all);
}
何か色々機能が増えてそうだね♪ って話じゃない。
$this->applyScopes($criteria)を呼ぶタイミングが変わってるんですよ。
$this->beforeFind()の前と後に。
でapplyScopes()は何と言うか、CDbCriteria(よーするにSQLクエリー)の情報を混ぜる役目っぽいのですよ。
新しいバージョン(1.1.1)ではbeforeFind()の前に呼ばれている。
これだと…そう、beforeFind()で条件を指定出来なくない!?
って話。
Yii Framework触るぜ日記(4)でやったshimiSoftDeleteが動いてなくて「あれ?俺、試してなかったっけ?」となっていたんですが…バグじゃね?
念の為にyii-1.1.0で試したらちゃんと動くじゃねーか!
仕様変更とも言えるかもしれないけど…検索条件さわれないbeforeFindに何の意味があるんですか(ノд`)俺の数時間返せ…
Yii PHP framework 1.1.2で修正される事を切に願います。
ってか誰か英語出来る人、本家に聞いてみてほしい(´・ω・`)
追記:速攻
issue見たらあった。。。orz
えー…なんなろこのキモチ(´・ω・`)
追記:one more thing!
えーっと、1.1.2が出るまで自力で修正する人は
CActiveRecode::query()の位置を変えるのと、CActiveFinder::query()の方も変更しないとwith()使った際にアレです。
これでさらに30分は使った。。。
urlManager Yii Framework触るぜ日記(7)
3月 18th
URLを変えたかったんです。
前にやった方法だと何だか長ったらしいじゃないですか。
http://shimi-zoo.com/member/view/id/1
上記のようなURLになるのを
http://shimi-zoo.com/member/1
こんな感じでアクセスしたいんです。
方法は簡単でapplication/protected/config/main.phpに設定するだけです。
公式の解説ページはコッチ。
'urlManager'=>array( 'urlFormat'=>'path', 'showScriptName'=>false, 'rules'=>array( 'member/<id:\d+>'=>'member/view', 'member/<id:\d+>/<_a:\w+>'=>'member/<_a>', ), ),
これで$_GET['id']で取得出来るし見た目的にもいい感じかな、と。
6行目の指定で他のactionにも紐付けられる感じです。
URLの生成については
$this->createUrl('view',array('id=>1));
CHtml::link('リンクだよ', array('view','id'=>1) );
CHtml::link('リンクだよ', array('member/view','id'=>1) );
どれでやっても対応した形式のURLにしてくれます。
まぁ、それだけ。忘れる前にメモる!
追記:3/22
urlManagerつながりでココに追記しておく。
urlFormatをpathに設定するときはactionを省略してかつ、引数を持たせるとダメみたいですね。
たとえばbookコントローラーのdefaultアクションにid=5を渡す時。
/book/id/5
みたいなIDになってbookのactionIdを動かそうとするワケです。
普段は気をつければいいレベルだけどモジュールでそういうアクションを指定されてるとアウトですね。。。Yii-userとか。
CakePHP関西workshopの感想(ぐちゃぐちゃ…)
3月 14th
と、いうわけで。
3月13日に開催されたCakePHP関西workshopに参加してきました。
CakePHPの初歩(インストールとか)からプラグイン実装とかまでを実際にコーディングしながらやっていこうという感じです。
「こいつはっ!」と、勇んで参加してきました(・∀・)
workshopでは、MySQLのパスワード忘れてたり、MAMP環境だとCakeのdb設定でportにsocketを指定しないとbakeがエラーになるとかで午前中はほとんど追えずに格闘してました。。。
ちなみにMAMPでbake時にmysqlに接続できない場合の対処はこちらを参照。
感想としては、実際の書き方がこんな感じなんかな〜ってなったのがすっごい収穫でした(・∀・)
authcompornentとかまでいけなかったのは残念だったけど時間的にもさすがに。。。
githubでwikiやったりサンプルソースを用意したりってのは素敵でした!
チャプター毎のソースをブランチきって使ったり、diffで今回はココにこんなの追加したよ!って見せ方も分かりやすくて途中から追った身としても助かりましたw
しかも内容がすごくて…これだけでもかなりの成果物ですよ!
丸一日(朝9時から17時まで)で弁当つけて1000円という異常な価格(いい意味で!!)でこの内容を提供されるとたまらんです(・∀・)
主催のslywalkerさんやお手伝いされていた皆さん。
ほんと、ありがとうございました!!
More >
コンソールアプリケーション Yii Framework触るぜ日記(6)
3月 9th
シェルからコマンド打ってガー!
というヤツです。
cronから動かしたりメール受信した際に処理させたりと意外と使う。
今回はコレをYiiでやってみるテストです。
参考にしたのはモチロン(?)choco & moca Yiiのcron jobの作成法と公式です。
今回は公式の方のタイプでやってみましたよ。
流れ
protected/直下にエントリースクリプトを置く。
protected/commands/直下にコマンドクラスを置く。
シェルからGO!!
という流れになります。
エントリースクリプト
まぁ、下記の内容でいいっす。
<?php
defined('YII_DEBUG') or define('YII_DEBUG',true);
require_once('/path/to/framework/yii.php');
$config = dirname(__FILE__).'/config/main.php';
Yii::createConsoleApplication($config)->run();
これを適当な名前でprotected直下においてくださいな。
とりあえず今回はcui.phpとして保存しました。
コマンドクラス
CConsoleCommandを継承したコマンドクラスを用意します。
このコマンドクラスをprotected/commands/の下に置く。
クラス名にCommand付けないとアレです。
<?php
class sampleCommand extends CConsoleCommand
{
public function run( $args )
{
echo('sample'."\n");
}
}
これをprotected/commands/sampleCommand.phpとして保存。
ファイル名にもCommandが必要です。
シェルからGO!
あとはシェルから入れればOKです
php ./protected/cui.php sample
これでsampleって表示されるよ!
おまけ
main.phpに設定するとCommand付けるとかいう気持ち悪さ(?)から開放されます。
protected/config/main.phpに設定を追加。
'commandMap'=>array( 'sample'=>'application.commands.sample' ),
これでクラス名やファイル名にsampleってつけなくてよくなりますよ。
クラスファイルを設置するディレクトリも自由になります。
まぁ、Commandつける方が早いけどね!!!
追記:3/11 嘘です。
commandMapを設定すると通常のwebアプリの方で「commandMapなんて設定されてねーよ」エラーが出ます。
設定するなら、エントリースクリプト(この例だとcui.php)の方で$config['commandMap'] = array(‘コマンド’);って指定する必要がありますね。
ゴメンちょ(´・ω・`)
携帯表示その1 Yii Framework触るぜ日記(5)
3月 2nd
ナウなヤングは携帯だって!
PCみたいなモン起動させてる間に携帯でいけますから!
ってか俺、携帯サイトばっかり触ってる人ですもんね。
javascriptで遊びたいよ、ママン(><)
そんなワケで携帯対応してみる。
とりいそぎ表示テンプレートを分ける程度の簡易対応です。
最初はCThemeとかCThemeManagerとか触るハメになるかと思ったけどそこまでしなくても大丈夫みたいです。
とはいえこれで正解か微妙ですが…。
やりたい事は、
- viewファイルを携帯なら携帯用のviewファイルを使いたい
- ディレクトリで携帯をわけるのヤダ(面倒)
- docomo_index.phpとかau_index.phpみたくしたい
- 3キャリア共通ならmobile_index.php使う
まぁ、よくあるっぽい感じにしたいんです。
実装はズバリ、application.components.Controllerに関数追加しました。
$breadcrumbsのメンバ変数を追加してるだけのヤツです。
いいよね?componentsに入ってるんだし。
resolveViewFile()をさわらないとファイル名での変更が厳しそうだったのでどうしてもControllerでやる必要があったんです。よ。
でも絵文字対応とかもあるんでちゃんと分離できればベストだなー。
やってるのは、コンストラクタでキャリア判別してファイル読み込み時にキャリアによって各ファイルをチェックする。
そんな流れ。
class Controller extends CController
{
/**
* @var array the breadcrumbs of the current page. The value of this property will
* be assigned to {@link CBreadcrumbs::links}. Please refer to {@link CBreadcrumbs::links}
* for more details on how to specify this property.
*/
public $breadcrumbs=array();
//以下、携帯対応
const FLG_MOBILE_DOCOMO = 'docomo';
const FLG_MOBILE_AU = 'au';
const FLG_MOBILE_SOFTBANK = 'softbank';
private $carrier = NULL;
public function __construct( $id, $module=null )
{
//キャリア判定
//面倒なんで未実装。
//pearのNet_UserAgent_Mobileとか使えばいいと思うよ。
$this->carrier = 'au';
//CControllerのコンストラクタ呼んであげる。
parent::__construct( $id, $module );
}
public function getCarrier()
{
return $this->carrier;
}
public function isMobile()
{
if( $this->carrier ){ return(true); }
else{ return(false); }
}
//携帯用viewファイル対応
public function resolveViewFile($viewName,$viewPath,$basePath)
{
$filename = parent::resolveViewFile($viewName,$viewPath,$basePath);
if( $this->isMobile() ){
$viewPath = dirname($filename).DIRECTORY_SEPARATOR;
$viewName = basename($filename);
switch( $this->getCarrier() )
{
case self::FLG_MOBILE_DOCOMO:
$tmpName = $viewPath.'docomo_'.$viewName;
break;
case self::FLG_MOBILE_AU:
$tmpName = $viewPath.'au_'.$viewName;
break;
case self::FLG_MOBILE_SOFTBANK:
$tmpName = $viewPath.'softbank_'.$viewName;
break;
}
if( is_file($tmpName) ){ return($tmpName); }
if( is_file($viewPath.'mobile_'.$viewName) ){ return($viewPath.'mobile_'.$viewName); }
}
return $filename;
}
}
キャリア判定つける前に力つきました。
もぅ帰る。
キャリア判定の他に絵文字の対応とかもいると思うけど、、
それはまた今度!