5

I have a structure called "locations" that contains two entry types:

  • State
  • Location

I'd like to access specific states at the URL locations/ny.json, for example, and get a JSON object with all the location entries nested under that state.

The entries are already properly nested for HTML output, but I'm trying to get the JSON to match.

This is my elementsapi.php file right now:

<?php
namespace Craft;

return [
  'endpoints' => [
    'locations.json' => [
      'elementType' => 'Entry',
      'criteria' => [
        'section' => 'locations',
        'type' => 'location'
      ],
      'transformer' => function(EntryModel $entry) {
        return [
          'title' => $entry->title,
          'url' => $entry->url,
          'latitude' => $entry->latitude,
          'longitude' => $entry->longitude,
          'jsonUrl' => UrlHelper::getUrl("locations/{$entry->id}.json")
        ];
      },
    ],
    'locations/<slug:{slug}>.json' => function($slug) {
      return [
        'elementType' => 'Entry',
        'criteria' => [
          'section' => 'locations',
          'type' => 'state',
          'slug' => $slug
        ],
        'transformer' => function(EntryModel $entry) {
          return [
            'title' => $entry->title,
            'url' => $entry->url,
            'latitude' => $entry->latitude,
            'longitude' => $entry->longitude,
            'jsonUrl' => UrlHelper::getUrl("locations/{$entry->id}.json")
          ];
        },
      ];
    },
  ]
];

The second endpoint is currently returning a single state entry, but I would like it to return all locations that are a descendant of that state.

Is this possible using a criteria param such as descendantOf? What criteria params are available?

6

The $entry variable that is passed to your endpoint’s transformer function will be an EntryModel object - the same type of object you use when interacting with entries in your templates. So everything you can do in your templates you can also do from this function.

The easiest way to get a Structure section entry’s children is with the getChildren() function, which will actually give you a new ElementCriteriaModel object with the descendantOf and descendantDist params pre-set for you. So here’s what your transformer function might look like:

'transformer' => function(EntryModel $state) {
  $locations = $state->getChildren()->type('location')->find();
  $locationsInfo = [];

  foreach ($locations as $location) {
    $locationsInfo[] = [
      'title' => $location->title,
      'url' => $location->url,
      // ...
    ];
  }

  return [
    'title' => $state->title,
    'url' => $state->url,
    'latitude' => $state->latitude,
    'longitude' => $state->longitude,
    'jsonUrl' => UrlHelper::getUrl("locations/{$state->id}.json"),
    'locations' => $locationsInfo
  ];
},

(Since you’re dealing with multiple entries within your transformer function, I also went ahead and renamed $entry to $state, just so it didn’t get confusing.)

  • This worked great and makes a lot of sense to structure it that way. Thanks! – coryetzkorn Aug 20 '15 at 19:26

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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