忍者ブログ

スイーツ(笑)と呼ばないで!!

NEW ENTRY
10 2024/11 1 23 4 5 6 7 8 910 11 12 13 14 15 1617 18 19 20 21 22 2324 25 26 27 28 29 30 12

11/24/05:46  [PR]

×

[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。

06/03/00:21  Route::controllerって本当に便利?

laravelにはいろんなroutingの書き方がありますね。

その中の一つにImpicit Controller(暗黙的なコントローラー)というものがあります。

どの辺が「暗黙的」か例を挙げましょう。


Route::controller(‘articles’,’ArticlesController’);

とroutes.phpに書きます。

そして、ArticlesControllerの中に、

public function getAbc(){

}

というアクションを定義するとします。

そうすると、このアクションは自動的に/articles/abcに対するgetリクエストにマッピングされます。
postAbc()と書けば、postリクエストにマッピングされたりしますね。

つまり、

httpメソッド名(get,post等) + アクション名

という形で自動でマッピングされるわけですね。

これが1つ目の暗黙のルールです。

なるほど、これは便利ですね。


ただ、この暗黙的なコントローラー、実は一部の人たちにはとても不人気です。

なぜでしょうか?

その理由の一つをご説明しましょう。

まず、ターミナルで
php artisan route
と打ってみましょう。

そのアプリケーションで定義されているroutingの一覧が表示されますね。
そこで先ほどの暗黙的なコントローラーについて見てみましょう。

GET|HEAD articles/abc/{one?}/{two?}/{three?}/{four?}/{five?}
というURIが
ArticlesController@getAbc
というアクションにマッピングされていますね。

さてURIの最後についている
/{one?}/{two?}/{three?}/{four?}/{five?}
これなんでしょうか?

URIからスラッシュ区切りで5つのパラメータの値を取得できる、という意味ですね。
暗黙的なコントローラーは自動で5つのパラメータの値を取得するroutingを作成するのです。

これが2つ目の暗黙のルールです。

これが嫌で暗黙的なコントローラーを使わない人は結構いますね。

例えば、下記のケースを考えてみましょう。

/articles/list?sort=1&page=3&category_id=3
こんなURIの一覧画面を想像してみましょう。
Webアプリではよく見るURIですね。

さて、本来、暗黙的なコントローラーを使用するなら、上のケースは
/articles/list/1/3/3/
という形式で表現するのが正しいかもしれませんね。
5つまではパラメータをURIから取得するのを予定したルーティングなのですから。

でも、別にInputのFacadeを使ってパラメータを取得してコントロールする分には、
最初に書いたURI前提でも一応動いたりしますね。

でも、前々回のブログ(クエリストリングの回)で書いたような
Redirect::action(‘ArticlesController@list’,パラメータの配列)
という形で楽々laravelの機能を使おうとすると、どうなるでしょうか?

暗黙のコントローラーは、5つのパラメータをスラッシュ区切りで受け取ることを予定しているので、
実はこれ、受け取った連想配列のうち最初の5つのパラメータだけはスラッシュ区切りのURIに展開されてしまうのです。

つまり、
/articles/list/value1/value2/value3/value4/value5?param6=value6&param7=value7…
という形で、最初の5つのパラメータだけはスラッシュ区切りのURIに展開され、
6つのパラメータから、いつものparam6=value6&param7=value7…という感じのクエリストリングに展開されるんですね。

先の例の後者のパターン
/articles/list/1/3/3/
という形で動くように書いてあれば何の問題もありませんが、そうでなければ、そこでアプリはクラッシュですね。


ということで、皆さん、暗黙のコントローラーを使用する際には、暗黙のルールをきちんと理解して使いましょう。

そして、暗黙のルールが嫌なら、暗黙的なコントローラーは使わない、というのは多くの人が選んできた一つの正解だと私は思います。

人それぞれですけどね^^

綺麗なバラにはトゲがある
一見便利な機能には罠がある

拍手[1回]

PR

05/27/16:21  compactを使おう!!

最近、ある部下と一緒にソースを読んでいて、
そうかcompactってあまり知られていないのか・・と知ったので今日はcompactのご紹介。
PHPでコード書いていると連想配列というのをたくさん扱いますね。
[‘key1’=>’value1’,’key2’=>’value2’]
みたいな。

laravelでもいろんなところでこの連想配列登場します。

例えば、viewにデータを渡しでviewの中で参照したいときどうしていますか?

人によっては、

return View::make(‘articles.detail’)
 ->with(‘data1’,$data1)
 ->with(‘data2’,$data2’)
 ->with(‘data3’,$data3)
 ->with(‘data4’,$data4’);

という感じでwithで渡している人もいますね。

laravelでは

return View::make(‘articles.detail’)
 ->withData1($data1)
 ->withData2($data2)
 ->withData3($data3)
 ->withData4($data4);

こんな渡し方もできますね。ちょっとマジカルな感じですね^^

でも、View:makeの第二引数で連想配列受け取れることを知っている人は、

return View::make(‘articles.deatil’,[
 ‘data1’=>$data1,
 ’data2’=>’$data2,
 ’data3’=>’$data3,
 ’data4’=>’$data4]);

こんな感じで書くかもしれないですね。少し良くなった気がしますね。

それをさらに簡単にやるのがcompact。

key名と同じ変数名をセットした連想配列を作成します。

return View::make(‘articles.deatil’,compact(‘data1’,’data2’,‘data3’,’data4’));

laravel5だとさらにviewというヘルパー関数があるので

return view(‘articles.deatil’,compact(‘data1’,’data2’,‘data3’,’data4’));

うん。無駄がないですね。

compact自体はもしかする知識として知っている人はいるかもしれないですね。

でも使ったことがない、使い道を知らない、という人が多いのかもしれません。

このcompact、laravelのフレームワーク内のソースでも多用していますね。

例えば、クエリビルダーのwhereメソッドのソースコードの中でも、

$this->wheres[] = compact('type', 'column', 'operator', 'value', 'boolean’);

こんな感じで使っています。

是非、compactを適材適所で使って無駄なコードを減らしましょう。

拍手[0回]

05/26/12:55  クエリストリング? 懐かしい響き!!

Laravelはクエリストリングについてあれこれ考える必要はありません!!

例えば、詳細な検索条件を入力して検索して表示される一覧画面。

ここから詳細画面とか他の画面に行って、その後またこの一覧画面に戻りたい、そんな時ありますね。

さて、複雑な条件保持するのどうしましょうか?

クエリストリング(?param1=abc&param2=defとか)を文字列として扱う?

そんなコードを見かけます。

Laravelならそんなことは不要です。

Laravelなら検索条件がpostされた時点でInput::all()とすればすべてのパラメータが連想配列で取得できますね。

これは皆さんご存知だと思います。

この配列を例えばセッションにsearch_paramsというキーで保存していたとします。

そして、他のアクションで処理が終わって同じ一覧に戻りたいとした場合、

return Redirect::action(‘ArticlesController@index’,Session::get(’search_params’));

この1行で済みますね。

え?「アクションのreturnじゃなくて、画面にリンクを表示したいです」って?

はい。そんな時も簡単です。

Laravelにはactionというヘルパー関数があります。

action(‘ArticlesController@index’,Session::get(’search_params’))

と書けば、クエリストリング付きのリンクのURLが取得できますね。

さあ、皆さん、もうクエリストリングについて思い悩むことはやめましょう。

あなたは自由です^^

ちなみに、Laravelのソースコード読むとわかりますが、第二引数のSession::get(’search_params’)がnullの場合、defaultとして空の配列が渡るので、ちゃんとLaravelは動いてくれます。


Laravelって便利ですねー

ちなみに、いろんな場所から飛んできて、前の画面に戻りたいけどケースによって変わる、そんなケースはどうします?

Laravelには、refererを見て判断してくれるRedirect::backというのが用意されていますね。


ソースを見るといろんなことがわかりますね。
皆さん、ガリガリ書くのではなく、バリバリとソースコードを読むことに時間を使いましょう!!

拍手[1回]

05/19/13:06  deleted_atではなく、deletedで論理削除したいと言われたら?


laravelは本当に便利ですね。

いろんな機能がすでに用意されていて、簡単につけたり外したりできます。

システム開発でよくある論理削除。

これもEloquentのModelの頭で

use SoftDeletes;

とか書くだけで利用できるようになります。

これだけで毎回、削除されているものを除く、とか条件をつける必要がなくなります。

削除されたものも含みたい場合は、

Article::withTrashed()->get();

みたいな感じでwithTrashedというscopeを指定するだけで可能。

本当に便利ですね。

ただ、この仕組みには大きな前提があります。

削除の判定はそのテーブルのdeleted_atがnullかどうかで判定する

というものです。

もちろんカラム名は

const DELETED_AT = ‘delete_datetime’;

なんて感じで上書き指定できる柔軟さがlaravelにはあります。

ただ、DB設計者が

「いや、ここはdeletedという1か0のフラグで判定する」

といった場合、ちょっと困りますね。

対処方法は大きく3つあります。

1.用意されているSoftDeletesの仕組みは使わない

毎回、where(‘deleted’,’=‘,0)とかって指定するパターンですね。
どうやら、皆この方法をとっているようです。

2.自前で論理削除の仕組みを実装する。

  自分でdeletedを使ったtraitとdeletedを使ったグローバルscopeを用意します。
  それなりに面倒ではありますね。ただ、deleted_byとか追加したりいろいろカスタマイズができます。

3.deletedではなく、deleted_atのnull判定を使うように説得する。

  DB設計者はそこまでこだわりはないかもしれません。
  毎回、where(‘deleted’,’=‘,0)と書く手間や、書き忘れによるバグが出るよりは良い、と判断するかもれません。


この週末に2のパターンで実装してみました。
一応、ちゃんと動きましたね。

ただ、deleted_atを使わず、deletedを使うためだけにこの仕組みをやるのは少し大げさかなと思いました。

私はDB設計をする側の立場ですが、いろいろバランスを考えると、laravelの標準のまま使う3の案が良いのではないかと思いました。

これはちょっと他のSEやPGたちと話し合いたいところです。
必ずしも統一する必要があるところではないと思いますが。

合わせて、created_by、updated_by、deleted_byといったデータの作成・更新・削除を行ったuser等のメタ情報の管理についても話し合いたいと思っています。

laravelにはmodel eventsという仕組みがあり、例えば、データが作成されたタイミングなどをイベントリスナーで取得し処理を実行させることができたりします。

例えばそのタイミングでログを作成することなどで、代用が可能かもしれません。
createdではなく、creatingでメタ情報をセットするのもあるかもしれません。
ただ、model毎にイベントリスナーを登録するのは面倒ですね。

今のところメタ情報更新用のtraitを作成し、modelでuseするのが一番手間では無い気がしています。

ということで、最終結論はでていませんが、同じ目的が達成できなるなら、楽でミスが少ない方法が良いですね。

拍手[1回]

05/18/20:37  guardedとfillable、ちゃんと使っている?


そのデータの作成者、簡単に偽装できます!!

と聞いたら誰もがビックリするでしょう。

今日はそんな可能性のあるお話です。

Laravelの初心者向けの講座や書籍でEloquentが紹介されるとき、

class Article extends Model{
 protected $guarded = ['id'];
}

とか書かれたりしますね。

「これはおまじないです」なんて言われて「そうかそうか」と深く考えずにそのまま真似したりします。

で、少し学習が進むと、guardedはブラックリスト、fillableはホワイトリストという感じで理解が進みます。

class Article extends Model{
 protected $fillable= [’title’,’body'];
}

こんな感じでホワイトリストの登録もできる、と。

簡単に表現すると、ブラックリストに書いてある項目はユーザー入力の配列渡しで更新ができない、ホワイトリストに書いてある項目はユーザー入力の配列渡しで更新ができる、ということになります。

そして、ホワイトリストとブラックリストは逆の意味・・・その理解から、「ホワイトリストの登録は面倒だから、テキスト通りブラックリストにidを指定しておけばいいや」と考えたりします。

本当にそうでしょうか?

fillableではなく、guardedを使っている人の多くが、idだけを指定していますね。

確かに、id,title,bodyこれだけしか項目が無ければ同じ意味です。

しかし、実案件ではこれらの他に

created_at
created_by
updated_at
updated_by

こんな項目も裏で用意されていたりしますね。

このようなケースを想定しても、ホワイトリスト方式の場合は、変わらずtitleとbodyしか更新できません。

しかし、ブラックリストでidだけ登録されている場合は、パラメータ偽装で簡単にcreated_byが更新できてしまいます。

実際にChromeの開発者ツールで簡単に試すことができました。

え、その前に頑張って配列を整理しているから問題ない?
そうかも知れません、でもfillableでホワイトリストを設定していれば、そんな努力は不要です。

ブラックリストの設定漏れだと、更新されてはいけないものが更新される可能性があります。
ホワイトリストの設定漏れだと、更新されるべきものが更新されない可能性があります。

さて、どちらのリスクをとるべきでしょうか?

私の好みはホワイトリストの方です。

laravelは私たちにセキュリティを確保するための簡単な仕組みを用意してくれています。
是非その仕組を有効活用して、無駄なコードを減らしましょう。

拍手[0回]