Orm and Database

ORM/Database/Datasourceの棲み分け

※1人AdventのDay-21です 1人advent(CakePHP中心、PHP開発よもやま) Advent Calendar 2018 - Adventar 概要 CakePHP3のデータベース周りの処理を追っていくと、「ORM」「Database」「Datasource」という、似た名前のレイヤーが存在することに気づきます。 普段は特に意識することのないこれらの違いは、どこにあるのでしょうか。 気になったので調べてみました。
Read more

Behaviorを使うか、Traitにするか

※1人AdventのDay-16です 1人advent(CakePHP中心、PHP開発よもやま) Advent Calendar 2018 - Adventar 概要 CakePHP3ではBehaviorを利用することで、Tableクラスにmixinすることができます。また、PHPにはTraitの仕組みがあり、これを利用することで継承を用いずにメソッドやプロパティの再利用を実現することができます。 現時点で考えている、個人的な「どう使い分けるか」というポイントをまとめてみます。
Read more

Entityの`$_accessible`について、もう1度。

※1人AdventのDay-14です 1人advent(CakePHP中心、PHP開発よもやま) Advent Calendar 2018 - Adventar 概要 CakePHP3では、データの誤操作を防ぐためEntityの持つプロパティへの代入可否を設定する $_accessible 機構が備わっています。 具体的な利用方法を確認していきたいと思います。
Read more

カスタムファインダーについておさらい

※1人AdventのDay-13です 1人advent(CakePHP中心、PHP開発よもやま) Advent Calendar 2018 - Adventar 概要 CakePHP3で導入された「カスタムファインダー」は、Queryの組み立てを抽象化・パッケージ化する手法です。 よく利用するconditonsの追加やfields、formatResultsなどの手順を一箇所にまとめ、更にメソッドチェーンによるQueryのビルドを可能にします。
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は表現力の話です。 これらに鑑みて、「デメリットはあまり無さそうでちょっとメリットがあるな」というのが、現時点での私の所見です。