tag:crieit.net,2005:https://crieit.net/tags/Eloquent/feed 「Eloquent」の記事 - Crieit Crieitでタグ「Eloquent」に投稿された最近の記事 2022-07-12T23:45:36+09:00 https://crieit.net/tags/Eloquent/feed tag:crieit.net,2005:PublicArticle/18234 2022-07-12T23:45:36+09:00 2022-07-12T23:45:36+09:00 https://crieit.net/posts/mysql80-with-recursive-in-standalone-eloquent-20220712 MySQL8.0 の再帰クエリを単独の Eloquent で使ってみる <p>ちょうどやりたいことができそうだったので、 MySQL8.0 で新しく追加された再帰クエリを使ってみました。なお、単独インストールした Eloquent での使用を想定しているので、リレーションの機能をそのまま使うのは難しそうなケースでした。</p> <h2 id="経緯"><a href="#%E7%B5%8C%E7%B7%AF">経緯</a></h2> <p>内容としてはありがちな部署マスタのようなもので、親子関係まで見たいと考えたためでした。</p> <div class="table-responsive"><table> <thead> <tr> <th align="right">id</th> <th align="right">parent</th> <th align="left">name</th> </tr> </thead> <tbody> <tr> <td align="right">1</td> <td align="right">0</td> <td align="left">営業部</td> </tr> <tr> <td align="right">2</td> <td align="right">1</td> <td align="left">営業1課</td> </tr> <tr> <td align="right">3</td> <td align="right">1</td> <td align="left">営業2課</td> </tr> <tr> <td align="right">4</td> <td align="right">0</td> <td align="left">システム部</td> </tr> <tr> <td align="right">5</td> <td align="right">4</td> <td align="left">開発課</td> </tr> <tr> <td align="right">6</td> <td align="right">4</td> <td align="left">運用保守課</td> </tr> <tr> <td align="right">7</td> <td align="right">5</td> <td align="left">フロントエンドグループ</td> </tr> <tr> <td align="right">8</td> <td align="right">5</td> <td align="left">バックエンドグループ</td> </tr> </tbody> </table></div> <p>イメージとしてはこんなイメージのテーブルがあったとして、例えば「システム部」と指定した場合、「開発課」「運用保守課」「フロントエンドグループ」「バックエンドグループ」のIDを子部署として参照したい、というようなケースです。</p> <h2 id="コード"><a href="#%E3%82%B3%E3%83%BC%E3%83%89">コード</a></h2> <pre><code class="php">$hogeObjectsArray = $this->dbConnect->connection('hogera') ->select(" WITH recursive child( depth, id, parent, name ) AS ( SELECT 0, id, parent, name FROM hoge WHERE id = {$foo} UNION ALL SELECT child.depth + 1, hoge.id, hoge.parent, hoge.name FROM hoge, child WHERE hoge.parent = child.id ) SELECT depth, id, parent, name FROM child ORDER BY depth "); </code></pre> <p>最終的には上述の形で取得できました。</p> <p><code>->table($this->table)</code> 等でテーブルを指定せず、いきなり <code>->select()</code> しているのがミソです。</p> <h2 id="参考"><a href="#%E5%8F%82%E8%80%83">参考</a></h2> <h3 id="with recursive"><a href="#with+recursive">with recursive</a></h3> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://codezine.jp/article/detail/2679">MySQL 8.0の再帰With句のサンプル集 (1\/3):CodeZine(コードジン)</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://zenn.dev/rstliz/articles/65278841ac26f7">MySQL 再帰クエリで階層構造のデータを一度に取得</a></li> </ul> <h3 id="単独の Eloquent 内で with recursive を使用したい"><a href="#%E5%8D%98%E7%8B%AC%E3%81%AE+Eloquent+%E5%86%85%E3%81%A7+with+recursive+%E3%82%92%E4%BD%BF%E7%94%A8%E3%81%97%E3%81%9F%E3%81%84">単独の Eloquent 内で with recursive を使用したい</a></h3> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/okumurakengo/items/0670ce39d758ed65e8e7">100行ぐらいのSQLをLaravelのEloquent\/Query Builderで頑張る - Qiita</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://leben.mobi/blog/laravel_raw_sql/php/">Laravel5で生のSQLを実行する方法</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/Yinaura/items/562079d937021f1fc30a">MySQL — サブクエリに AS を付けないとエラーを起こす | Every derived table must have its own alias - Qiita</a></li> </ul> <h4 id="メソッド確認"><a href="#%E3%83%A1%E3%82%BD%E3%83%83%E3%83%89%E7%A2%BA%E8%AA%8D">メソッド確認</a></h4> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://laravel.com/api/5.8/Illuminate/Database/Capsule/Manager.html#method_connection">Illuminate\Database\Capsule\Manager | Laravel API</a></li> <li>query(): <a target="_blank" rel="nofollow noopener" href="https://laravel.com/api/5.8/Illuminate/Database/Connection.html#method_query">Illuminate\Database\Connection | Laravel API</a></li> <li>Builder: <a target="_blank" rel="nofollow noopener" href="https://laravel.com/api/5.8/Illuminate/Database/Query/Builder.html">Illuminate\Database\Query\Builder | Laravel API</a></li> <li>selectRaw(): <a target="_blank" rel="nofollow noopener" href="https://laravel.com/api/5.8/Illuminate/Database/Query/Builder.html#method_selectRaw">Illuminate\Database\Query\Builder | Laravel API</a></li> <li>select(): <a target="_blank" rel="nofollow noopener" href="https://laravel.com/api/5.8/Illuminate/Database/Query/Builder.html#method_select">Illuminate\Database\Query\Builder | Laravel API</a></li> <li>raw(): <a target="_blank" rel="nofollow noopener" href="https://laravel.com/api/5.8/Illuminate/Database/Connection.html#method_raw">Illuminate\Database\Connection | Laravel API</a></li> </ul> <h4 id="unionAll"><a href="#unionAll">unionAll</a></h4> <ul> <li>unionAll(): <a target="_blank" rel="nofollow noopener" href="https://laravel.com/api/5.8/Illuminate/Database/Query/Builder.html#method_unionAll">Illuminate\Database\Query\Builder | Laravel API</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://mysql.sql55.com/sql/mysql-union.php">MySQL の UNION \/ UNION ALL - MySQL の基礎 - MySQL 入門</a></li> </ul> <h4 id="(未使用) 外部パッケージ"><a href="#%28%E6%9C%AA%E4%BD%BF%E7%94%A8%29+%E5%A4%96%E9%83%A8%E3%83%91%E3%83%83%E3%82%B1%E3%83%BC%E3%82%B8">(未使用) 外部パッケージ</a></h4> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://github.com/soda-framework/eloquent-closure">GitHub - soda-framework\/eloquent-closure</a></li> </ul> <h4 id="(未使用) もはや生PDOに回帰するか"><a href="#%28%E6%9C%AA%E4%BD%BF%E7%94%A8%29+%E3%82%82%E3%81%AF%E3%82%84%E7%94%9FPDO%E3%81%AB%E5%9B%9E%E5%B8%B0%E3%81%99%E3%82%8B%E3%81%8B">(未使用) もはや生PDOに回帰するか</a></h4> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/jjongs08/items/f53bc04d582e63e7ad10">Laravelでクエリ結果を配列で取得する方法 - Qiita</a></li> </ul> <h4 id="whereIn()"><a href="#whereIn%28%29">whereIn()</a></h4> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/miriwo/items/553dccbae72a25b5467b">laravel クエリビルダ whereInを使って賢く取得情報を絞ろう - Qiita</a></li> </ul> arm-band tag:crieit.net,2005:PublicArticle/18211 2022-06-09T23:58:40+09:00 2022-06-09T23:58:40+09:00 https://crieit.net/posts/eloquent-use-db-raw-a-facade-root-has-not-been-set-error-20220610 Eloquent 単独で COUNT(*) を使用したいが DB:raw() を使用すると A facade root has not been set. エラーになる <h2 id="経緯"><a href="#%E7%B5%8C%E7%B7%AF">経緯</a></h2> <p>Eloquent 単独利用しているプログラムの中で COUNT(*) を使用したくなったのでその方法をメモ。</p> <p>単純に件数をカウントしてその数値を使いたいだけであれば</p> <pre><code class="php">$data_count = $dbConnect->table('hoge') ->count(); </code></pre> <p>で済ませることができます。が、今回はサブクエリとして使用した方がコード的にすっきりしそうな状況でした。</p> <p>先の方法ではコード上は関連性のない別のクエリをもう1つ記述しなければならないので如何なものかと思い……。</p> <h2 id="調査"><a href="#%E8%AA%BF%E6%9F%BB">調査</a></h2> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://awesome-programmer.hateblo.jp/entry/2019/07/03/162835">LaravelのEloquentで集計関数Count()などを使うとき - バックエンドとフロントエンドを行き来するWEBプログラマ―のメモ帳</a></li> </ul> <p>検索したところ、 SQL で <code>COUNT(*)</code> を使用する場合は <code>DB:raw()</code> を使うとのこと。</p> <p>ただし、 Laravel の中ならばいざ知らず今回は Eloquent 単独使用なので、 <code>DB</code> なるクラスはどこから来るのか……となってしまいました。しかも <code>::raw()</code> は static メソッドですし。</p> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://readouble.com/laravel/8.x/ja/queries.html">データベース:クエリビルダ 8.x Laravel</a></li> </ul> <p>引き続き検索すると、 <code>DB</code> はファサードでした。</p> <p>しかし、 Laravel 公式のサンプルのように</p> <pre><code class="php">use Illuminate\Support\Facades\DB; </code></pre> <p>を追加すると、</p> <blockquote> <p>A facade root has not been set.</p> </blockquote> <p>というエラーが発生して怒られてしまいます。</p> <p>通常の Laravel 内で使用する場合はインスタンスとの紐付けが上手く行われますが、今回は Eloquent のみの単体使用なのでこのパターンではできそうにないように見受けられました (できたとしても素直に Laravel を使った方が早そう)。</p> <p>最終的には</p> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/s-higuma/items/ab8fa110b13301d0c959">Eloquentを単体で導入している時にDBファサードを使用する方法 - Qiita</a></li> </ul> <p>この記事の方法で</p> <pre><code class="php">use \Illuminate\Database\Capsule\Manager as DB; </code></pre> <p>を <code>DB::raw()</code> を使うクラスのファイルの中で再度読み込ませる (別のファイルでDB接続用のインスタンスを生成していて、それを DI していたので今回は「再度読み込ませる」という表現) ことで乗り越えることができました。</p> <h2 id="参考"><a href="#%E5%8F%82%E8%80%83">参考</a></h2> <h3 id="count()"><a href="#count%28%29">count()</a></h3> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/zaburo/items/d665804f8ea850502c64">Laravelでの基本的なリレーションシップもしくはJOIN - Qiita</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://www.84kure.com/blog/2017/07/12/laravel-eloquent%E3%81%A7%E3%82%AB%E3%82%A6%E3%83%B3%E3%83%88%E3%81%99%E3%82%8B%E3%81%A8%E3%81%8D%E3%81%AE%E6%B3%A8%E6%84%8F/">[Laravel] Eloquentでカウントするときの注意 – 端くれプログラマの備忘録</a></li> </ul> <h3 id="DB::raw()"><a href="#DB%3A%3Araw%28%29">DB::raw()</a></h3> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://awesome-programmer.hateblo.jp/entry/2019/07/03/162835">LaravelのEloquentで集計関数Count()などを使うとき - バックエンドとフロントエンドを行き来するWEBプログラマ―のメモ帳</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://readouble.com/laravel/8.x/ja/queries.html">データベース:クエリビルダ 8.x Laravel</a></li> </ul> <h3 id="A facade root has not been set. エラー"><a href="#A+facade+root+has+not+been+set.+%E3%82%A8%E3%83%A9%E3%83%BC">A facade root has not been set. エラー</a></h3> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://re-engines.com/2020/05/11/laravel-facade/">LaravelのFacade(ファサード)とは? 何気なく使用していた裏側の仕組みを解説! | RE:ENGINES</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://www.wakuwakubank.com/posts/453-laravel-sql-basic/">Laravel|DBデータ操作(DBファサード, クエリビルダ, Eloquent) - わくわくBank</a> (バージョン古い)</li> <li><a target="_blank" rel="nofollow noopener" href="https://matchingood-engineer.hatenablog.com/">エンジニアブログ</a> (バージョン古い)</li> <li><a target="_blank" rel="nofollow noopener" href="https://stackoverflow.com/questions/22925451/how-can-i-query-raw-via-eloquent">php - How can I query raw via Eloquent? - Stack Overflow</a> (バージョン古い)</li> <li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/s-higuma/items/ab8fa110b13301d0c959">Eloquentを単体で導入している時にDBファサードを使用する方法 - Qiita</a></li> </ul> arm-band tag:crieit.net,2005:PublicArticle/18207 2022-05-31T23:48:56+09:00 2022-05-31T23:48:56+09:00 https://crieit.net/posts/stdclass-and-illuminate-support-collection-convert-array-20220601 Illuminate\Support\Collection を配列に変換する <h2 id="経緯"><a href="#%E7%B5%8C%E7%B7%AF">経緯</a></h2> <p>Eloquent で取得したデータはそのままだと Object の Collection になっているのですが、配列として扱いたいケースが出てきました。そこで先の Collection を配列に変換するメモを残しておきます。</p> <h2 id="コード"><a href="#%E3%82%B3%E3%83%BC%E3%83%89">コード</a></h2> <pre><code class="php">$employeesCollectionObject = $dbConnect->table($this->table) ->where( [ ['id', '=', $id], ] ) ->select( 'employee_id', 'depart', ) ->get(); $employeesCollectionArray = $employeesCollectionObject->map(function ($item, $key) { return [ 'tori_id' => $item->employee_id, 'domain' => $item->depart, ]; }); </code></pre> <p>例えばこうすることで、</p> <pre><code class="php">object(Illuminate\Support\Collection)[xxx] protected 'items' => array (size=10) 0 => object(stdClass)[yyy] public 'employee_id' => string '001' (length=3) public 'depart' => string 'sales' (length=5) 1 => object(stdClass)[zzz] public 'employee_id' => string '002' (length=3) public 'depart' => string 'accounting' (length=10) 2 => ... </code></pre> <p>このようなコレクション→オブジェクトの配列が</p> <pre><code class="php">object(Illuminate\Support\Collection)[xxx] protected 'items' => array (size=10) 0 => array (size=2) 'employee_id' => string '001' (length=3) 'depart' => string 'sales' (length=5) 1 => array (size=2) 'employee_id' => string '002' (length=3) 'depart' => string 'accounting' (length=10) ... </code></pre> <p>このようなコレクション→連想配列の配列になります。各プロパティへのアクセス等が犠牲になりますが、今回は織り込み済み。</p> <p>さらに <code>->toArray()</code> を使って</p> <pre><code class="php">$employeesCollectionArray = $employeesCollectionObject->map(function ($item, $key) { return [ 'tori_id' => $item->employee_id, 'domain' => $item->depart, ]; }); $customersArray = $employeesCollectionArray->toArray(); </code></pre> <p>こうすることで</p> <pre><code class="php">array (size=10) 0 => array (size=2) 'employee_id' => string '001' (length=3) 'depart' => string 'sales' (length=5) 1 => array (size=2) 'employee_id' => string '002' (length=3) 'depart' => string 'accounting' (length=10) ... </code></pre> <p>配列→連想配列にできました。</p> <p>今回はこれで対応。</p> <h2 id="参考"><a href="#%E5%8F%82%E8%80%83">参考</a></h2> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://techplay.jp/column/630">Laravel collectionの使い方【初心者向け】|TECH PLAY Magazine [テックプレイマガジン]</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/ucan-lab/items/47638a7b52090f59c2bf">Laravel Collection型の配列変換 toArray と all の違い - Qiita</a></li> </ul> arm-band tag:crieit.net,2005:PublicArticle/18193 2022-05-19T23:50:29+09:00 2022-05-19T23:50:29+09:00 https://crieit.net/posts/eloquent-connect-multiple-db-20220520 Eloquent で複数DBに接続する <p>単独の Eloquent を利用して異なるデータソースにアクセスしてみたのでメモしておきます。</p> <h2 id="コード"><a href="#%E3%82%B3%E3%83%BC%E3%83%89">コード</a></h2> <pre><code class="php"><?php declare(strict_types=1); use Illuminate\Database\Capsule\Manager; class DBConnection { private $db; public function __construct() { $this->db = new Manager; // default $this->db->addConnection([ 'driver' => 'mysql', 'host' => $_ENV['MYSQL1_HOST'], 'database' => $_ENV['MYSQL1_DBNAME'], 'username' => $_ENV['MYSQL1_USER'], 'password' => $_ENV['MYSQL1_PASSWORD'], 'charset' => 'utf8', ]); // second $this->db->addConnection([ 'driver' => 'mysql', 'host' => $_ENV['MYSQL2_HOST'], 'database' => $_ENV['MYSQL2_DBNAME'], 'username' => $_ENV['MYSQL2_USER'], 'password' => $_ENV['MYSQL2_PASSWORD'], 'charset' => 'utf8', ], 'second'); // addConnection() メソッドの第二引数に接続名を指定する (1つ目はなしだと default になる) $this->db->setAsGlobal(); $this->db->bootEloquent(); } // 略 } </code></pre> <p>肝はコメントにも記した通り <code>Manager</code>クラス の <code>addConnection()</code>メソッド について、第二引数に接続名を指定することです (1つ目はなしだと <code>default</code> になり、後で使用する分にも指定は不要) 。</p> <p>あ、しれっと書いていますが <code>dotenv</code> を使用した想定です。</p> <pre><code class="php"><br />$db = new DBConnection(); $secondDBrows = $db->connection('second')->table('hoge_db') ->where( /* 略 */ ) ->select( /* 略 */ ) ->get(); </code></pre> <p>こちらもしれっと書いていますがイメージとしては先程のDB接続用クラス <code>DBConnection</code> をインスタンス化して、その中から <code>connection()</code>メソッド で引数に先程指定した接続名を記述することで二つ目の接続を利用してDBにアクセスできる、ということです。</p> <p>これで意図したことを実装することができました。</p> <h2 id="参考"><a href="#%E5%8F%82%E8%80%83">参考</a></h2> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://blog.bagooon.com/?p=1492">Laravelを使わず、直接PHPからEloquentを使用し、かつ複数のDBに接続する方法。</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://technoledge.net/composer-eloquent-illuminate-database/">LaravelのORM「Eloquent」を単体で使ってスクラッチ開発する | テクナレジ</a></li> </ul> arm-band tag:crieit.net,2005:PublicArticle/18191 2022-05-18T00:03:50+09:00 2022-05-18T00:03:50+09:00 https://crieit.net/posts/eloquent-multiple-where-condition-closure-20220518 Eloquent で複合条件の抽出をする <p>Eloquent を実践的に使い始めたばかりなので初歩的なところですが、複合条件を組み立てるところについてメモ。</p> <h2 id="コード"><a href="#%E3%82%B3%E3%83%BC%E3%83%89">コード</a></h2> <p>やりたいこととしては、 <code>WHERE A AND B AND (C OR D)</code> という条件。</p> <pre><code class="php">$departName = [ '総務部', '営業部', ]; $dataRows = $dbConnect->table('hoge_db') ->where( [ ['user_id', '>', 23], ['age', '<', 42], ] ) ->where(function($query) use ($departName) { $query->orWhere('depart_name', '=', $departName[0]) ->orWhere('depart_name', '=', $departName[1]); }) ->select( 'fuga_db.name', 'fuga_db.attribute', 'fuga_db.parameter' ) ->join('fuga_db', 'hoge_db.user_id', '=', 'fuga_db.employee_id') ->get(); </code></pre> <p><code>$dbConnect</code> にDB接続情報が入ったインスタンスがあるという前提ですが、イメージとしてこのようなコードです。</p> <p>肝は以下。</p> <ul> <li><code>OR</code> 条件の括弧の中身を <code>where()</code>メソッド の中にクロージャとして無名関数で記述する。</li> <li>関数の引数はクエリ。そこに <code>orWhere()</code>メソッド を足していく。</li> <li>クロージャの外部の変数はスコープの関係で Undefined Variable になってしまうので <code>use</code>句 でクロージャ内に持ち込む</li> </ul> <p>これで意図した挙動になることを確認しました。</p> <h2 id="参考"><a href="#%E5%8F%82%E8%80%83">参考</a></h2> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/Hwoa/items/542456b63e51895f9a55">Laravel5で「.. or ...) and (..」みたいな複雑な条件を書く - Qiita</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/mitashun/items/7b1a6c4bb44acd08472e">【Laravel】EloquentでOR検索する方法 - Qiita</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://umebius.com/laravel/querybuilder%E3%81%AB%E3%82%88%E3%82%8Band%E6%A4%9C%E7%B4%A2%E3%81%A8or%E6%A4%9C%E7%B4%A2%E3%81%AE%E8%A4%87%E5%90%88/">Eloquent\/QueryBuilderによるAnd検索とOr検索の複合 - Laravel5開発</a></li> </ul> arm-band