1

I have an API endpoint set up for a category group. This currently provides some details of all entries that have been assigned that category (i.e. related entries). That works well for some high level details, but I now need to add support for a Matrix field that those related entries contain. Here's the current setup:

'series.json' => function() {
            return [
                'elementType' => Category::class,
                'criteria' => ['group' => 'series'],
                'paginate' => false,
                'transformer' => function(Category $entry) {
                    $entries = Entry::find()
                        ->relatedTo($entry)
                        ->select(['slug','title','field_rating AS rating','field_pageCopy AS desc','postDate AS date'])
                        ->asArray()
                        ->all();

                    $typeArray = array_map('strval', $entry->mediaType->all());

                    return [
                        'id' => $entry->id,
                        'slug' => $entry->slug,
                        'title' => $entry->title,
                        'type' => strtolower($typeArray[0]),
                        'desc' => $entry->blurb,
                        'entries' => $entries
                    ];
                }
            ];
        }

However, if I try to add the Matrix field to the select() argument it doesn't work. If I remove select() I can see why: it isn't a listed field. If I remove asArray() then I can see all the relevant fields, but I can't limit the ones available, which is undesirable as it exposes a lot of excess information.

I feel like their might be a better way to format my transformer to begin with, but I'm at a bit of a loss when it comes to the docs.

1 Answer 1

1

I've found a workaround for now. It's not ideal and I feel like it will probably be too intensive at scale but, for my uses, it will work.

Rather than using select() to reduce the data being returned from the initial query, I'm simply returning everything:

$related = Entry::find()
   ->relatedTo($entry)
   ->all();

I'm then looping over the returned object using foreach(), within which I'm dealing with the Matrix blocks in a seperate foreach(). At both levels I just pass back the data I want, something like this:

$reviews = [];
foreach ($related as $relatedEntry) {

   // Condense matrix blocks
   $critiques = [];

   foreach($relatedEntry->critique as $block) {
      $critiques[] = array(
         'title' => $block->seriesTitle,
         'copy' => $block->review,
         'date' => $block->date,
         'viewCount' => $viewCount,
      );
   }

   $reviews[] = [
      'id' => $relatedEntry->id,
      'slug' => $relatedEntry->slug,
      'title' => $relatedEntry->title,
      'critiques' => $critiques,
   ];
};

The output $reviews[] array is therefore equivalent to what I was doing with select() but not contains subarrays of my matrix field. Incidentally, I have managed to nest that one further with a SuperTable field within a matrix field. It needed another nested foreach() but it worked easily enough.

Once you have all of that, you can just pass it back to the endpoint like normal, so the whole thing (with above sections of code collapsed) looks like this:

'api.json' => function() {
   return [
      'elementType' => Category::class,
      'criteria' => ['group' => 'series'],
      'paginate' => false,
      'transformer' => function(Category $entry) {
         $related = Entry::find()
            ->relatedTo($entry)
            ->all();

         // Loop over related entries to extract just the information wanted
         $reviews = [];
         foreach ($related as $relatedEntry) {
            {...}   
         };

         return [
            'id' => $entry->id,
            'slug' => $entry->slug,
            'title' => $entry->title,
            'reviews' => $reviews,
         ];
      }
   ];
}

As I say, not ideal so I'm leaving this unanswered. If anyone has a more elegant solution I'd love to know.

1
  • It's been four years, so I'm marking this as the answer for now. Still open to better options. Commented May 15 at 10:59

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.