Skip to content

Instantly share code, notes, and snippets.

@geoidesic
Created August 3, 2020 09:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save geoidesic/2fe50b47e4aefad16a57a7bb044b9b02 to your computer and use it in GitHub Desktop.
Save geoidesic/2fe50b47e4aefad16a57a7bb044b9b02 to your computer and use it in GitHub Desktop.
Adds actions to your `crud-json-api` controller to handle POST and PATCH relationships requests.
<?php
namespace App\Traits;
use Cake\Utility\Inflector;
use Cake\Utility\Hash;
trait CrudJsonApiControllerTrait
{
/**
* related method
* NB: requires a route matcher: $routes->connect('/{relation}/{id}/<table_name>', ['controller' => 'model_name', 'action' => 'related'], ['id' => '\d+', 'pass' => ['id', 'relation']]);
* @return \Cake\Http\Response|null
*
*/
public function index()
{
$input_line = $this->request->getParam('_matchedRoute');
preg_match('/\/([[a-zA-Z]*)\/]*:([a-zA-Z]*_id)\/[a-zA-Z]*/', $input_line, $output_array);
if (!empty($output_array)) {
$this->Crud->on('beforePaginate', function (\Cake\Event\Event $event) use ($output_array) {
$event->getSubject()->query
->innerJoinWith(ucfirst($output_array[1]))
->where([ucfirst($output_array[1]) . '.id' => $this->request->getParam($output_array[2])]);
$event->getSubject()->query->first();
});
}
return parent::index();
}
/**
* JSONAPI spec for POST relationships is enabled here via `beforeFind` and `beforeSave` hooks.
* @todo: this would probably be better as a custom Action (https://github.com/FriendsOfCake/crud-json-api/issues/118)
*/
public function postrelationships()
{
$request = $this->request;
$id = $request->getParam('id');
$foreignTableName = $request->getParam('foreignTableName');
$data = $request->getData();
$requestMethod = $request->getMethod();
$this->Crud->on('beforeFind', function (\Cake\Event\Event $event) use ($data, $foreignTableName, $requestMethod) {
$query = $event->getSubject()->query;
$query->contain(['Dishes']);
});
$this->Crud->on('afterFind', function (\Cake\Event\Event $event) use ($data, $foreignTableName, $requestMethod) {
$entity = $event->getSubject()->entity;
});
// ensure that only adds new relationships, doesn't destroy old ones
$this->Crud->on('beforeSave', function (\Cake\Event\Event $event) use ($id, $data, $foreignTableName) {
$entity = $event->getSubject()->entity;
$entity->$foreignTableName = empty($entity->$foreignTableName) ? [] : $entity->$foreignTableName;
$ids = Hash::extract($entity->$foreignTableName, '{n}.id');
foreach ($data['data'] as $key => $recordAttributes) {
// get the related record
$foreignTable = $this->getTableLocator()->get(Inflector::camelize($foreignTableName));
$foreignKey = $foreignTableName . '.id';
$query = $foreignTable->findAllById($recordAttributes['id']);
$foreignRecord = $query->first();
// push it onto the relationsships array
if (!empty($foreignRecord)) {
if (in_array($foreignRecord->id, $ids)) {
// don't add id's that are already added
} else {
array_push($entity->$foreignTableName, $foreignRecord);
}
}
}
});
return parent::edit($id);
}
/**
* @todo: this would probably be better as a custom Action (https://github.com/FriendsOfCake/crud-json-api/issues/117)
*/
public function updaterelationships()
{
$request = $this->request;
$id = $request->getParam('id');
$foreignTableName = $request->getParam('foreignTableName');
$data = $request->getData();
$this->Crud->on('beforeSave', function (\Cake\Event\Event $event) use ($data, $foreignTableName) {
// Allow all relationships to be removed, as per 1.0 JSONAPI spec https://jsonapi.org/format/#crud-updating-to-many-relationships
$entity = $event->getSubject()->entity;
if (empty((array)$data['data'])) {
$entity->$foreignTableName = [];
} else {
$entity->$foreignTableName = [];
foreach ($data['data'] as $key => $recordAttributes) {
// get the related record
$foreignTable = $this->getTableLocator()->get(Inflector::camelize($foreignTableName));
$foreignKey = $foreignTableName . '.id';
$query = $foreignTable->findAllById($recordAttributes['id']);
$foreignRecord = $query->first();
// push it onto the relationsships array if it exists
if (!empty($foreignRecord)) {
array_push($entity->$foreignTableName, $foreignRecord);
}
}
}
});
return parent::edit($id);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment