craftcms / element-api

Create a JSON API/Feed for your elements in Craft.
MIT License
498 stars 56 forks source link

Question: How to fetch entries based on their matrix field value? #87

Closed stigzelm closed 4 years ago

stigzelm commented 5 years ago

I am using element api for craft 3.

I am trying to return all the entries that have a matrix field with a block that has a textfield with a specific handle and value.

Example: I have entries ("Shows") that have the matrix field called "Presentations". That matrix field has a block called "presentation". This block has a text field called "date". I want to fetch all the entries with "Presentations" that have the field called "date" with the value "12.12.2018".

How should I write the endpoint for this kind of result? I guess I would have to add it to the criteria, but I don't know how to do it when it is a matrix field. is this even possible?

mattandrews commented 5 years ago

As far as I know you can't filter on matrix field content in the criteria, but maybe in your transformer you could check for the field's presence/status, and output a flag for each piece of content saying valid: true or similar (and then filter those out after you've called the API)? Not ideal, but not sure there's an alternative.

brandonkelly commented 4 years ago

You’d have to search for the Matrix blocks first, then have criteria set to their owner entry IDs.

Here’s how you’d do it, assuming the date is supplied as part of the endpoint URI:

use craft\elements\Entry;
use craft\elements\MatrixBlock;
use craft\helpers\DateTimeHelper;
use yii\web\NotFoundHttpException;

'your/endpoint/pattern/<date:.*>' => function(string $date) {
    // Make sure a valid date was provided
    $date = DateTimeHelper::toDateTime($date);
    if (!$date) {
        throw new NotFoundHttpException();
    }

    // Get the Matrix field
    $matrixField = Craft::$app->fields->getFieldByHandle('yourMatrixFieldHandle');

    // Get the Matrix blocks’ owner IDs
    $ownerIds = MatrixBlock::find()
        ->select(['matrixblocks.ownerId'])
        ->distinct()
        ->asArray()
        ->fieldId($matrixField->id)
        ->yourDateFieldHandle($date)
        ->column();

    return [
        'elementType' => Entry::class,
        'criteria' => [
            'id' => $ownerIds ?: false,
            // ...
        ],
        // ...
    ];
},