クエリ

データベースから指定した条件に一致するデータを取得する機能です。 コンテンツ(ページ・コレクション・モジュール・カレンダー)に登録したデータはデータベース管理システムに保存されています。 設定ファイルに条件を指定することで、その条件に一致するデータをデータベース管理システムから取り出すことができます。 特定のカテゴリや任意で定義したお知らせタイプ毎に一覧を作成するなどさまざまな用途で利用できます。

PHPでクエリクラスを作成してEloquent(DB操作ライブラリ)を直接利用することも可能です。

クエリ設定

クエリの設定ファイルは system/config/query.php です。 この設定ファイルはPHPの配列で定義されます。配列のキーがクエリ名になります。

設定ファイルのフォーマットと設定項目について説明します。
設定ファイルフォーマット:

<?php

return [
    'クエリ名' => [
        // クエリの設定項目
    ],
    // ... 以降のクエリ設定
];

クエリの設定項目

項目 説明
base_type collection ベースタイプ(page, collection, module, calendar)のいずれかを指定します。各ベースタイプでユニークなコンテンツタイプの場合は省略可能です。
type store コンテンツタイプを指定します。
category 1 カテゴリIDを指定します。配列にして複数のカテゴリIDを指定することもできます。
dir /company/ ページコンテンツの場合に、パスのディレクトリを指定できます。一致したディレクトリ配下のコンテンツは全て対象になります。(先頭一致でパターンマッチングされます)
filename index ページコンテンツの場合に、ファイルに一致するコンテンツを指定できます。配列で複数のファイル名を指定することもできます。
exclude_filename index ページコンテンツの場合に、ファイルに一致しないコンテンツを指定できます。配列で複数のファイル名を指定することもできます。
join
['recommend']
メタ保存したキー名を指定すると、そのキー名を条件にメタ保存テーブルが結合(join)されます。その際にキー名がエイリアス名となります。結合したテーブルは where で絞り込むことができます。 たとえば、recommend というキー名でメタ保存していた場合に ['recommend'] を指定すると、メタ保存テーブルの name カラム が recommend という条件で inner join されます。その際に recommend というエイリアスが付けられます。メタ保存テーブルの value カラムで絞り込みたい場合は、recommend.value というカラム名で条件を指定できます。
where
'where' => [
    ['display_order', '<=', 5],
],
and 条件
and (A = 1 and B = 1) という条件を where に追加します。
'where' => [
    ['A', 1],
    ['B', 1],
],
or 条件
and (A = 1 or B = 1) という条件を where に追加します。
'where' => [
    ['A', 1],
    'or',
    ['B', 1],
],
() 指定
and (A = 1 or (B > 10 and B < 20)) という条件を where に追加します。
'where' => [
    ['A', 1],
    'or',
    [
        ['B', '>', 10],
        ['c', '<', 20],
    ],
],
where 条件を指定できます。

複数の条件を指定するとそれぞれを and で結合したクエリを作成します。 or 条件で組み合わせたい場合は、'or', を指定します。 SQLとして () で囲いたい場合はPHP側で配列をネストさせることで可能になります。 他の条件(公開条件)と or にならないように、where設定で指定した箇所全体が and () で囲われることになります。

末端の配列に条件を指定します。配列の一つ目にカラム名を指定します。 配列の2つ目に条件(=, >, <, >=, <=, <>, like)を指定します。条件を省略した場合は一致するという条件になります。 配列の3つ目に比較する値を指定します。

meta
'meta' => [
    ['title', 'test'],
    ['color', 'red'],
],
メタ保存したデータを保存キーと値で絞り込みます。whereの条件は and_or になります。 join と where でも同様のことができますが単純にメタ保存データで絞り込みたい場合はこちらのほうが簡単に指定できます。
order pref.value 並べ替え対象カラムを指定します。
sort desc 並べ替え順をしていします。昇順の場合は asc を指定します。降順の場合は desc を指定します。省略した場合のデフォルトは asc です。
extra_order
'extra_order' => [
    'display_order' => 'asc',
],
追加の order sort 設定を配列で設定します。
offset 3 取得するレコードのオフセットを指定します。
limit 15 取得するレコード数を指定します。
class Stores クエリクラスを利用する場合はクラス名を指定します。

設定例1:

    'store_list' => [
        'type' => 'store',
        'base_type' => 'collection',
        'join' => [
            'pref',
        ],
        'order' => 'pref.value',
        'extra_order' => [
            'display_order' => 'asc',
        ],
    ],

設定例2:

    'product_recommend' => [
        'type' => 'product_item',
        'base_type' => 'page',
        'join' => [
            'recommend',
        ],
        'where' => [
            ['recommend.value', '>=', 0],
        ],
        'order' => 'recommend.value',
        'limit' => 5,
    ],

クエリを利用する

クエリ設定ファイルに定義したクエリを利用したい場合にはテンプレートで query() 関数を使用します。

次のように query() 関数の引数にクエリ設定ファイルに定義したクエリ名を指定して実行すると、そのクエリ結果を取得することができます。
例:

{% set recommend = query('product_recommend') %}

クエリパラメータ

クエリ実行時にパラメータを渡すことも可能です。

パラメータを渡したい場合には、クエリ設定ファイルに波括弧 {} を用いたプレースホルダを用意します。
例:

    'pages_in_category' => [
        'base_type' => 'page',
        'category' => '{id}',
    ],

テンプレートでは query() 関数の第2引数に配列でプレースホルダ名と割り当てる値を指定します。
例:

{% for item in query('pages_in_category', {'id': 1}) %}
  <li><a href="{{ item.path }}">{{ item.name }}</a></li>
{% endfor %}

※ プレースホルダ名を示す場合には {} は不要です。

パラメータが1つの場合は次のように Twig の配列ではなく値を直接指定できます。
通常:query('pages_in_category', {'id': 1})
省略:query('pages_in_category', 1)

クエリを活用する

クエリの結果は Laravel の Illuminate\Support\Collection という配列データを操作するためのクラスを継承したオブジェクトで返されるため、その機能を活用することができます。 Laravel の Collection については次のドキュメントが参考になります。
コレクション 6.0 Laravel https://readouble.com/laravel/6.x/ja/collections.html
※ コレクションコンテンツと区別するため、本ドキュメントでは Laravel の コレクション は「配列操作コレクション」と記す場合があります。

配列操作コレクションの groupBy メソッドを活用する例を紹介します。 店舗リストをコレクションコンテンツで管理していて、都道府県別に見出しなどのHTMLの構造を調整して出力したい場合の例です。 コレクションコンテンツは、都道府県選択セレクトボックスがあり、選択した値として都道府県コードを保持しています。

クエリ設定例:

    'store_list' => [
        'type' => 'store',
        'base_type' => 'collection',
        'join' => [
            'pref',
        ],
        'order' => 'pref.value',
        'extra_order' => [
            'display_order' => 'asc',
        ],
    ],

テンプレートの例:

{% set pref_code = table('pref_code') %}
{% for code, pref in query('store_list').groupBy('fields.pref.select') %}
<h3>{{ pref_code[code] }}</h3>
<table class="table table-bordered">
  <thead>
  <tr>
    <th>店舗名</th>
    <th>住所 / 電話番号</th>
    <th>営業時間</th>
    <th>お知らせ</th>
  </tr>
  </thead>
  <tbody>
  {% for store in pref %}
  <tr>
    <td><a href="{{ url_for('store_detail', {'store_code': store.fields.store_code.text}) }}">{{ store.name }}</a></td>
    <td>
      {{ field('address', store) }}<br>
      電話番号:{{ field('tel', store) }}
    </td>
    <td>{{ field('hours', store) }}</td>
    <td>{{ field('information', store) }}</td>
  </tr>
  {% endfor %}
  </tbody>
</table>
{% endfor %}

この例では、 query('store_list').groupBy('fields.pref.select') のように query()関数に続けて groupBy() メソッドを実行している。 groupBy() の引数の fields.pref.select の値でグループ化されたデータを利用できます。

この例では、都道府県コードと都道府県名を対応させるテーブルコンテンツを別途用意して、table('pref_code') で利用しています。

クエリクラス

クエリ機能は設定ファイルにクエリの条件を指定して利用するということが基本になりますが、PHPでクエリ用のクラスを作成してその中でEloquent(DB操作ライブラリ)を利用するコードを自由に記述することができます。

クエリクラスは system/app/Queries/ ディレクトリに任意のファイル名のPHPファイルを用意します。 クエリ設定ファイルでは、class 項目のみを指定します。これにより、他のクエリと同様にテンプレートから呼び出して利用できるようになります。

クエリクラスの例:system/app/Queries/Stores.php
<?php

namespace App\Queries;

use MicroEngine\Core\Queries\Query;
use MicroEngine\Cms\Models\Collection;

class Stores extends Query
{
    /**
     * @param array $config
     * @param array $params
     * @return array
     */
    public function __invoke(array $config, array $params = [])
    {
        $data = Collection::where('type', 'store')->where('name', 'like', '%' . $params['shop'] . '%')->get();

        return $data;
    }
}
設定例:query.php
    'stores' => [
        'class' => 'Stores',
    ],
テンプレートで利用する例:
{% for store in query('stores', {'shop': '木'}) %}
  <h4>{{ store.name }}</h4>
{% endfor %}