25日目の記事ではありません。Blockを活用しようCRUDプラグインお勧めこの記事を書いた動機CakePHPにおいてビジネスロジックに該当するものをComponentに書くという記事を見かけるたびに、それはアンチパターンじゃないのと感じている日々。ビジネスロジックをどこに書くべきか、共通処理をどこに書くべきかというのを、自分の考えを整理する意味でも記事として残しておきたいと思います。コンポーネントにビジネスロジックを書いてはいけないのかコントローラやリクエストに依存するためテストを書きづらくなるのと、そのビジネスロジックをシェルなどから実行したい場合にそのまま呼び出せないという問題があります。ビジネスロジックはコントローラに依存しないように書くべきです。特定のページからの遷移しか許可しない、ログインユーザによってアクセスを制限する、といったような処理は、Controller/Componentに書くべき処理です。HTTPリクエストに関する処理は、DispacherFilterやMiddlewareという選択肢もあります。部分も一読すると良いでしょう。リクエスト、セッション状態をModel層に渡す処理、Model層からの結果をViewへ渡す処理Contollerの本来の領分ですね。add/editのアクションで同じようなデータを取得しておきたいなど、複数のactionから使用されるような処理は、Controller内にprivateなメソッドを作成するか、Controllerをまたぐようであれば、Component化するのがよいと思います。Contoller/Componentでconditionsなどのパラメータを組立ててfindメソッドを呼び出すのはお勧めしません。カスタムファインドや取得用のメソッドをModel層に作成して取得するようにすべきです。定義する保存処理などにおいて入力パラメータの変換などをContoller/Componentに書いてしまいがちですが、モデルのメソッドへ$this->request->data()などを直接渡して、パラメータの変換などもモデル層で行うのがよいでしょう。3.x以降では、ビューセルという概念が追加されています。画面へ共通パーツを表示したいという目的であれば、ビューセルを使うのが望ましいでしょう。コントローラのメソッドに10行以上の記述がある場合は、危ない兆候だと思いましょう。CRUDプラグインによる矯正CRUDプラグインを利用することでコントローラ層を簡潔に記述することができます。SearchCRUDプラグインはマスタデータの管理やAPIを作成する場合に有用なのですが、独自ロジックを組み込む場合はイベントを利用するため、処理ごとにロジックを分離しやすくなります。SLYWALKERControllerでのTraitの使用は危険トレイトを使用した場合、意図せずにメソッドが公開されてしまう可能性があります。GOTOさんの回答が素晴らしいので以下に引用します。モデルとは?一般的に「モデル」というのは、仕組みや構造を分かりやすく表したものを指します。業務のためのシステムであれば、その業務で扱っている「情報の構造」だったり、「情報の作り方のルール」「手順」だったりします。CakePHPのModelは?CakePHPのModelの場合、データベースのスキーマを自動的に読み取って、そのテーブルのレコードを簡単に扱えるようになっているため、一見Modelの役割が「DB入出力のためのコード置き場」のように見えてしまいます。統一した形式で扱えるようにする点にあります。他のMVC系のフレームワークでも、Modelと名付けられている部分には、このように「情報の形」を表現するという目的が与えられています。この情報の形に付随する処理(情報の入出力や、形の整合性のチェック、形の多少の変形・合成)は、Modelに記述するということになるでしょう。3.xにおいては、Repository/Entityパターンを採用していますので、情報の取得に関すること、情報の整合性のチェックに関することについてはTableに、個々の情報の整形についてはEntityの役割になります。データソースからの取得データソースから情報を指定の条件で取得したい場合は、モデルクラスのfindメソッドを直接利用するのではなく、取得、整形するためのメソッドを用意した方がよいです。定義するまた、2.xにおいては取得条件が複雑になる場合、条件を返すメソッドをモデルクラスへ作成するのも良い手法です。$Post->getPublishedConditions($now)]);取得したデータの整形モデルに取得用の専用メソッドを作成するか、カスタムfindメソッドを利用して書きます。個々のフィールドの整形については、Entityに記述します。'KVAS');}ただし、アクセサメソッド(_get)はDBへの保存時にも適用されてしまいます。取得したデータを呼び出すときのみフィルタを掛けたければ、仮想プロパティを作成して、そちらを利用するようにするとよいでしょう。text型のフィールドにシリアライズして格納したデータを呼び戻したい場合などは、カスタムデータタイプを定義します。2.xではエンティティの概念がないため、一般的にはafterFindにて処理することになります。入れることでエンティティへの変換が可能になります。場面によって表示形式を変えたい場合は、Entityクラスを変更する方法がよいと考えます。データの整形についてHelperなどを使用してView層でやると、規模が大きくなってきた場合に破綻しやすいのであまりお勧めしません。同じテーブル/データソースに対してでも、状況によって保存するフィールドやバリデーションを変えたいということは往々にしてあります。CakePHPのよくある誤解として、1つのテーブルに対してモデルクラスは1つというのがありますが、そんなことはありません。上記のモデルの定義の通り、1つのテーブルに対してでも場面ごとにモデルクラスを作成して、バリデーションや保存処理を書いていくとよいでしょう。理想としては、コントローラではモデルの保存処理メソッドを呼び出すだけの記述になるのがよいです。3.xでは、バリデーションの変更が容易になっています。こちらを利用してバリデーションを切り替える方法もありです。分かれていることを覚えておいてください。beforeSave/afterSaveを避ける保存処理の前後にメール送信や決済処理など連動する処理がある場合、beforeSave/afterSaveなどに書いてしまいがちですが、処理が複雑になってくるとイベントの依存関係の把握に苦労するようになります。そのため、保存の前後に併せて処理を行う場合は一連の処理専用メソッドを作成するようにします。利用して入力に対してのバリデーション定義と実テーブルへのフィールド変換を行うとよいでしょう。することで、テーブルに紐付かないモデルを作成できます。$_schemaプロパティを定義することで、FormHelprとの連携も可能です。一度のリクエストで複数のテーブルにまたがって処理を行いたい場合があります。利用して処理を記述するのがよいでしょう。php-tips.comビヘイビアを活用するビジネスロジックを記述するのにビヘイビアを利用するのも良い手法です。Slackチャンネルでslywakerさんにお聞きしたのがきっかけです。1テーブルに複数のロジックが存在する場合、モデルクラスが肥大化しがちです。Formを利用するなどの方法がありますが、処理ごとにビヘイビアを作成し切り替えて利用するのも一つのアイディアです。Traitで処理を切り分ける方法もありますが、処理の有効化/無効化が容易なことと、モデル/ビヘイビアの依存関係を記述しやすいことから、ビジネスロジックを書くのであればビヘイビアをお勧めします。※デメリットとしてIDEの補完ができない点があります。@methodアノテーションをモデルクラスに付与して我慢しましょう。コア部分で名前空間を使用できない2.x系で処理を分けるのに有用です。Orderモデル専用です。セットされていません。Orderモデル専用です。セットされていません。Cell3.xからの新機能で、CMSでサイドバーへの記事ランキングの表示や、カートシステムでの買い物カゴの表示などに利用できるのがビューセルです。Qiita2.xではrequestAction()メソッドを利用して同じようなことができますが、あまりお勧めしません。Controller::requestAction()Elementエレメントは繰り返し表示する部品や、共通パーツを表現するのによく使います。"おお、このテキストはとても役に立つ。"おお、このテキストはとても役に立つ。Blockヘッダーやサイドバーに特定のページのみ何かを表示したい場合などに利用できるのが、ビューブロックという機能です。利用方法としてはまず挿入先のブロックをレイアウトファイルなどに定義します。?></aside>そして、特定ページのテンプレートから定義したビューブロックへコンテンツを追加します。$this->end();?>詳しくはマニュアルを確認してください。ビューブロックView層からModelを直接呼び出すSELECTタグのoption表示用のデータを取得したい場合など、いちいちコントローラーでセットして取得するというのは面倒ですので、主となるもの以外のデータの取得に限って言えばViewからModelを呼び出してもよいでしょう。データの更新など副作用を伴う処理を書いてはいけません。知らない子ですね標準のHtmlHelperやFormHelperを拡張する以外では、独自に作成するメリットをあまり見いだせていません。