ed23b4270e7f8ca8b41743034a04c84a00ab8eb9
[yaffs-website] / vendor / chi-teck / drupal-code-generator / templates / d8 / plugin / rest-resource.twig
1 <?php
2
3 namespace Drupal\{{ machine_name }}\Plugin\rest\resource;
4
5 use Drupal\Component\Plugin\DependentPluginInterface;
6 use Drupal\Core\Database\Connection;
7 use Drupal\rest\ModifiedResourceResponse;
8 use Drupal\rest\Plugin\ResourceBase;
9 use Drupal\rest\ResourceResponse;
10 use Psr\Log\LoggerInterface;
11 use Symfony\Component\DependencyInjection\ContainerInterface;
12 use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
13 use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
14
15 /**
16  * Represents {{ plugin_label }} records as resources.
17  *
18  * @RestResource (
19  *   id = "{{ plugin_id }}",
20  *   label = @Translation("{{ plugin_label }}"),
21  *   uri_paths = {
22  *     "canonical" = "/api/{{ plugin_id|u2h }}/{id}",
23  *     "https://www.drupal.org/link-relations/create" = "/api/{{ plugin_id|u2h }}"
24  *   }
25  * )
26  *
27  * @DCG
28  * This plugin exposes database records as REST resources. In order to enable it
29  * import the resource configuration into active configuration storage. You may
30  * find an example of such configuration in the following file:
31  * core/modules/rest/config/optional/rest.resource.entity.node.yml.
32  * Alternatively you can make use of REST UI module.
33  * @see https://www.drupal.org/project/restui
34  * For accessing Drupal entities through REST interface use
35  * \Drupal\rest\Plugin\rest\resource\EntityResource plugin.
36  */
37 class {{ class }} extends ResourceBase implements DependentPluginInterface {
38
39   /**
40    * The database connection.
41    *
42    * @var \Drupal\Core\Database\Connection
43    */
44   protected $dbConnection;
45
46   /**
47    * Constructs a Drupal\rest\Plugin\rest\resource\EntityResource object.
48    *
49    * @param array $configuration
50    *   A configuration array containing information about the plugin instance.
51    * @param string $plugin_id
52    *   The plugin_id for the plugin instance.
53    * @param mixed $plugin_definition
54    *   The plugin implementation definition.
55    * @param array $serializer_formats
56    *   The available serialization formats.
57    * @param \Psr\Log\LoggerInterface $logger
58    *   A logger instance.
59    * @param \Drupal\Core\Database\Connection $db_connection
60    *   The database connection.
61    */
62   public function __construct(array $configuration, $plugin_id, $plugin_definition, array $serializer_formats, LoggerInterface $logger, Connection $db_connection) {
63     parent::__construct($configuration, $plugin_id, $plugin_definition, $serializer_formats, $logger);
64     $this->dbConnection = $db_connection;
65   }
66
67   /**
68    * {@inheritdoc}
69    */
70   public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
71     return new static(
72       $configuration,
73       $plugin_id,
74       $plugin_definition,
75       $container->getParameter('serializer.formats'),
76       $container->get('logger.factory')->get('rest'),
77       $container->get('database')
78     );
79   }
80
81   /**
82    * Responds to GET requests.
83    *
84    * @param int $id
85    *   The ID of the record.
86    *
87    * @return \Drupal\rest\ResourceResponse
88    *   The response containing the record.
89    *
90    * @throws \Symfony\Component\HttpKernel\Exception\HttpException
91    */
92   public function get($id) {
93     return new ResourceResponse($this->loadRecord($id));
94   }
95
96   /**
97    * Responds to POST requests and saves the new record.
98    *
99    * @param mixed $record
100    *   Data to write into the database.
101    *
102    * @return \Drupal\rest\ModifiedResourceResponse
103    *   The HTTP response object.
104    */
105   public function post($record) {
106
107     $this->validate($record);
108
109     $id = $this->dbConnection->insert('{{ plugin_id }}')
110       ->fields($record)
111       ->execute();
112
113     $this->logger->notice('New {{ plugin_label|lower }} record has been created.');
114
115     $created_record = $this->loadRecord($id);
116
117     // Return the newly created record in the response body.
118     return new ModifiedResourceResponse($created_record, 201);
119   }
120
121   /**
122    * Responds to entity PATCH requests.
123    *
124    * @param int $id
125    *   The ID of the record.
126    * @param mixed $record
127    *   Data to write into the database.
128    *
129    * @return \Drupal\rest\ModifiedResourceResponse
130    *   The HTTP response object.
131    */
132   public function patch($id, $record) {
133     $this->validate($record);
134     return $this->updateRecord($id, $record);
135   }
136
137   /**
138    * Responds to entity PUT requests.
139    *
140    * @param int $id
141    *   The ID of the record.
142    * @param mixed $record
143    *   Data to write into the database.
144    *
145    * @return \Drupal\rest\ModifiedResourceResponse
146    *   The HTTP response object.
147    */
148   public function put($id, $record) {
149
150     $this->validate($record);
151
152     // Provide default values to make sure the record is completely replaced.
153     $record += [
154       'title' => '',
155       'description' => '',
156       'price' => 0,
157     ];
158
159     return $this->updateRecord($id, $record);
160   }
161
162   /**
163    * Responds to entity DELETE requests.
164    *
165    * @param int $id
166    *   The ID of the record.
167    *
168    * @return \Drupal\rest\ModifiedResourceResponse
169    *   The HTTP response object.
170    *
171    * @throws \Symfony\Component\HttpKernel\Exception\HttpException
172    */
173   public function delete($id) {
174
175     // Make sure the record still exists.
176     $this->loadRecord($id);
177
178     $this->dbConnection->delete('{{ plugin_id }}')
179       ->condition('id', $id)
180       ->execute();
181
182     $this->logger->notice('{{ plugin_label }} record @id has been deleted.', ['@id' => $id]);
183
184     // Deleted responses have an empty body.
185     return new ModifiedResourceResponse(NULL, 204);
186   }
187
188   /**
189    * {@inheritdoc}
190    */
191   protected function getBaseRoute($canonical_path, $method) {
192     $route = parent::getBaseRoute($canonical_path, $method);
193
194     // Change ID validation pattern.
195     if ($method != 'POST') {
196       $route->setRequirement('id', '\d+');
197     }
198
199     return $route;
200   }
201
202   /**
203    * {@inheritdoc}
204    */
205   public function calculateDependencies() {
206     return [];
207   }
208
209   /**
210    * {@inheritdoc}
211    */
212   public function routes() {
213     $collection = parent::routes();
214
215     // ResourceBase class does not support PUT method by some reason.
216     $definition = $this->getPluginDefinition();
217     $canonical_path = $definition['uri_paths']['canonical'];
218     $route = $this->getBaseRoute($canonical_path, 'PUT');
219     $route->addRequirements(['_content_type_format' => implode('|', $this->serializerFormats)]);
220     $collection->add('{{ plugin_id }}.PUT', $route);
221
222     return $collection;
223   }
224
225   /**
226    * Validates incoming record.
227    *
228    * @param mixed $record
229    *   Data to validate.
230    *
231    * @throws \Symfony\Component\HttpKernel\Exception\BadRequestHttpException
232    */
233   protected function validate($record) {
234     if (!is_array($record) || count($record) == 0) {
235       throw new BadRequestHttpException('No record content received.');
236     }
237
238     $allowed_fields = [
239       'title',
240       'description',
241       'price',
242     ];
243
244     if (count(array_diff(array_keys($record), $allowed_fields)) > 0) {
245       throw new BadRequestHttpException('Record structure is not correct.');
246     }
247
248     if (empty($record['title'])) {
249       throw new BadRequestHttpException('Title is required.');
250     }
251     elseif (isset($record['title']) && strlen($record['title']) > 255) {
252       throw new BadRequestHttpException('Title is too big.');
253     }
254     // @DCG Add more validation rules here.
255   }
256
257   /**
258    * Loads record from database.
259    *
260    * @param int $id
261    *   The ID of the record.
262    *
263    * @return array
264    *   The database record.
265    *
266    * @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException
267    */
268   protected function loadRecord($id) {
269     $record = $this->dbConnection->query('SELECT * FROM {{ '{' }}{{ plugin_id }}{{ '}' }} WHERE id = :id', [':id' => $id])->fetchAssoc();
270     if (!$record) {
271       throw new NotFoundHttpException('The record was not found.');
272     }
273     return $record;
274   }
275
276   /**
277    * Updates record.
278    *
279    * @param int $id
280    *   The ID of the record.
281    * @param array $record
282    *   The record to validate.
283    *
284    * @return \Drupal\rest\ModifiedResourceResponse
285    *   The HTTP response object.
286    */
287   protected function updateRecord($id, array $record) {
288
289     // Make sure the record already exists.
290     $this->loadRecord($id);
291
292     $this->validate($record);
293
294     $this->dbConnection->update('{{ plugin_id }}')
295       ->fields($record)
296       ->condition('id', $id)
297       ->execute();
298
299     $this->logger->notice('{{ plugin_label }} record @id has been updated.', ['@id' => $id]);
300
301     // Return the updated record in the response body.
302     $updated_record = $this->loadRecord($id);
303     return new ModifiedResourceResponse($updated_record, 200);
304   }
305
306 }