CakePHP 3.7の個人的な見どころ

※1人AdventのDay-9です 1人advent(CakePHP中心、PHP開発よもやま) Advent Calendar 2018 - Adventar 晴れて、CakePHPの3.7がリリースされました。 CakePHP 3.7.0 Released — Bakery ここしばらく、「4へのスムーズな移行をするために」を意識し続けてきたCakePHPコミュニティです。その様子は、別の場所に自分なりの観点でまとめてみています。 今からちょっとだけ先の未来、CakePHP4の話 〜Upcoming CakePHP Roadmap & Releases〜 - コネヒト開発者ブログ CakePHP3.6.0のbeta1が出たのでおさらいしてみる - コネヒト開発者ブログ そして、本来であれば「出さずに済ませたかった」とも言える3.7であり、これが3系のファイナルバージョンとなるはずです。 リリースノートと移行ガイドから、その内容を読み取ってみます。 主観により取捨選択しているので、詳細は原文を参照してください。 CakePHP 3.7.0 Released — Bakery 3.7 Migration Guide - 3.7 CakePHP3.xの最終バージョン This release is the last planned feature release for 3.x. Going forward the core team will be focusing on supporting 3.7 and completing 4.0.0. とされています。
Read more

dereuromark/cakephp-dtoに触ってみる

※1人AdventのDay-8です 1人advent(CakePHP中心、PHP開発よもやま) Advent Calendar 2018 - Adventar CakePHP開発者であるMark Sch.さんが、新しいプラグインを公開されていました。 [New]dereuromark/cakephp-dto CakePHP DTO Plugin https://t.co/vBFe8DJUPE — function(){exit;} (@call_user_func) 2018年12月8日 名前の通り、CakePHPでDTOを扱うための実装のようです。 cf) Data Transfer Object - Wikipedia おもしろそうなので、早速触ってみました。 ざっくりいうと何? 決められたプロパティを持つmutable/immutableなオブジェクトを扱いやすくするためのもの 決められたプロパティ = 型は、設定ファイルに記述していく それらの設定を、実クラス生成コマンドによって作成する 実際のクラスを生成するからIDE上での保管や静的解析との相性が良い CakeDTOに触ってみる setup まずは、インストールです composer require dereuromark/cakephp-dto:dev-master Pluginを有効化します。1 bin/cake plugin load CakeDto -b はじめてのDTO作成 ファイル初期生成用のコマンドが用意されています。 bin/cake dto init これを実行すると、config/dto.xmlに以下のようなファイルが設置されます <?xml version="1.0"?> <dtos xmlns="cakephp-dto" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="cakephp-dto https://github.com/dereuromark/cakephp-dto"> </dtos> ・・・と言っておいて何ですが、個人的にYAMLでいきたいのでYAMLに書き換えます。 こちらのExampleを参考にしましょう。 /examples/basic.dto.yml
Read more

findOrCreate()時にvalidationを行う

※1人AdventのDay-2です 1人advent(CakePHP中心、PHP開発よもやま) Advent Calendar 2018 - Adventar 先日、Modelを書いているときにfindOrCreate()の挙動でハマった部分があったので調べてみました。 バリデーションが期待通りに動かなかったので、その対応を書いています。 findOrCreateメソッドについて CakePHP3のTableClassに、 findOrCreate() というメソッドがあります。 code: https://github.com/cakephp/cakephp/blob/3.6.13/src/ORM/Table.php#L1686 これは、「第1引数で渡されたデータを検索する。DB上に存在しなければ、新規にEntityを作成・保存し、それを返却する」というものです。知っていると、多くの場面で使いたくなります。 $data = ['name' => 'new太郎']; $entity = $this->Table->findOrCreate($data); この結果として、(DB上にすでにレコードがあるか無いかにかかわらず) {name: new太郎} のEntityインスタンスが取得される、というわけです。なお、 すでに persistent 済みであるため、$entity->isNew() はfalseとなります。 実装内容について詳しく もう少し、内部処理について詳しく見てみましょう。 // \Cake\ORM\Table public function findOrCreate($search, callable $callback = null, $options = []) { $options = new ArrayObject($options + [ 'atomic' => true, 'defaults' => true, ]); $entity = $this->_executeTransaction(function () use ($search, $callback, $options) { return $this->_processFindOrCreate($search, $callback, $options->getArrayCopy()); }, $options['atomic']); if ($entity && $this->_transactionCommitted($options['atomic'], true)) { $this->dispatchEvent('Model.
Read more

`Query` を愛用する。(もしくは `->all()` を避ける)

Cake2では、Modelからの返却値がすべて配列でした。 そのため、私はCake3を利用し始めた当初、「データベースからの取得した内容」は「値の集合」に変換して処理するぞ!みたいな意識が働きがちでした。 例えばこんな様子です $books = $this->Books->find()->all(); $this->set(compact('books')); もっと酷い時は、ResultSetの使い方に難儀してhydrationをいじって、そのまま配列にして処理を・・・という書き方をしたりもしました。 ref: Class Cake\ORM\Query | CakePHP 3.4 しかし、QueryはIteratorAggregateを備えているので、「それをそのままループさせる」ことでレコードを処理することが可能です // in controller $books = $this->Books->find(); $this->set(compact('books')); // in template <?php foreach ($books as $book): ?> <div><h1><?= h($book->title) ?></h1></div> <?php endforeach; ?>} 個人的には「単純にレコードを取り出したいだけ」の時は(all()などを使って)ResultSet化しないでQueryオブジェクトのままやり取りすることが多いです。 Queryのままにしておく = 結果を確定させないままの状態を維持しておくことで利用できる機能があるため orderやwhereの追加、subqueryの利用など 後にロジックの改修があったときに変更をしやすい 1と同じ理由です 明示的にall()を使っている箇所について、必ず「ResultSetが欲しい」「DBにクエリを実行させたい」と言ったような意図をコード上で表現できるようになる 単純にコードが減る 1,2は昨日の話です。3,4は表現力の話です。 これらに鑑みて、「デメリットはあまり無さそうでちょっとメリットがあるな」というのが、現時点での私の所見です。

コレクションを任意の順番で並び替える

コレクションを任意の順番で並び替える PHPを使っていると、「任意に順番を並び替えたキーに沿って、連想配列を並び替えたい」ということが意外と面倒くさかったりする。 MySQLでいう ORDER BY FIELD(field, idx1, idx2, idx3) みたいなやつ。 Collectionクラスを用いると簡単にできそうだな〜と思ったのでメモ。 $order = [2, 1, 3]; $data = collection([ ['id' => 1, 'name' => 'John'], ['id' => 2, 'name' => 'Alice'], ['id' => 3, 'name' => 'Yui'], ]); $orderMap = array_flip($order); $data = $data->sortBy( function ($datum) use ($orderMap) { return $orderMap[$datum->id]; }, SORT_ASC ) ->compile(false); 何をしているかというと、 array_flipでもとの並び順を覚えさせて 対応順にarrayに位置を教えてあげる というだけのもの。 Collectionクラスは、以前にQiitaにも書いた。 とても便利で強力なUtilityなので、使いこなしたい。 [CakePHP3]現場で使えるCollectionクラスの15選 - Qiita