I need to sort the entries for an Element API endpoint by a value calculated in a custom transformer. Is this possible?
The use case is this: We're dealing with Events/Courses that have multiple instances (sessions) that each may contain multiple dates. I have a Neo field called sessions
with session
blocks that contain date
sub-blocks. The session
block contains registrationLink
and location
, and each date
block contains the fields date
, startTime
, and endTime
.
However, these need to be sorted by nearest session date (the user could input the sessions/dates in any order), so I need to determine the nearest upcoming session by looking through all the sessions and finding the first date for that session. We also don't want to show sessions that have already passed. I wasn't able to figure out how to do this in Twig, so I thought it might be easier in Element API. I've got the transformer working, so I can get output like this:
{
"entries": [
{
"title": "TITLE REMOVED",
"url": "URL REMOVED",
"nextSessionStart": "2017-08-09",
"sessions": [
{
"location": "LOCATION REMOVED",
"registrationLink": "URL REMOVED",
"dates": [
{
"date": "2017-08-09",
"startTime": "8:30AM",
"endTime": "4:30PM"
},
{
"date": "2017-08-10",
"startTime": "8:30AM",
"endTime": "4:30PM"
}
]
},
{
"location": "LOCATION REMOVED",
"registrationLink": "URL REMOVED",
"dates": [
{
"date": "2017-11-02",
"startTime": "8:30AM",
"endTime": "4:30PM"
},
{
"date": "2017-11-03",
"startTime": "8:30AM",
"endTime": "4:30PM"
}
]
},
{
"location": "LOCATION REMOVED",
"registrationLink": "URL REMOVED",
"dates": [
{
"date": "2018-02-06",
"startTime": "8:30AM",
"endTime": "4:30PM"
},
{
"date": "2018-02-07",
"startTime": "8:30AM",
"endTime": "4:30PM"
}
]
}
]
},
{
"title": "TITLE REMOVED",
"url": "URL REMOVED",
"nextSessionStart": "2018-07-07",
"sessions": [
{
"location": "LOCATION REMOVED",
"registrationLink": "URL REMOVED",
"dates": [
{
"date": "2018-07-07",
"startTime": "5:30PM",
"endTime": "8:30PM"
},
{
"date": "2018-08-07",
"startTime": "8:30AM",
"endTime": "4:30PM"
}
]
}
]
},
{
"title": "TITLE REMOVED",
"url": "URL REMOVED",
"nextSessionStart": "2017-07-11",
"sessions": [
{
"location": "LOCATION REMOVED",
"registrationLink": "URL REMOVED",
"dates": [
{
"date": "2017-12-05",
"startTime": "8:30AM",
"endTime": "4:30PM"
}
]
},
{
"location": "LOCATION REMOVED",
"registrationLink": "URL REMOVED",
"dates": [
{
"date": "2017-07-11",
"startTime": "8:30AM",
"endTime": "4:30PM"
}
]
},
{
"location": "LOCATION REMOVED",
"registrationLink": "URL REMOVED",
"dates": [
{
"date": "2017-10-25",
"startTime": "8:30AM",
"endTime": "4:30PM"
}
]
}
]
}
],
"meta": {
"pagination": {
"total": 3,
"count": 3,
"per_page": 10,
"current_page": 1,
"total_pages": 1,
"links": [
]
}
}
}
The problem is that I need to sort and paginate the results based on that nextSessionStart key.
Here's the elementapi.php config file:
return [
'defaults' => [
'elementType' => ElementType::Entry,
'elementsPerPage' => 10,
'pageParam' => 'pg',
'resourceKey' => 'entries'
],
'endpoints' => [
'courses.json' => function() {
require craft()->path->getConfigPath().'elementapi/CoursesTransformer.php';
return [
'criteria' => [
'section' => ['courses'],
'order' => 'nextSessionStart asc' //NOTE: this doesn't work and needs to be removed to get the above output
],
'transformer' => new CoursesTransformer()
];
}
]
];
The transformer looks like this:
class CoursesTransformer extends TransformerAbstract {
public function transform (EntryModel $entry) {
$next_session_start = null;
$sessions = array();
$now = date('Y-m-d');
foreach ($entry->sessions as $session) {
if ($session->level == 1) {
$this_session = array(
'location' => $session->location,
'registrationLink' => $session->registrationLink,
'dates' => array()
);
foreach ($session->children as $date) {
$this_date = $date->date;
array_push($this_session['dates'], array(
'date' => date_format($this_date, 'Y-m-d'),
'startTime' => date_format($date->startTime, 'g:iA'),
'endTime' => date_format($date->endTime, 'g:iA')
));
if ($this_date > $now && (is_null($next_session_start) || $this_date < $next_session_start)) {
$next_session_start = $this_date;
}
}
array_push($sessions, $this_session);
}
}
return [
'title' => $entry->title,
'url' => $entry->url,
'nextSessionStart' => date_format(new DateTime($next_session_start), 'Y-m-d'),
'sessions' => $sessions
];
}
}
Any information about how I can resort based on the transformer output would be really appreciated. This project is sort of at a standstill until I can figure out how to sort these courses and events based on their next upcoming date.