リレーション

Craft は、5つの関連フィールドタイプを持つ、エレメントを互いに関連付けるための強力なエンジンを持っています。

他のフィールドタイプと同様に、これらをセクションユーザーアセットカテゴリグループタググループ、および、グローバル設定のフィールドレイアウトに追加できます。

# 専門用語

それぞれのリレーションは、ソースターゲット と呼ぶ、2つの要素で構成されています。

  • ソースは、他のエレメントが選択される関連フィールドを持っています。
  • ターゲットエレメントは、ソースによって選択されたものです。

エントリフィールドのリレーションとしてそれぞれの原材料を選択する、ドリンクレシピのエントリがあるとします。

次のように設定します。

  1. フィールドタイプ「エントリ」を使用する新しいフィールドを作成し、名前を「原材料」とします。
  2. 利用可能なソースエレメントから「原材料」をチェックして、そこに含まれるエントリだけがオプションで選択できるようにします。
  3. レシピごとに必要とする多くの原材料を選択できるよう、「リミット」欄を空白のままにします。

これで、それぞれのドリンクエントリに新しい「原材料」フィールドから原材料を割り当てることができます。

エントリで複数の原材料を選択することで、レシピをソース、原材料をターゲットとして、いくつかのリレーションシップを作成します。

# テンプレート記法

リレーションフィールドをセットアップすると、テンプレート内で関連するエレメントを出力するためのオプションを見ることができます。

# ソースエレメントを経由したターゲットエレメントの取得

「ドリンク」エントリを出力している以下の例のように、すでにテンプレート内でソースエレメントを保持している場合、他のフィールドの値にアクセスするのと同じ方法、すなわちハンドルによって、特定のフィールドのターゲットエレメントにアクセスできます。

ソースの関連フィールドのハンドル(ingredients)を呼び出すと、そのフィールドのターゲットエレメントをフィールドに定義された順序で出力できるエレメントクエリが返ります。

ドリンクレシピの原材料リストを出力したい場合、次のようにします。

{% if drink.ingredients|length %}

    <h3>Ingredients</h3>

    <ul>
        {% for ingredient in drink.ingredients %}
            <li>{{ ingredient.title }}</li>
        {% endfor %}
    </ul>

{% endif %}

エレメントタイプでサポートされている追加パラメータを付加することもできます。

{% for ingredient in drink.ingredients.section('ingredients') %}
    <li>{{ ingredient.title }}</li>
{% endfor %}

# relatedTo パラメータ

アセット、カテゴリ、エントリ、ユーザー、および、タグは、それぞれ relatedTo パラメータをサポートし、あらゆる種類のとんでもないことを可能にします。

次のうちの1つを渡すことができます。

  • 単一のエレメントオブジェクトcraft\elements\Assetcraft\elements\Categorycraft\elements\Entrycraft\elements\User、または、craft\elements\Tag
  • 単一のエレメント ID
  • 以下ようなプロパティを持つハッシュelement、オプションで field、および / または、sourceSite を持つ sourceElement または targetElement
  • 上記のオプションの任意の組み合わせを含む配列いくつかの エレメントではなく、すべてのエレメントのリレーションの場合は and ではじめることができます。(デフォルトの振る舞いは or で、省略したり明示的に渡せます)

# シンプルなリレーションシップ

シンプルなクエリは、drink で表される drinks セクションのエントリのような、単一エレメントのオブジェクトや ID を渡すことです。

{% set relatedDrinks = craft.entries()
    .section('drinks')
    .relatedTo(drink)
    .all() %}
{# result: drinks entries with *any* relationship to `drink` (source or target) #}

エレメントの配列を渡すと、指定されたアイテムのいずれかに関連する結果を返します。

{% set relatedDrinks = craft.entries()
    .section('drinks')
    .relatedTo([ gin, lime ])
    .all() %}
{# result: drinks entries with any relationship to `gin` or `lime` #}

配列の最初に and を渡すと、指定されたアイテムの すべて に関連する結果を返します。

{% set relatedDrinks = craft.entries()
    .section('drinks')
    .relatedTo([ 'and', gin, lime ])
    .all() %}
{# result: drinks entries with any relationship to `gin` and `lime` #}

# 高度なリレーションシップ

次のプロパティを含むハッシュrelatedTo に渡すことで、より具体的なクエリを実行できます。

プロパティ 受け入れる値 説明
elementsourceElement、または、targetElement エレメント ID、エレメント、エレメントクエリ、または、それらのいずれかを持つ配列。 ソース または ターゲットの関連性は element、提供されるものがソースである関連性は sourceElement、または、提供されるものがソースである関連性は targetElement
field(オプション) フィールドハンドル、フィールド ID、または、それらのいずれかを含む配列。 指定したフィールドによって作成されたリレーションにスコープを制限します。
sourceSite(オプション) サイトオブジェクト、サイト ID、または、サイトハンドル。 指定したサイトによって作成されたリレーションにスコープを制限します。

翻訳可能なリレーションフィールドとしてデザインされている場合のみ、sourceSite を利用してください。

これは drink.ingredients.all() の呼び出しと同等です。

{% set ingredients = craft.entries()
    .section('ingredients')
    .relatedTo({
        sourceElement: drink,
        field: 'ingredients'
    })
    .all() %}
{# result: ingredients entries related from `drink`’s custom `ingredients` field #}

これは特定のフィールドを制限しませんが、現在のサイトとのリレーションに制限しています。

{% set ingredients = craft.entries()
    .section('ingredients')
    .relatedTo({
        sourceElement: drink,
        sourceSite: craft.app.sites.currentSite.id
    })
    .all() %}
{# result: ingredients entries related from `drink`, limited to the current site #}

これは現在の原材料を主成分とするドリンクを探します。

{% set moreDrinks = craft.entries()
    .section('drinks')
    .relatedTo({
        targetElement: drink.ingredients.one(),
        field: 'ingredients'
    })
    .all() %}
{# result: other drinks using `drink`’s first ingredient #}

# 行列を経由する

行列フィールド内のソースエレメントに関連するエレメントを見つけたい場合、行列フィールドのハンドルを field パラメータに渡します。複数の関連フィールドを持つ行列フィールドにある特定のフィールドだけをターゲットにしたい場合、ドット表記を利用してブロックタイプのフィールドハンドルを指定できます。

{% set ingredients = craft.entries()
    .section('ingredients')
    .relatedTo({
        sourceElement: drink,
        field: 'ingredientsMatrix.relatedIngredient'
    })
    .all() %}

# 複数のリレーションの判定基準を渡す

複数のタイプのリレーションを組み合わせる必要がある場合があります。例えば、エスプレッソを含む現在のユーザーのお気に入りのドリンクをすべて出力するには、次のようになります。

{% set espresso = craft.entries()
    .section('ingredients')
    .slug('espresso')
    .one() %}

{% set cocktails = craft.entries()
    .section('drinks')
    .relatedTo([
        'and',
        { sourceElement: currentUser, field: 'favoriteDrinks' },
        { targetElement: espresso, field: 'ingredients' }
    ])
    .all() %}
{# result: current user’s favorite espresso drinks #}

または、現在の原材料を主成分とするユーザーのお気に入りのドリンクを探すために、エレメントクエリを渡したいことでしょう。

{% set otherUsers = craft.users()
    .not(currentUser)
    .all() %}

{% set recommendedCocktails = craft.entries()
    .section('drinks')
    .relatedTo([
        'and',
        { sourceElement: otherUsers, field: 'favoriteDrinks' },
        { targetElement: drink.ingredients.one(), field: 'ingredients' }
    ])
    .all() %}
{# result: other users’ favorite drinks that use `drink`’s first ingredient #}