307 lines
8.4 KiB
Twig
307 lines
8.4 KiB
Twig
<?php
|
|
|
|
namespace Drupal\{{ machine_name }}\Plugin\rest\resource;
|
|
|
|
use Drupal\Component\Plugin\DependentPluginInterface;
|
|
use Drupal\Core\Database\Connection;
|
|
use Drupal\rest\ModifiedResourceResponse;
|
|
use Drupal\rest\Plugin\ResourceBase;
|
|
use Drupal\rest\ResourceResponse;
|
|
use Psr\Log\LoggerInterface;
|
|
use Symfony\Component\DependencyInjection\ContainerInterface;
|
|
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
|
|
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
|
|
|
/**
|
|
* Represents {{ plugin_label }} records as resources.
|
|
*
|
|
* @RestResource (
|
|
* id = "{{ plugin_id }}",
|
|
* label = @Translation("{{ plugin_label }}"),
|
|
* uri_paths = {
|
|
* "canonical" = "/api/{{ plugin_id|u2h }}/{id}",
|
|
* "https://www.drupal.org/link-relations/create" = "/api/{{ plugin_id|u2h }}"
|
|
* }
|
|
* )
|
|
*
|
|
* @DCG
|
|
* This plugin exposes database records as REST resources. In order to enable it
|
|
* import the resource configuration into active configuration storage. You may
|
|
* find an example of such configuration in the following file:
|
|
* core/modules/rest/config/optional/rest.resource.entity.node.yml.
|
|
* Alternatively you can make use of REST UI module.
|
|
* @see https://www.drupal.org/project/restui
|
|
* For accessing Drupal entities through REST interface use
|
|
* \Drupal\rest\Plugin\rest\resource\EntityResource plugin.
|
|
*/
|
|
class {{ class }} extends ResourceBase implements DependentPluginInterface {
|
|
|
|
/**
|
|
* The database connection.
|
|
*
|
|
* @var \Drupal\Core\Database\Connection
|
|
*/
|
|
protected $dbConnection;
|
|
|
|
/**
|
|
* Constructs a Drupal\rest\Plugin\rest\resource\EntityResource object.
|
|
*
|
|
* @param array $configuration
|
|
* A configuration array containing information about the plugin instance.
|
|
* @param string $plugin_id
|
|
* The plugin_id for the plugin instance.
|
|
* @param mixed $plugin_definition
|
|
* The plugin implementation definition.
|
|
* @param array $serializer_formats
|
|
* The available serialization formats.
|
|
* @param \Psr\Log\LoggerInterface $logger
|
|
* A logger instance.
|
|
* @param \Drupal\Core\Database\Connection $db_connection
|
|
* The database connection.
|
|
*/
|
|
public function __construct(array $configuration, $plugin_id, $plugin_definition, array $serializer_formats, LoggerInterface $logger, Connection $db_connection) {
|
|
parent::__construct($configuration, $plugin_id, $plugin_definition, $serializer_formats, $logger);
|
|
$this->dbConnection = $db_connection;
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*/
|
|
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
|
|
return new static(
|
|
$configuration,
|
|
$plugin_id,
|
|
$plugin_definition,
|
|
$container->getParameter('serializer.formats'),
|
|
$container->get('logger.factory')->get('rest'),
|
|
$container->get('database')
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Responds to GET requests.
|
|
*
|
|
* @param int $id
|
|
* The ID of the record.
|
|
*
|
|
* @return \Drupal\rest\ResourceResponse
|
|
* The response containing the record.
|
|
*
|
|
* @throws \Symfony\Component\HttpKernel\Exception\HttpException
|
|
*/
|
|
public function get($id) {
|
|
return new ResourceResponse($this->loadRecord($id));
|
|
}
|
|
|
|
/**
|
|
* Responds to POST requests and saves the new record.
|
|
*
|
|
* @param mixed $record
|
|
* Data to write into the database.
|
|
*
|
|
* @return \Drupal\rest\ModifiedResourceResponse
|
|
* The HTTP response object.
|
|
*/
|
|
public function post($record) {
|
|
|
|
$this->validate($record);
|
|
|
|
$id = $this->dbConnection->insert('{{ plugin_id }}')
|
|
->fields($record)
|
|
->execute();
|
|
|
|
$this->logger->notice('New {{ plugin_label|lower }} record has been created.');
|
|
|
|
$created_record = $this->loadRecord($id);
|
|
|
|
// Return the newly created record in the response body.
|
|
return new ModifiedResourceResponse($created_record, 201);
|
|
}
|
|
|
|
/**
|
|
* Responds to entity PATCH requests.
|
|
*
|
|
* @param int $id
|
|
* The ID of the record.
|
|
* @param mixed $record
|
|
* Data to write into the database.
|
|
*
|
|
* @return \Drupal\rest\ModifiedResourceResponse
|
|
* The HTTP response object.
|
|
*/
|
|
public function patch($id, $record) {
|
|
$this->validate($record);
|
|
return $this->updateRecord($id, $record);
|
|
}
|
|
|
|
/**
|
|
* Responds to entity PUT requests.
|
|
*
|
|
* @param int $id
|
|
* The ID of the record.
|
|
* @param mixed $record
|
|
* Data to write into the database.
|
|
*
|
|
* @return \Drupal\rest\ModifiedResourceResponse
|
|
* The HTTP response object.
|
|
*/
|
|
public function put($id, $record) {
|
|
|
|
$this->validate($record);
|
|
|
|
// Provide default values to make sure the record is completely replaced.
|
|
$record += [
|
|
'title' => '',
|
|
'description' => '',
|
|
'price' => 0,
|
|
];
|
|
|
|
return $this->updateRecord($id, $record);
|
|
}
|
|
|
|
/**
|
|
* Responds to entity DELETE requests.
|
|
*
|
|
* @param int $id
|
|
* The ID of the record.
|
|
*
|
|
* @return \Drupal\rest\ModifiedResourceResponse
|
|
* The HTTP response object.
|
|
*
|
|
* @throws \Symfony\Component\HttpKernel\Exception\HttpException
|
|
*/
|
|
public function delete($id) {
|
|
|
|
// Make sure the record still exists.
|
|
$this->loadRecord($id);
|
|
|
|
$this->dbConnection->delete('{{ plugin_id }}')
|
|
->condition('id', $id)
|
|
->execute();
|
|
|
|
$this->logger->notice('{{ plugin_label }} record @id has been deleted.', ['@id' => $id]);
|
|
|
|
// Deleted responses have an empty body.
|
|
return new ModifiedResourceResponse(NULL, 204);
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*/
|
|
protected function getBaseRoute($canonical_path, $method) {
|
|
$route = parent::getBaseRoute($canonical_path, $method);
|
|
|
|
// Change ID validation pattern.
|
|
if ($method != 'POST') {
|
|
$route->setRequirement('id', '\d+');
|
|
}
|
|
|
|
return $route;
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*/
|
|
public function calculateDependencies() {
|
|
return [];
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*/
|
|
public function routes() {
|
|
$collection = parent::routes();
|
|
|
|
// ResourceBase class does not support PUT method by some reason.
|
|
$definition = $this->getPluginDefinition();
|
|
$canonical_path = $definition['uri_paths']['canonical'];
|
|
$route = $this->getBaseRoute($canonical_path, 'PUT');
|
|
$route->addRequirements(['_content_type_format' => implode('|', $this->serializerFormats)]);
|
|
$collection->add('{{ plugin_id }}.PUT', $route);
|
|
|
|
return $collection;
|
|
}
|
|
|
|
/**
|
|
* Validates incoming record.
|
|
*
|
|
* @param mixed $record
|
|
* Data to validate.
|
|
*
|
|
* @throws \Symfony\Component\HttpKernel\Exception\BadRequestHttpException
|
|
*/
|
|
protected function validate($record) {
|
|
if (!is_array($record) || count($record) == 0) {
|
|
throw new BadRequestHttpException('No record content received.');
|
|
}
|
|
|
|
$allowed_fields = [
|
|
'title',
|
|
'description',
|
|
'price',
|
|
];
|
|
|
|
if (count(array_diff(array_keys($record), $allowed_fields)) > 0) {
|
|
throw new BadRequestHttpException('Record structure is not correct.');
|
|
}
|
|
|
|
if (empty($record['title'])) {
|
|
throw new BadRequestHttpException('Title is required.');
|
|
}
|
|
elseif (isset($record['title']) && strlen($record['title']) > 255) {
|
|
throw new BadRequestHttpException('Title is too big.');
|
|
}
|
|
// @DCG Add more validation rules here.
|
|
}
|
|
|
|
/**
|
|
* Loads record from database.
|
|
*
|
|
* @param int $id
|
|
* The ID of the record.
|
|
*
|
|
* @return array
|
|
* The database record.
|
|
*
|
|
* @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException
|
|
*/
|
|
protected function loadRecord($id) {
|
|
$record = $this->dbConnection->query('SELECT * FROM {{ '{' }}{{ plugin_id }}{{ '}' }} WHERE id = :id', [':id' => $id])->fetchAssoc();
|
|
if (!$record) {
|
|
throw new NotFoundHttpException('The record was not found.');
|
|
}
|
|
return $record;
|
|
}
|
|
|
|
/**
|
|
* Updates record.
|
|
*
|
|
* @param int $id
|
|
* The ID of the record.
|
|
* @param array $record
|
|
* The record to validate.
|
|
*
|
|
* @return \Drupal\rest\ModifiedResourceResponse
|
|
* The HTTP response object.
|
|
*/
|
|
protected function updateRecord($id, array $record) {
|
|
|
|
// Make sure the record already exists.
|
|
$this->loadRecord($id);
|
|
|
|
$this->validate($record);
|
|
|
|
$this->dbConnection->update('{{ plugin_id }}')
|
|
->fields($record)
|
|
->condition('id', $id)
|
|
->execute();
|
|
|
|
$this->logger->notice('{{ plugin_label }} record @id has been updated.', ['@id' => $id]);
|
|
|
|
// Return the updated record in the response body.
|
|
$updated_record = $this->loadRecord($id);
|
|
return new ModifiedResourceResponse($updated_record, 200);
|
|
}
|
|
|
|
}
|