Issues (31)

src/Admin/JsonAdm/Standard.php (1 issue)

Labels
Severity
1
<?php
2
3
/**
4
 * @license LGPLv3, http://opensource.org/licenses/LGPL-3.0
5
 * @copyright Aimeos (aimeos.org), 2015-2025
6
 * @package Admin
7
 * @subpackage JsonAdm
8
 */
9
10
11
namespace Aimeos\Admin\JsonAdm;
12
13
use Psr\Http\Message\ServerRequestInterface;
14
use Psr\Http\Message\ResponseInterface;
15
16
17
/**
18
 * JSON API standard client
19
 *
20
 * @package Admin
21
 * @subpackage JsonAdm
22
 */
23
class Standard
24
	extends \Aimeos\Admin\JsonAdm\Base
25
	implements \Aimeos\Admin\JsonAdm\Common\Iface
26
{
27
	/**
28
	 * Deletes the resource or the resource list
29
	 *
30
	 * @param \Psr\Http\Message\ServerRequestInterface $request Request object
31
	 * @param \Psr\Http\Message\ResponseInterface $response Response object
32
	 * @return \Psr\Http\Message\ResponseInterface Modified response object
33
	 */
34
	public function delete( ServerRequestInterface $request, ResponseInterface $response ) : \Psr\Http\Message\ResponseInterface
35
	{
36
		$view = $this->view();
37
38
		try
39
		{
40
			$response = $this->deleteItems( $view, $request, $response );
41
			$status = 200;
42
		}
43
		catch( \Aimeos\Admin\JsonAdm\Exception $e )
44
		{
45
			$status = $e->getCode();
46
			$view->errors = array( array(
47
				'title' => $this->context()->translate( 'admin/jsonadm', $e->getMessage() ),
48
				'detail' => $e->getTraceAsString(),
49
			) );
50
		}
51
		catch( \Aimeos\MShop\Exception $e )
52
		{
53
			$status = 404;
54
			$view->errors = array( array(
55
				'title' => $this->context()->translate( 'mshop', $e->getMessage() ),
56
				'detail' => $e->getTraceAsString(),
57
			) );
58
		}
59
		catch( \Exception $e )
60
		{
61
			$status = 500;
62
			$view->errors = array( array(
63
				'title' => $e->getMessage(),
64
				'detail' => $e->getTraceAsString(),
65
			) );
66
		}
67
68
		/** admin/jsonadm/template-delete
69
		 * Relative path to the JSON API template for DELETE requests
70
		 *
71
		 * The template file contains the code and processing instructions
72
		 * to generate the result shown in the JSON API body. The
73
		 * configuration string is the path to the template file relative
74
		 * to the templates directory (usually in templates/admin/jsonadm).
75
		 *
76
		 * You can overwrite the template file configuration in extensions and
77
		 * provide alternative templates. These alternative templates should be
78
		 * named like the default one but with the string "standard" replaced by
79
		 * an unique name. You may use the name of your project for this. If
80
		 * you've implemented an alternative client class as well, "standard"
81
		 * should be replaced by the name of the new class.
82
		 *
83
		 * @param string Relative path to the template creating the body for the DELETE method of the JSON API
84
		 * @since 2015.12
85
		 * @category Developer
86
		 * @see admin/jsonadm/template-aggregate
87
		 * @see admin/jsonadm/template-get
88
		 * @see admin/jsonadm/template-patch
89
		 * @see admin/jsonadm/template-post
90
		 * @see admin/jsonadm/template-put
91
		 * @see admin/jsonadm/template-options
92
		 */
93
		$tplconf = 'admin/jsonadm/template-delete';
94
		$default = 'delete';
95
96
		$body = $view->render( $view->config( $tplconf, $default ) );
97
98
		return $response->withHeader( 'Content-Type', 'application/vnd.api+json; supported-ext="bulk"' )
99
			->withBody( $view->response()->createStreamFromString( $body ) )
100
			->withStatus( $status );
0 ignored issues
show
The method withStatus() does not exist on Psr\Http\Message\MessageInterface. It seems like you code against a sub-type of Psr\Http\Message\MessageInterface such as Psr\Http\Message\ResponseInterface or Aimeos\Base\View\Helper\Request\Standard. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

100
			->/** @scrutinizer ignore-call */ withStatus( $status );
Loading history...
101
	}
102
103
104
	/**
105
	 * Returns the requested resource or the resource list
106
	 *
107
	 * @param \Psr\Http\Message\ServerRequestInterface $request Request object
108
	 * @param \Psr\Http\Message\ResponseInterface $response Response object
109
	 * @return \Psr\Http\Message\ResponseInterface Modified response object
110
	 */
111
	public function get( ServerRequestInterface $request, ResponseInterface $response ) : \Psr\Http\Message\ResponseInterface
112
	{
113
		$view = $this->view();
114
115
		try
116
		{
117
			$response = $this->getItems( $view, $request, $response );
118
			$status = 200;
119
		}
120
		catch( \Aimeos\MShop\Exception $e )
121
		{
122
			$status = 404;
123
			$view->errors = array( array(
124
				'title' => $this->context()->translate( 'mshop', $e->getMessage() ),
125
				'detail' => $e->getTraceAsString(),
126
			) );
127
		}
128
		catch( \Exception $e )
129
		{
130
			$status = 500;
131
			$view->errors = array( array(
132
				'title' => $e->getMessage(),
133
				'detail' => $e->getTraceAsString(),
134
			) );
135
		}
136
137
		if( $view->param( 'aggregate' ) !== null )
138
		{
139
			/** admin/jsonadm/template-aggregate
140
			 * Relative path to the JSON API template for GET aggregate requests
141
			 *
142
			 * The template file contains the code and processing instructions
143
			 * to generate the result shown in the JSON API body. The
144
			 * configuration string is the path to the template file relative
145
			 * to the templates directory (usually in templates/admin/jsonadm).
146
			 *
147
			 * You can overwrite the template file configuration in extensions and
148
			 * provide alternative templates. These alternative templates should be
149
			 * named like the default one but with the string "standard" replaced by
150
			 * an unique name. You may use the name of your project for this. If
151
			 * you've implemented an alternative client class as well, "standard"
152
			 * should be replaced by the name of the new class.
153
			 *
154
			 * @param string Relative path to the template creating the body for the GET aggregate request of the JSON API
155
			 * @since 2016.07
156
			 * @category Developer
157
			 * @see admin/jsonadm/template-delete
158
			 * @see admin/jsonadm/template-get
159
			 * @see admin/jsonadm/template-patch
160
			 * @see admin/jsonadm/template-post
161
			 * @see admin/jsonadm/template-put
162
			 * @see admin/jsonadm/template-options
163
			 */
164
			$tplconf = 'admin/jsonadm/template-aggregate';
165
			$default = 'aggregate';
166
		}
167
		else
168
		{
169
			/** admin/jsonadm/template-get
170
			 * Relative path to the JSON API template for GET requests
171
			 *
172
			 * The template file contains the code and processing instructions
173
			 * to generate the result shown in the JSON API body. The
174
			 * configuration string is the path to the template file relative
175
			 * to the templates directory (usually in templates/admin/jsonadm).
176
			 *
177
			 * You can overwrite the template file configuration in extensions and
178
			 * provide alternative templates. These alternative templates should be
179
			 * named like the default one but with the string "standard" replaced by
180
			 * an unique name. You may use the name of your project for this. If
181
			 * you've implemented an alternative client class as well, "standard"
182
			 * should be replaced by the name of the new class.
183
			 *
184
			 * @param string Relative path to the template creating the body for the GET method of the JSON API
185
			 * @since 2015.12
186
			 * @category Developer
187
			 * @see admin/jsonadm/template-aggregate
188
			 * @see admin/jsonadm/template-delete
189
			 * @see admin/jsonadm/template-patch
190
			 * @see admin/jsonadm/template-post
191
			 * @see admin/jsonadm/template-put
192
			 * @see admin/jsonadm/template-options
193
			 */
194
			$tplconf = 'admin/jsonadm/template-get';
195
			$default = 'get';
196
		}
197
198
		$body = $view->render( $view->config( $tplconf, $default ) );
199
200
		return $response->withHeader( 'Content-Type', 'application/vnd.api+json; supported-ext="bulk"' )
201
			->withBody( $view->response()->createStreamFromString( $body ) )
202
			->withStatus( $status );
203
	}
204
205
206
	/**
207
	 * Updates the resource or the resource list partitially
208
	 *
209
	 * @param \Psr\Http\Message\ServerRequestInterface $request Request object
210
	 * @param \Psr\Http\Message\ResponseInterface $response Response object
211
	 * @return \Psr\Http\Message\ResponseInterface Modified response object
212
	 */
213
	public function patch( ServerRequestInterface $request, ResponseInterface $response ) : \Psr\Http\Message\ResponseInterface
214
	{
215
		$view = $this->view();
216
217
		try
218
		{
219
			$response = $this->patchItems( $view, $request, $response );
220
			$status = 200;
221
		}
222
		catch( \Aimeos\Admin\JsonAdm\Exception $e )
223
		{
224
			$status = $e->getCode();
225
			$view->errors = array( array(
226
				'title' => $this->context()->translate( 'admin/jsonadm', $e->getMessage() ),
227
				'detail' => $e->getTraceAsString(),
228
			) );
229
		}
230
		catch( \Aimeos\MShop\Exception $e )
231
		{
232
			$status = 404;
233
			$view->errors = array( array(
234
				'title' => $this->context()->translate( 'mshop', $e->getMessage() ),
235
				'detail' => $e->getTraceAsString(),
236
			) );
237
		}
238
		catch( \Exception $e )
239
		{
240
			$status = 500;
241
			$view->errors = array( array(
242
				'title' => $e->getMessage(),
243
				'detail' => $e->getTraceAsString(),
244
			) );
245
		}
246
247
		/** admin/jsonadm/template-patch
248
		 * Relative path to the JSON API template for PATCH requests
249
		 *
250
		 * The template file contains the code and processing instructions
251
		 * to generate the result shown in the JSON API body. The
252
		 * configuration string is the path to the template file relative
253
		 * to the templates directory (usually in templates/admin/jsonadm).
254
		 *
255
		 * You can overwrite the template file configuration in extensions and
256
		 * provide alternative templates. These alternative templates should be
257
		 * named like the default one but with the string "standard" replaced by
258
		 * an unique name. You may use the name of your project for this. If
259
		 * you've implemented an alternative client class as well, "standard"
260
		 * should be replaced by the name of the new class.
261
		 *
262
		 * @param string Relative path to the template creating the body for the PATCH method of the JSON API
263
		 * @since 2015.12
264
		 * @category Developer
265
		 * @see admin/jsonadm/template-aggregate
266
		 * @see admin/jsonadm/template-get
267
		 * @see admin/jsonadm/template-post
268
		 * @see admin/jsonadm/template-delete
269
		 * @see admin/jsonadm/template-put
270
		 * @see admin/jsonadm/template-options
271
		 */
272
		$tplconf = 'admin/jsonadm/template-patch';
273
		$default = 'patch';
274
275
		$body = $view->render( $view->config( $tplconf, $default ) );
276
277
		return $response->withHeader( 'Content-Type', 'application/vnd.api+json; supported-ext="bulk"' )
278
			->withBody( $view->response()->createStreamFromString( $body ) )
279
			->withStatus( $status );
280
	}
281
282
283
	/**
284
	 * Creates or updates the resource or the resource list
285
	 *
286
	 * @param \Psr\Http\Message\ServerRequestInterface $request Request object
287
	 * @param \Psr\Http\Message\ResponseInterface $response Response object
288
	 * @return \Psr\Http\Message\ResponseInterface Modified response object
289
	 */
290
	public function post( ServerRequestInterface $request, ResponseInterface $response ) : \Psr\Http\Message\ResponseInterface
291
	{
292
		$view = $this->view();
293
294
		try
295
		{
296
			$response = $this->postItems( $view, $request, $response );
297
			$status = 201;
298
		}
299
		catch( \Aimeos\Admin\JsonAdm\Exception $e )
300
		{
301
			$status = $e->getCode();
302
			$view->errors = array( array(
303
				'title' => $this->context()->translate( 'admin/jsonadm', $e->getMessage() ),
304
				'detail' => $e->getTraceAsString(),
305
			) );
306
		}
307
		catch( \Aimeos\MShop\Exception $e )
308
		{
309
			$status = 404;
310
			$view->errors = array( array(
311
				'title' => $this->context()->translate( 'mshop', $e->getMessage() ),
312
				'detail' => $e->getTraceAsString(),
313
			) );
314
		}
315
		catch( \Exception $e )
316
		{
317
			$status = 500;
318
			$view->errors = array( array(
319
				'title' => $e->getMessage(),
320
				'detail' => $e->getTraceAsString(),
321
			) );
322
		}
323
324
		/** admin/jsonadm/template-post
325
		 * Relative path to the JSON API template for POST requests
326
		 *
327
		 * The template file contains the code and processing instructions
328
		 * to generate the result shown in the JSON API body. The
329
		 * configuration string is the path to the template file relative
330
		 * to the templates directory (usually in templates/admin/jsonadm).
331
		 *
332
		 * You can overwrite the template file configuration in extensions and
333
		 * provide alternative templates. These alternative templates should be
334
		 * named like the default one but with the string "standard" replaced by
335
		 * an unique name. You may use the name of your project for this. If
336
		 * you've implemented an alternative client class as well, "standard"
337
		 * should be replaced by the name of the new class.
338
		 *
339
		 * @param string Relative path to the template creating the body for the POST method of the JSON API
340
		 * @since 2015.12
341
		 * @category Developer
342
		 * @see admin/jsonadm/template-aggregate
343
		 * @see admin/jsonadm/template-get
344
		 * @see admin/jsonadm/template-patch
345
		 * @see admin/jsonadm/template-delete
346
		 * @see admin/jsonadm/template-put
347
		 * @see admin/jsonadm/template-options
348
		 */
349
		$tplconf = 'admin/jsonadm/template-post';
350
		$default = 'post';
351
352
		$body = $view->render( $view->config( $tplconf, $default ) );
353
354
		return $response->withHeader( 'Content-Type', 'application/vnd.api+json; supported-ext="bulk"' )
355
			->withBody( $view->response()->createStreamFromString( $body ) )
356
			->withStatus( $status );
357
	}
358
359
360
	/**
361
	 * Creates or updates the resource or the resource list
362
	 *
363
	 * @param \Psr\Http\Message\ServerRequestInterface $request Request object
364
	 * @param \Psr\Http\Message\ResponseInterface $response Response object
365
	 * @return \Psr\Http\Message\ResponseInterface Modified response object
366
	 */
367
	public function put( ServerRequestInterface $request, ResponseInterface $response ) : \Psr\Http\Message\ResponseInterface
368
	{
369
		$status = 501;
370
		$view = $this->view();
371
372
		$view->errors = array( array(
373
			'title' => $this->context()->translate( 'admin/jsonadm', 'Not implemented, use PATCH instead' ),
374
		) );
375
376
		/** admin/jsonadm/template-put
377
		 * Relative path to the JSON API template for PUT requests
378
		 *
379
		 * The template file contains the code and processing instructions
380
		 * to generate the result shown in the JSON API body. The
381
		 * configuration string is the path to the template file relative
382
		 * to the templates directory (usually in templates/admin/jsonadm).
383
		 *
384
		 * You can overwrite the template file configuration in extensions and
385
		 * provide alternative templates. These alternative templates should be
386
		 * named like the default one but with the string "standard" replaced by
387
		 * an unique name. You may use the name of your project for this. If
388
		 * you've implemented an alternative client class as well, "standard"
389
		 * should be replaced by the name of the new class.
390
		 *
391
		 * @param string Relative path to the template creating the body for the PUT method of the JSON API
392
		 * @since 2015.12
393
		 * @category Developer
394
		 * @see admin/jsonadm/template-aggregate
395
		 * @see admin/jsonadm/template-delete
396
		 * @see admin/jsonadm/template-patch
397
		 * @see admin/jsonadm/template-post
398
		 * @see admin/jsonadm/template-get
399
		 * @see admin/jsonadm/template-options
400
		 */
401
		$tplconf = 'admin/jsonadm/template-put';
402
		$default = 'put';
403
404
		$body = $view->render( $view->config( $tplconf, $default ) );
405
406
		return $response->withHeader( 'Content-Type', 'application/vnd.api+json; supported-ext="bulk"' )
407
			->withBody( $view->response()->createStreamFromString( $body ) )
408
			->withStatus( $status );
409
	}
410
411
412
	/**
413
	 * Returns the available REST verbs and the available resources
414
	 *
415
	 * @param \Psr\Http\Message\ServerRequestInterface $request Request object
416
	 * @param \Psr\Http\Message\ResponseInterface $response Response object
417
	 * @return \Psr\Http\Message\ResponseInterface Modified response object
418
	 */
419
	public function options( ServerRequestInterface $request, ResponseInterface $response ) : \Psr\Http\Message\ResponseInterface
420
	{
421
		$context = $this->context();
422
		$view = $this->view();
423
424
		try
425
		{
426
			$resources = $attributes = [];
427
428
			foreach( $this->getDomains( $view ) as $domain )
429
			{
430
				$manager = \Aimeos\MShop::create( $context, $domain );
431
				$attributes = array_merge( $attributes, $manager->getSearchAttributes( true ) );
432
				$resources[] = join( '/', $manager->type() );
433
			}
434
435
			foreach( $this->getResources( $view ) as $resource ) {
436
				$resources[] = $resource;
437
			}
438
439
			$view->resources = $this->getAllowedResources( $view, $resources );
440
			$view->attributes = $attributes;
441
442
			$status = 200;
443
		}
444
		catch( \Aimeos\MShop\Exception $e )
445
		{
446
			$status = 404;
447
			$view->errors = array( array(
448
				'title' => $context->translate( 'mshop', $e->getMessage() ),
449
				'detail' => $e->getTraceAsString(),
450
			) );
451
		}
452
		catch( \Exception $e )
453
		{
454
			$status = 500;
455
			$view->errors = array( array(
456
				'title' => $e->getMessage(),
457
				'detail' => $e->getTraceAsString(),
458
			) );
459
		}
460
461
		/** admin/jsonadm/template-options
462
		 * Relative path to the JSON API template for OPTIONS requests
463
		 *
464
		 * The template file contains the code and processing instructions
465
		 * to generate the result shown in the JSON API body. The
466
		 * configuration string is the path to the template file relative
467
		 * to the templates directory (usually in templates/admin/jsonadm).
468
		 *
469
		 * You can overwrite the template file configuration in extensions and
470
		 * provide alternative templates. These alternative templates should be
471
		 * named like the default one but with the string "standard" replaced by
472
		 * an unique name. You may use the name of your project for this. If
473
		 * you've implemented an alternative client class as well, "standard"
474
		 * should be replaced by the name of the new class.
475
		 *
476
		 * @param string Relative path to the template creating the body for the OPTIONS method of the JSON API
477
		 * @since 2015.12
478
		 * @category Developer
479
		 * @see admin/jsonadm/template-aggregate
480
		 * @see admin/jsonadm/template-delete
481
		 * @see admin/jsonadm/template-patch
482
		 * @see admin/jsonadm/template-post
483
		 * @see admin/jsonadm/template-get
484
		 * @see admin/jsonadm/template-put
485
		 */
486
		$tplconf = 'admin/jsonadm/template-options';
487
		$default = 'options';
488
489
		$body = $view->render( $view->config( $tplconf, $default ) );
490
491
		return $response->withHeader( 'Allow', 'DELETE,GET,PATCH,POST,OPTIONS' )
492
			->withHeader( 'Content-Type', 'application/vnd.api+json; supported-ext="bulk"' )
493
			->withBody( $view->response()->createStreamFromString( $body ) )
494
			->withStatus( $status );
495
	}
496
497
498
	/**
499
	 * Deletes one or more items
500
	 *
501
	 * @param \Aimeos\Base\View\Iface $view View instance with "param" view helper
502
	 * @param \Psr\Http\Message\ServerRequestInterface $request Request object
503
	 * @param \Psr\Http\Message\ResponseInterface $response Response object
504
	 * @return \Psr\Http\Message\ResponseInterface Modified response object
505
	 * @throws \Aimeos\Admin\JsonAdm\Exception If the request body is invalid
506
	 */
507
	protected function deleteItems( \Aimeos\Base\View\Iface $view, ServerRequestInterface $request, ResponseInterface $response ) : \Psr\Http\Message\ResponseInterface
508
	{
509
		$manager = \Aimeos\MShop::create( $this->context(), $this->getPath() );
510
511
		if( ( $id = $view->param( 'id' ) ) == null )
512
		{
513
			$body = (string) $request->getBody();
514
515
			if( ( $payload = json_decode( $body ) ) === null || !isset( $payload->data ) || !is_array( $payload->data ) ) {
516
				throw new \Aimeos\Admin\JsonAdm\Exception( 'Invalid JSON in body', 400 );
517
			}
518
519
			$ids = map( $payload->data )->col( 'id' );
520
			$manager->delete( $ids->toArray() );
521
			$view->total = count( $ids );
522
		}
523
		else
524
		{
525
			$manager->delete( $id );
526
			$view->total = 1;
527
		}
528
529
		return $response;
530
	}
531
532
533
	/**
534
	 * Retrieves the item or items and adds the data to the view
535
	 *
536
	 * @param \Aimeos\Base\View\Iface $view View instance
537
	 * @param \Psr\Http\Message\ServerRequestInterface $request Request object
538
	 * @param \Psr\Http\Message\ResponseInterface $response Response object
539
	 * @return \Psr\Http\Message\ResponseInterface Modified response object
540
	 */
541
	protected function getItems( \Aimeos\Base\View\Iface $view, ServerRequestInterface $request, ResponseInterface $response ) : \Psr\Http\Message\ResponseInterface
542
	{
543
		$manager = \Aimeos\MShop::create( $this->context(), $this->getPath() );
544
545
		if( ( $key = $view->param( 'aggregate' ) ) !== null )
546
		{
547
			$search = $this->initCriteria( $manager->filter(), $view->param() );
548
			$view->data = $manager->aggregate( $search, explode( ',', $key ), $view->param( 'value' ), $view->param( 'type' ) );
549
			return $response;
550
		}
551
552
		$total = 1;
553
		$include = ( ( $include = $view->param( 'include' ) ) !== null ? explode( ',', $include ) : [] );
554
555
		if( ( $id = $view->param( 'id' ) ) == null )
556
		{
557
			$search = $this->initCriteria( $manager->filter(), $view->param() );
558
			$view->data = $manager->search( $search, $include, $total );
559
			$view->childItems = $this->getChildItems( $view->data, $include );
560
			$view->listItems = $this->getListItems( $view->data, $include );
561
		}
562
		else
563
		{
564
			$view->data = $manager->get( $id, $include );
565
			$view->childItems = $this->getChildItems( map( [$id => $view->data] ), $include );
566
			$view->listItems = $this->getListItems( map( [$id => $view->data] ), $include );
567
		}
568
569
		$view->refItems = $this->getRefItems( $view->listItems );
570
		$view->total = $total;
571
572
		return $response;
573
	}
574
575
576
	/**
577
	 * Saves new attributes for one or more items
578
	 *
579
	 * @param \Aimeos\Base\View\Iface $view View that will contain the "data" and "total" properties afterwards
580
	 * @param \Psr\Http\Message\ServerRequestInterface $request Request object
581
	 * @param \Psr\Http\Message\ResponseInterface $response Response object
582
	 * @return \Psr\Http\Message\ResponseInterface Modified response object
583
	 * @throws \Aimeos\Admin\JsonAdm\Exception If "id" parameter isn't available or the body is invalid
584
	 */
585
	protected function patchItems( \Aimeos\Base\View\Iface $view, ServerRequestInterface $request, ResponseInterface $response ) : \Psr\Http\Message\ResponseInterface
586
	{
587
		$body = (string) $request->getBody();
588
589
		if( ( $payload = json_decode( $body ) ) === null || !isset( $payload->data ) ) {
590
			throw new \Aimeos\Admin\JsonAdm\Exception( 'Invalid JSON in body', 400 );
591
		}
592
593
		$manager = \Aimeos\MShop::create( $this->context(), $this->getPath() );
594
595
		if( is_array( $payload->data ) )
596
		{
597
			$data = $this->saveData( $manager, $payload );
598
599
			$view->data = $data;
600
			$view->total = count( $data );
601
			$response = $response->withHeader( 'Content-Type', 'application/vnd.api+json; ext="bulk"; supported-ext="bulk"' );
602
		}
603
		elseif( ( $id = $view->param( 'id' ) ) != null )
604
		{
605
			$payload->data->id = $id;
606
			$data = $this->saveEntry( $manager, $payload->data );
607
608
			$view->data = $data;
609
			$view->total = 1;
610
		}
611
		else
612
		{
613
			throw new \Aimeos\Admin\JsonAdm\Exception( 'No ID given', 400 );
614
		}
615
616
		return $response;
617
	}
618
619
620
	/**
621
	 * Creates one or more new items
622
	 *
623
	 * @param \Aimeos\Base\View\Iface $view View that will contain the "data" and "total" properties afterwards
624
	 * @param \Psr\Http\Message\ServerRequestInterface $request Request object
625
	 * @param \Psr\Http\Message\ResponseInterface $response Response object
626
	 * @return \Psr\Http\Message\ResponseInterface Modified response object
627
	 */
628
	protected function postItems( \Aimeos\Base\View\Iface $view, ServerRequestInterface $request, ResponseInterface $response ) : \Psr\Http\Message\ResponseInterface
629
	{
630
		$body = (string) $request->getBody();
631
632
		if( ( $payload = json_decode( $body ) ) === null || !isset( $payload->data ) ) {
633
			throw new \Aimeos\Admin\JsonAdm\Exception( 'Invalid JSON in body', 400 );
634
		}
635
636
		if( isset( $payload->data->id ) || $view->param( 'id' ) != null ) {
637
			throw new \Aimeos\Admin\JsonAdm\Exception( 'Client generated IDs are not supported', 403 );
638
		}
639
640
641
		$manager = \Aimeos\MShop::create( $this->context(), $this->getPath() );
642
643
		if( is_array( $payload->data ) )
644
		{
645
			$data = $this->saveData( $manager, $payload );
646
647
			$view->data = $data;
648
			$view->total = count( $data );
649
			$response = $response->withHeader( 'Content-Type', 'application/vnd.api+json; ext="bulk"; supported-ext="bulk"' );
650
		}
651
		else
652
		{
653
			$payload->data->id = null;
654
			$data = $this->saveEntry( $manager, $payload->data );
655
656
			$view->data = $data;
657
			$view->total = 1;
658
		}
659
660
		return $response;
661
	}
662
}
663