Tips, Snippets and Tutorials ( Japanese )


(Tmsongbooks215) #1

Yiiを使いこなすためのヒント、コツ、小技等を扱うトピックです

Yii初心者のための基本的なことまとめと同様、それぞれのTipsをリストアップしていきます

これは便利だと思う使い方や、こういう風に扱うとスマートになるなど

ささいなことでもかまわないので、遠慮なく書き込んでください

本家はこちら - Yii Framework Discussions Subforums - Tips, Snippets and Tutorials

  • CRUD操作の簡略化

  • ページキャッシュノウハウ

  • ビヘイビアを使って、画像アップロード処理を簡単にする

  • 複写して新規作成

  • ユーザ関連の実装をモジュールで作る利点

  • Yiiコードリーディング

  • ビューでウィジェットのコードをシンプルに書くいくつかの方法

  • CDetailView に複雑なHTMLを表示させたいとき

  • CLinkPagerの実装を拡張してシンプルにする

  • 3通りを簡単に切り替えられるログインの実装

( 最終更新日 2012-04-08 )


(Tmsongbooks215) #2

[color="#8B0000"][size="3"]CRUD操作の簡略化[/size][/color]

それぞれのコントローラで

同じようなCRUDアクションを書くのに退屈しないために

まず、createと、updateはほぼ同じなので、components/actions/Save.phpにまとめます


<?php

class Save extends CAction {


	public function run($id=null)

	{

		$c = $this->getController(); // $cは各コントローラ内で使う$thisと同じ

		$m = ucfirst($c->getId()); // $mは各コントローラ内で使うモデル名

		$model = $id===null ? new $m : $m::model()->load($id); // GET['id']がnullならcreate処理, そうでないならupdate処理

	

		if (isset($_POST['confirm']))

		{

			$model->attributes = $_POST[$m];

			if ($model->validate())

			{

				$c->setPageState('x', $model->attributes);

				$c->render('confirm', array('model'=>$model));

				return;

			}

		}

		else if (isset($_POST['back']))

			$model->attributes = $c->getPageState('x');

		else if (isset($_POST['finish']))

		{

			$model->attributes = $c->getPageState('x');

			if ($model->save())

				$c->redirect(array('index'));

		}

		$c->render('save', array('model'=>$model)); // create, updateともにsave.php(view)でまとめています

	}

}

確認画面処理も追加しています。確認画面の操作はこちらなどを参考にしてください

続いて、components/actions/Delete.php:


<?php

class Delete extends CAction {


	public function run($id=null)

	{

		$c = $this->getController();

		$m = ucfirst($c->getId());

		

		$m::model()->load($id)->delete();

		$c->redirect(array('index'));

	}

}

$m::model()->load($id)はモデル内で次のように書いています


public function load($id)

{

	$model = $this->findByPk((int)$id);

	if ($model===null)

		throw new CHttpException(404,'データがありません');

	return $model;

}

create, update, deleteアクションの骨格はできたので

次に、components/Controller.phpに以下のコードを足します


public function actions()

{

	return array(

		'save'=>array(

			'class'=>'application.components.actions.Save',

		),

		'delete'=>array(

			'class'=>'application.components.actions.Delete',

		),

	);

}

あとは、Controller.phpを継承して各コントローラを書けば

自動的にcreate, update, deleteのアクションが作られるようになります

[color="#8B0000"]ttp://www.example.com/index.php?r=hoge/save[/color] にアクセスするとcreate処理

[color="#8B0000"]ttp://www.example.com/index.php?r=hoge/save&id=777[/color] にアクセスするとupdate処理

[color="#8B0000"]ttp://www.example.com/index.php?r=hoge/delete&id=777[/color] にアクセスするとdelete処理になります

( readも同じような流れだと思うので省きました )

補足:

Viewについてですが、create, updateの処理をviews/hoge/save.phpにまとめる形になるので

$model->isNewRecordなどを使って、少し表示に工夫が必要になるかもしれません

関連リンク

[Wiki] Actions code reuse with CAction

[Guide] コントローラ - 3.アクション


(Mocapapa) #3

[size="4"][color="#8b0000"]ページキャッシュノウハウ[/color][/size]

開発はローカルで高速なサーバで、運用はリモートで遅いサーバで行っていますが、高速なYiiといえども、ページの表示に悪くすると1秒かかったりしています。これではとても見るに耐えないため、ガイドのキャッシュの項を参考にしてページ表示の超高速化に成功しました。

http://pugpug.lolipo…as-blog/post/89

遅いサーバでもキャッシュに入れば2msec程度で表示されるため、数百倍の超高速化が達成できました。


(Tmsongbooks215) #4

[color="#8B0000"][size="3"]ビヘイビアを使って、画像アップロード処理を簡単にする[/size][/color]

再利用可能なコードはcomponentやbehaviorなどにまとめておくと便利です

今回は画像アップロード処理をbehaviorにまとめて

使用したいモデルのみでそれを利用するやり方を書いていきます

2011-12-03 更新

以前書いたものを参考にして

ブログで書き直してみました。ボリュームがありますが、よろしければ参考にしてください


(Softark) #5

[color="#8B0000"][size="3"]複写して新規作成[/size][/color]

CRUD 操作に「複写して新規作成」という操作を追加すると便利です。

機能的には、既存のエントリーの内容をコピーして、新規作成のフォームにペーストするものです。少し内容を変えただけの新規エントリーを登録したい場合に重宝します。

「複写して新規作成」は、Gii が自動生成した CRUD のコードをほんの少し拡張するだけで実装することが可能です。

  1. コントローラに、モデルのデータを複製するメソッドを追加。



public function duplicateModel($id)

{

        $model = $this->loadModel($id);

        // 新規エントリーとするために、データを部分的にクリアする

        $model->id = null;   // PK をクリア ... たいていの場合に必須

        $model->foo = null;  // 例

        $model->bar = null;  // 例

        ....                 // 何をクリアすべきかは、モデルの設計によって異なる

                             // クリア操作は、モデルクラスでやる方が良いかも、、、

        $model->isNewRecord = true;    // 新規レコードとする ... 必須

        return $model;

}



  1. コントローラの actionCreate() メソッドを修正して、PK をパラメータとして取るようにする。



public function actionCreate($id = null)

{

        $model = null;

        if ($id === null || isset($_POST['FooBar']))

                $model = new FooBar;

        else

                $model = $this->duplicateModel($id);


        // AJAX validation

        $this->performAjaxValidation($model);


        if (isset($_POST['FooBar']))

        {

                $model->attributes = $_POST['FooBar'];

                if ($model->save())

                        $this->redirect(array('view', 'id'=>$model->id));

        }

        $this->render('create',array(

                'model' => $model,

        ));

}



引数 &#036;id は、デフォルト値として null を取ります。

&#036;id が null の場合は、従来同様、"create" のアクションとして機能し、&#036;id に有効な値が入っている場合は、「複写して新規作成」のアクションとして機能します。

  1. ビュー・ファイルで、「複写して新規作成」を呼び出すリンクを作る。

例えば、view.php で、




// views/FooBar/view.php

....

<?php echo CHtml::link('複写して新規作成', array('create', 'id'=>$model->id)); ?>

....



または、admin.php で、




// views/FooBar/admin.php

....

$this->widget('zii.widgets.grid.CGridView', array(

        'id' => 'foo-bar-grid',

        'dataProvider' => $model->search(),

        'filter' => $model,

        'columns' => array(

                'foo',

                'bar',

                ....

                array(

                        'class' => 'CButtonColumn',

                ),

                array(

                        'header' => '複写して新規作成',

                        'type' => 'raw',

                        'value' => 'CHtml::link("複写して新規作成", array("create", "id"=>$data->id))',

                ),

        ),

));



たったこれだけです。お試しあれ。


(Tmsongbooks215) #6

[color="#8B0000"][size="3"]ユーザ関連の実装をモジュールで作る利点[/size][/color]

ユーザ関連の実装をモジュールで作ってみたんですが

なかなか良かったので、メリット、デメリットなどをブログにまとめてみました

http://livejamdb.blogspot.com/2011/12/yii_20.html


(Mocapapa) #7

[size="4"][color="#8b0000"]Yiiコードリーディング[/color][/size]

index.phpから追いかけようと思ったこと、ありますよね?普通はclass referenceに詳細な説明があるので、メソッドを追いかけるのにclass referenceを使うと思いますが、欠点がひとつあります。それはメソッド名を出すのに検索しなければならないことです。

先日、ひらメソッドという方法をみつけ、さっそくYiiのコードリーディングに応用できないかと思い、ためしたところ、ある程度うまく行ったので以下に記して置きます。

https://sites.google…iianalysis/home

ちなみに、ひらメソッドというのは自分がCPUになった気持ちで、完全にボトムアップにコードを読む方式です。


(Tmsongbooks215) #8

[color="#8B0000"][size="3"]ビューでウィジェットのコードをシンプルに書くいくつかの方法[/size][/color]

どうしても長くなりがちなウィジェットのコードを、シンプルに書く方法をまとめてみました

わりと基本的な3つを紹介していますが、これらの他にもこういう方法があるよ、などの意見も聞ければ幸いです

http://livejamdb.blogspot.com/2012/02/yii.html?spref=tw


(Tanakahisateru) #9

[size="4"][color="#8B0000"]CDetailView に複雑なHTMLを表示させたいとき[/color][/size]

Yii の CDetailView に複雑なHTMLを表示させたいとき CController::renderPartial で value を埋める。

たとえば _complex_content.php というような、複雑なHTMLの中身をレンダリングするためのファイルを作り、そこでHTMLを構築するようにする。で、CDetailView のほうで特定のカラムの表示のみ詳細化し、type を raw に、そして value として CController::renderPartial メソッドを使う。




$this->widget('zii.widgets.CDetailView', array(

    'data'=>$model,

    'attributes'=>array(

        'id',

        'name',

        //'poor_content',  // 文字列表示じゃかっこ悪い

        array(

            'label'=>'Complex Content',

            'type'=>'raw',

            'value'=> $this->renderPartial('_complex_content', array(

                'data'=>$model,

            ), true), // ここ大事

        ),

),

));



CController::renderPartialメソッドはサブテンプレートに「出力」させるだけでなく、結果を文字列で得ることもできます。省略可能な第三引数は、サブテンプレートのレンダリング結果をいきなり表示するか、結果を文字列で得るかのオプションです。

これで、凝ったHTMLを表示させたいとき、いきなり CDetailView や CGridView の便利さを捨てて全部自前でデザインする必要がなくなりました。スキャフォルドで生成された、標準の機能を使うテンプレートの大部分を生かしつつ、かつ、部分的に独自のHTMLにすることができます。

テンプレートの外部化によって、CDetailView の直前でHTMLを得るために文字列結合処理するという汚いやり方を避けられます。また、本質的に複雑なものは自然に外出しファイルになってくれます。


(Tmsongbooks215) #10

[color="#8B0000"][size="3"]CLinkPagerの実装を拡張してシンプルにする[/size][/color]

やや、強引な拡張の仕方ではありますが

CLinkPagerクラスを使って、ウィジェットの拡張方法を簡単にまとめてみました

http://livejamdb.blogspot.com/2012/03/yii-framework-clinkpager.html?spref=tw


(Tmsongbooks215) #11

[color="#8B0000"][size="3"]3通りを簡単に切り替えられるログインの実装[/size][/color]

  • ユーザ名 と パスワード

  • メールアドレス と パスワード

  • ユーザ名またはメールアドレス と パスワード

LoginForm部分のrules()で array(‘login, password’, ‘loginValidator’),

と指定しているのが、果たしてアリなのかがちょっと微妙です。誤作動はないですが、もしあれば言ってください

http://livejamdb.blogspot.jp/2012/04/yii-framework-3.html