Completed
Push — master ( 00af66...7df475 )
by Aimeos
02:30
created

Base   C

Complexity

Total Complexity 76

Size/Duplication

Total Lines 904
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 10

Importance

Changes 4
Bugs 1 Features 0
Metric Value
wmc 76
c 4
b 1
f 0
lcom 1
cbo 10
dl 0
loc 904
rs 5

25 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 7 1
B delete() 0 73 5
B get() 0 64 4
B patch() 0 73 5
B post() 0 73 5
B put() 0 41 1
B options() 0 79 5
C deleteItems() 0 30 7
B getItem() 0 26 3
A getView() 0 4 1
A initCriteria() 0 8 1
A initCriteriaConditions() 0 11 3
A initCriteriaSlice() 0 7 3
A initCriteriaSortations() 0 19 4
B getDomains() 0 29 2
A getChildItems() 0 4 1
A getListItems() 0 4 1
A getRefItems() 0 20 3
A getContext() 0 4 1
A getTemplatePaths() 0 4 1
A getPath() 0 4 1
B patchItems() 0 31 5
B postItems() 0 32 6
A saveData() 0 13 3
A saveEntry() 0 15 4

How to fix   Complexity   

Complex Class

Complex classes like Base often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Base, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/**
4
 * @license LGPLv3, http://opensource.org/licenses/LGPL-3.0
5
 * @copyright Aimeos (aimeos.org), 2015
6
 * @package Admin
7
 * @subpackage JsonAdm
8
 */
9
10
11
namespace Aimeos\Admin\JsonAdm;
12
13
14
/**
15
 * JSON API common client
16
 *
17
 * @package Admin
18
 * @subpackage JsonAdm
19
 */
20
class Base
21
{
22
	private $view;
23
	private $context;
24
	private $templatePaths;
25
	private $path;
26
27
28
	/**
29
	 * Initializes the client
30
	 *
31
	 * @param \Aimeos\MShop\Context\Item\Iface $context MShop context object
32
	 * @param \Aimeos\MW\View\Iface $view View object
33
	 * @param array $templatePaths List of file system paths where the templates are stored
34
	 * @param string $path Name of the client separated by slashes, e.g "product/stock"
35
	 * @return void
0 ignored issues
show
Comprehensibility Best Practice introduced by
Adding a @return annotation to constructors is generally not recommended as a constructor does not have a meaningful return value.

Adding a @return annotation to a constructor is not recommended, since a constructor does not have a meaningful return value.

Please refer to the PHP core documentation on constructors.

Loading history...
36
	 */
37
	public function __construct( \Aimeos\MShop\Context\Item\Iface $context, \Aimeos\MW\View\Iface $view, array $templatePaths, $path )
38
	{
39
		$this->view = $view;
40
		$this->context = $context;
41
		$this->templatePaths = $templatePaths;
42
		$this->path = $path;
43
	}
44
45
46
	/**
47
	 * Deletes the resource or the resource list
48
	 *
49
	 * @param string $body Request body
50
	 * @param array &$header Variable which contains the HTTP headers and the new ones afterwards
51
	 * @param integer &$status Variable which contains the HTTP status afterwards
52
	 * @return string Content for response body
53
	 */
54
	public function delete( $body, array &$header, &$status )
55
	{
56
		$header = array( 'Content-Type' => 'application/vnd.api+json; supported-ext="bulk"' );
57
		$context = $this->getContext();
58
		$view = $this->getView();
59
60
		try
61
		{
62
			$view = $this->deleteItems( $view, $body );
63
			$status = 200;
64
		}
65
		catch( \Aimeos\Admin\JsonAdm\Exception $e )
66
		{
67
			$status = $e->getCode();
68
			$view->errors = array( array(
69
				'title' => $context->getI18n()->dt( 'admin/jsonadm', $e->getMessage() ),
70
				'detail' => $e->getTraceAsString(),
71
			) );
72
		}
73
		catch( \Aimeos\MAdmin\Exception $e )
74
		{
75
			$status = 404;
76
			$view->errors = array( array(
77
				'title' => $context->getI18n()->dt( 'mshop', $e->getMessage() ),
78
				'detail' => $e->getTraceAsString(),
79
			) );
80
		}
81
		catch( \Aimeos\MShop\Exception $e )
82
		{
83
			$status = 404;
84
			$view->errors = array( array(
85
				'title' => $context->getI18n()->dt( 'mshop', $e->getMessage() ),
86
				'detail' => $e->getTraceAsString(),
87
			) );
88
		}
89
		catch( \Exception $e )
90
		{
91
			$status = 500;
92
			$view->errors = array( array(
93
				'title' => $e->getMessage(),
94
				'detail' => $e->getTraceAsString(),
95
			) );
96
		}
97
98
		/** admin/jsonadm/standard/template-delete
99
		 * Relative path to the JSON API template for DELETE requests
100
		 *
101
		 * The template file contains the code and processing instructions
102
		 * to generate the result shown in the JSON API body. The
103
		 * configuration string is the path to the template file relative
104
		 * to the templates directory (usually in admin/jsonadm/templates).
105
		 *
106
		 * You can overwrite the template file configuration in extensions and
107
		 * provide alternative templates. These alternative templates should be
108
		 * named like the default one but with the string "standard" replaced by
109
		 * an unique name. You may use the name of your project for this. If
110
		 * you've implemented an alternative client class as well, "standard"
111
		 * should be replaced by the name of the new class.
112
		 *
113
		 * @param string Relative path to the template creating the body for the DELETE method of the JSON API
114
		 * @since 2015.12
115
		 * @category Developer
116
		 * @see admin/jsonadm/standard/template-get
117
		 * @see admin/jsonadm/standard/template-patch
118
		 * @see admin/jsonadm/standard/template-post
119
		 * @see admin/jsonadm/standard/template-put
120
		 * @see admin/jsonadm/standard/template-options
121
		 */
122
		$tplconf = 'admin/jsonadm/standard/template-delete';
123
		$default = 'delete-default.php';
124
125
		return $view->render( $view->config( $tplconf, $default ) );
126
	}
127
128
129
	/**
130
	 * Returns the requested resource or the resource list
131
	 *
132
	 * @param string $body Request body
133
	 * @param array &$header Variable which contains the HTTP headers and the new ones afterwards
134
	 * @param integer &$status Variable which contains the HTTP status afterwards
135
	 * @return string Content for response body
136
	 */
137
	public function get( $body, array &$header, &$status )
138
	{
139
		$header = array( 'Content-Type' => 'application/vnd.api+json; supported-ext="bulk"' );
140
		$view = $this->getView();
141
142
		try
143
		{
144
			$view = $this->getItem( $view );
145
			$status = 200;
146
		}
147
		catch( \Aimeos\MAdmin\Exception $e )
148
		{
149
			$status = 404;
150
			$view->errors = array( array(
151
				'title' => $this->getContext()->getI18n()->dt( 'mshop', $e->getMessage() ),
152
				'detail' => $e->getTraceAsString(),
153
			) );
154
		}
155
		catch( \Aimeos\MShop\Exception $e )
156
		{
157
			$status = 404;
158
			$view->errors = array( array(
159
				'title' => $this->getContext()->getI18n()->dt( 'mshop', $e->getMessage() ),
160
				'detail' => $e->getTraceAsString(),
161
			) );
162
		}
163
		catch( \Exception $e )
164
		{
165
			$status = 500;
166
			$view->errors = array( array(
167
				'title' => $e->getMessage(),
168
				'detail' => $e->getTraceAsString(),
169
			) );
170
		}
171
172
		/** admin/jsonadm/standard/template-get
173
		 * Relative path to the JSON API template for GET requests
174
		 *
175
		 * The template file contains the code and processing instructions
176
		 * to generate the result shown in the JSON API body. The
177
		 * configuration string is the path to the template file relative
178
		 * to the templates directory (usually in admin/jsonadm/templates).
179
		 *
180
		 * You can overwrite the template file configuration in extensions and
181
		 * provide alternative templates. These alternative templates should be
182
		 * named like the default one but with the string "standard" replaced by
183
		 * an unique name. You may use the name of your project for this. If
184
		 * you've implemented an alternative client class as well, "standard"
185
		 * should be replaced by the name of the new class.
186
		 *
187
		 * @param string Relative path to the template creating the body for the GET method of the JSON API
188
		 * @since 2015.12
189
		 * @category Developer
190
		 * @see admin/jsonadm/standard/template-delete
191
		 * @see admin/jsonadm/standard/template-patch
192
		 * @see admin/jsonadm/standard/template-post
193
		 * @see admin/jsonadm/standard/template-put
194
		 * @see admin/jsonadm/standard/template-options
195
		 */
196
		$tplconf = 'admin/jsonadm/standard/template-get';
197
		$default = 'get-default.php';
198
199
		return $view->render( $view->config( $tplconf, $default ) );
200
	}
201
202
203
	/**
204
	 * Updates the resource or the resource list partitially
205
	 *
206
	 * @param string $body Request body
207
	 * @param array &$header Variable which contains the HTTP headers and the new ones afterwards
208
	 * @param integer &$status Variable which contains the HTTP status afterwards
209
	 * @return string Content for response body
210
	 */
211
	public function patch( $body, array &$header, &$status )
212
	{
213
		$header = array( 'Content-Type' => 'application/vnd.api+json; supported-ext="bulk"' );
214
		$context = $this->getContext();
215
		$view = $this->getView();
216
217
		try
218
		{
219
			$view = $this->patchItems( $view, $body, $header );
220
			$status = 200;
221
		}
222
		catch( \Aimeos\Admin\JsonAdm\Exception $e )
223
		{
224
			$status = $e->getCode();
225
			$view->errors = array( array(
226
				'title' => $context->getI18n()->dt( 'admin/jsonadm', $e->getMessage() ),
227
				'detail' => $e->getTraceAsString(),
228
			) );
229
		}
230
		catch( \Aimeos\MAdmin\Exception $e )
231
		{
232
			$status = 404;
233
			$view->errors = array( array(
234
				'title' => $context->getI18n()->dt( 'mshop', $e->getMessage() ),
235
				'detail' => $e->getTraceAsString(),
236
			) );
237
		}
238
		catch( \Aimeos\MShop\Exception $e )
239
		{
240
			$status = 404;
241
			$view->errors = array( array(
242
				'title' => $context->getI18n()->dt( 'mshop', $e->getMessage() ),
243
				'detail' => $e->getTraceAsString(),
244
			) );
245
		}
246
		catch( \Exception $e )
247
		{
248
			$status = 500;
249
			$view->errors = array( array(
250
				'title' => $e->getMessage(),
251
				'detail' => $e->getTraceAsString(),
252
			) );
253
		}
254
255
		/** admin/jsonadm/standard/template-patch
256
		 * Relative path to the JSON API template for PATCH requests
257
		 *
258
		 * The template file contains the code and processing instructions
259
		 * to generate the result shown in the JSON API body. The
260
		 * configuration string is the path to the template file relative
261
		 * to the templates directory (usually in admin/jsonadm/templates).
262
		 *
263
		 * You can overwrite the template file configuration in extensions and
264
		 * provide alternative templates. These alternative templates should be
265
		 * named like the default one but with the string "standard" replaced by
266
		 * an unique name. You may use the name of your project for this. If
267
		 * you've implemented an alternative client class as well, "standard"
268
		 * should be replaced by the name of the new class.
269
		 *
270
		 * @param string Relative path to the template creating the body for the PATCH method of the JSON API
271
		 * @since 2015.12
272
		 * @category Developer
273
		 * @see admin/jsonadm/standard/template-get
274
		 * @see admin/jsonadm/standard/template-post
275
		 * @see admin/jsonadm/standard/template-delete
276
		 * @see admin/jsonadm/standard/template-put
277
		 * @see admin/jsonadm/standard/template-options
278
		 */
279
		$tplconf = 'admin/jsonadm/standard/template-patch';
280
		$default = 'patch-default.php';
281
282
		return $view->render( $view->config( $tplconf, $default ) );
283
	}
284
285
286
	/**
287
	 * Creates or updates the resource or the resource list
288
	 *
289
	 * @param string $body Request body
290
	 * @param array &$header Variable which contains the HTTP headers and the new ones afterwards
291
	 * @param integer &$status Variable which contains the HTTP status afterwards
292
	 * @return string Content for response body
293
	 */
294
	public function post( $body, array &$header, &$status )
295
	{
296
		$header = array( 'Content-Type' => 'application/vnd.api+json; supported-ext="bulk"' );
297
		$context = $this->getContext();
298
		$view = $this->getView();
299
300
		try
301
		{
302
			$view = $this->postItems( $view, $body, $header );
303
			$status = 201;
304
		}
305
		catch( \Aimeos\Admin\JsonAdm\Exception $e )
306
		{
307
			$status = $e->getCode();
308
			$view->errors = array( array(
309
				'title' => $context->getI18n()->dt( 'admin/jsonadm', $e->getMessage() ),
310
				'detail' => $e->getTraceAsString(),
311
			) );
312
		}
313
		catch( \Aimeos\MAdmin\Exception $e )
314
		{
315
			$status = 404;
316
			$view->errors = array( array(
317
				'title' => $context->getI18n()->dt( 'mshop', $e->getMessage() ),
318
				'detail' => $e->getTraceAsString(),
319
			) );
320
		}
321
		catch( \Aimeos\MShop\Exception $e )
322
		{
323
			$status = 404;
324
			$view->errors = array( array(
325
				'title' => $context->getI18n()->dt( 'mshop', $e->getMessage() ),
326
				'detail' => $e->getTraceAsString(),
327
			) );
328
		}
329
		catch( \Exception $e )
330
		{
331
			$status = 500;
332
			$view->errors = array( array(
333
				'title' => $e->getMessage(),
334
				'detail' => $e->getTraceAsString(),
335
			) );
336
		}
337
338
		/** admin/jsonadm/standard/template-post
339
		 * Relative path to the JSON API template for POST requests
340
		 *
341
		 * The template file contains the code and processing instructions
342
		 * to generate the result shown in the JSON API body. The
343
		 * configuration string is the path to the template file relative
344
		 * to the templates directory (usually in admin/jsonadm/templates).
345
		 *
346
		 * You can overwrite the template file configuration in extensions and
347
		 * provide alternative templates. These alternative templates should be
348
		 * named like the default one but with the string "standard" replaced by
349
		 * an unique name. You may use the name of your project for this. If
350
		 * you've implemented an alternative client class as well, "standard"
351
		 * should be replaced by the name of the new class.
352
		 *
353
		 * @param string Relative path to the template creating the body for the POST method of the JSON API
354
		 * @since 2015.12
355
		 * @category Developer
356
		 * @see admin/jsonadm/standard/template-get
357
		 * @see admin/jsonadm/standard/template-patch
358
		 * @see admin/jsonadm/standard/template-delete
359
		 * @see admin/jsonadm/standard/template-put
360
		 * @see admin/jsonadm/standard/template-options
361
		 */
362
		$tplconf = 'admin/jsonadm/standard/template-post';
363
		$default = 'post-default.php';
364
365
		return $view->render( $view->config( $tplconf, $default ) );
366
	}
367
368
369
	/**
370
	 * Creates or updates the resource or the resource list
371
	 *
372
	 * @param string $body Request body
373
	 * @param array &$header Variable which contains the HTTP headers and the new ones afterwards
374
	 * @param integer &$status Variable which contains the HTTP status afterwards
375
	 * @return string Content for response body
376
	 */
377
	public function put( $body, array &$header, &$status )
378
	{
379
		$header = array( 'Content-Type' => 'application/vnd.api+json; supported-ext="bulk"' );
380
		$status = 501;
381
382
		$context = $this->getContext();
383
		$view = $this->getView();
384
385
		$view->errors = array( array(
386
			'title' => $context->getI18n()->dt( 'admin/jsonadm', 'Not implemented, use PATCH instead' ),
387
		) );
388
389
		/** admin/jsonadm/standard/template-put
390
		 * Relative path to the JSON API template for PUT requests
391
		 *
392
		 * The template file contains the code and processing instructions
393
		 * to generate the result shown in the JSON API body. The
394
		 * configuration string is the path to the template file relative
395
		 * to the templates directory (usually in admin/jsonadm/templates).
396
		 *
397
		 * You can overwrite the template file configuration in extensions and
398
		 * provide alternative templates. These alternative templates should be
399
		 * named like the default one but with the string "standard" replaced by
400
		 * an unique name. You may use the name of your project for this. If
401
		 * you've implemented an alternative client class as well, "standard"
402
		 * should be replaced by the name of the new class.
403
		 *
404
		 * @param string Relative path to the template creating the body for the PUT method of the JSON API
405
		 * @since 2015.12
406
		 * @category Developer
407
		 * @see admin/jsonadm/standard/template-delete
408
		 * @see admin/jsonadm/standard/template-patch
409
		 * @see admin/jsonadm/standard/template-post
410
		 * @see admin/jsonadm/standard/template-get
411
		 * @see admin/jsonadm/standard/template-options
412
		 */
413
		$tplconf = 'admin/jsonadm/standard/template-put';
414
		$default = 'put-default.php';
415
416
		return $view->render( $view->config( $tplconf, $default ) );
417
	}
418
419
420
	/**
421
	 * Returns the available REST verbs and the available resources
422
	 *
423
	 * @param string $body Request body
424
	 * @param array &$header Variable which contains the HTTP headers and the new ones afterwards
425
	 * @param integer &$status Variable which contains the HTTP status afterwards
426
	 * @return string Content for response body
427
	 */
428
	public function options( $body, array &$header, &$status )
429
	{
430
		$context = $this->getContext();
431
		$view = $this->getView();
432
433
		try
434
		{
435
			$resources = $attributes = array();
436
437
			foreach( $this->getDomains( $view ) as $domain )
438
			{
439
				$manager = \Aimeos\MShop\Factory::createManager( $context, $domain );
440
				$resources = array_merge( $resources, $manager->getResourceType( true ) );
441
				$attributes = array_merge( $attributes, $manager->getSearchAttributes( true ) );
442
			}
443
444
			$view->resources = $resources;
445
			$view->attributes = $attributes;
446
447
			$header = array(
448
				'Content-Type' => 'application/vnd.api+json; supported-ext="bulk"',
449
				'Allow' => 'DELETE,GET,POST,OPTIONS'
450
			);
451
			$status = 200;
452
		}
453
		catch( \Aimeos\MAdmin\Exception $e )
454
		{
455
			$status = 404;
456
			$view->errors = array( array(
457
				'title' => $context->getI18n()->dt( 'mshop', $e->getMessage() ),
458
				'detail' => $e->getTraceAsString(),
459
			) );
460
		}
461
		catch( \Aimeos\MShop\Exception $e )
462
		{
463
			$status = 404;
464
			$view->errors = array( array(
465
				'title' => $context->getI18n()->dt( 'mshop', $e->getMessage() ),
466
				'detail' => $e->getTraceAsString(),
467
			) );
468
		}
469
		catch( \Exception $e )
470
		{
471
			$status = 500;
472
			$view->errors = array( array(
473
				'title' => $e->getMessage(),
474
				'detail' => $e->getTraceAsString(),
475
			) );
476
		}
477
478
		/** admin/jsonadm/standard/template-options
479
		 * Relative path to the JSON API template for OPTIONS requests
480
		 *
481
		 * The template file contains the code and processing instructions
482
		 * to generate the result shown in the JSON API body. The
483
		 * configuration string is the path to the template file relative
484
		 * to the templates directory (usually in admin/jsonadm/templates).
485
		 *
486
		 * You can overwrite the template file configuration in extensions and
487
		 * provide alternative templates. These alternative templates should be
488
		 * named like the default one but with the string "standard" replaced by
489
		 * an unique name. You may use the name of your project for this. If
490
		 * you've implemented an alternative client class as well, "standard"
491
		 * should be replaced by the name of the new class.
492
		 *
493
		 * @param string Relative path to the template creating the body for the OPTIONS method of the JSON API
494
		 * @since 2015.12
495
		 * @category Developer
496
		 * @see admin/jsonadm/standard/template-delete
497
		 * @see admin/jsonadm/standard/template-patch
498
		 * @see admin/jsonadm/standard/template-post
499
		 * @see admin/jsonadm/standard/template-get
500
		 * @see admin/jsonadm/standard/template-put
501
		 */
502
		$tplconf = 'admin/jsonadm/standard/template-options';
503
		$default = 'options-default.php';
504
505
		return $view->render( $view->config( $tplconf, $default ) );
506
	}
507
508
509
	/**
510
	 * Deletes one or more items
511
	 *
512
	 * @param \Aimeos\MW\View\Iface $view View instance with "param" view helper
513
	 * @param string $body Request body
514
	 * @return \Aimeos\MW\View\Iface $view View object that will contain the "total" property afterwards
515
	 * @throws \Aimeos\Admin\JsonAdm\Exception If the request body is invalid
516
	 */
517
	protected function deleteItems( \Aimeos\MW\View\Iface $view, $body )
518
	{
519
		$manager = \Aimeos\MShop\Factory::createManager( $this->getContext(), $this->getPath() );
520
521
		if( ( $id = $view->param( 'id' ) ) == null )
522
		{
523
			if( ( $request = json_decode( $body ) ) === null || !isset( $request->data ) || !is_array( $request->data ) ) {
524
				throw new \Aimeos\Admin\JsonAdm\Exception( sprintf( 'Invalid JSON in body' ), 400 );
525
			}
526
527
			$ids = array();
528
529
			foreach( $request->data as $entry )
530
			{
531
				if( isset( $entry->id ) ) {
532
					$ids[] = $entry->id;
533
				}
534
			}
535
536
			$manager->deleteItems( $ids );
537
			$view->total = count( $ids );
538
		}
539
		else
540
		{
541
			$manager->deleteItem( $id );
542
			$view->total = 1;
543
		}
544
545
		return $view;
546
	}
547
548
549
	/**
550
	 * Retrieves the item or items and adds the data to the view
551
	 *
552
	 * @param \Aimeos\MW\View\Iface $view View instance
553
	 * @return \Aimeos\MW\View\Iface View instance with additional data assigned
554
	 */
555
	protected function getItem( \Aimeos\MW\View\Iface $view )
556
	{
557
		$total = 1;
558
		$manager = \Aimeos\MShop\Factory::createManager( $this->getContext(), $this->getPath() );
559
		$include = ( ( $include = $view->param( 'include' ) ) !== null ? explode( ',', $include ) : array() );
560
561
		if( ( $id = $view->param( 'id' ) ) == null )
562
		{
563
			$search = $this->initCriteria( $manager->createSearch(), $view->param() );
564
			$view->data = $manager->searchItems( $search, array(), $total );
565
			$view->childItems = $this->getChildItems( $view->data, $include );
566
			$view->listItems = $this->getListItems( $view->data, $include );
567
		}
568
		else
569
		{
570
			$view->data = $manager->getItem( $id, array() );
571
			$view->childItems = $this->getChildItems( array( $id => $view->data ), $include );
572
			$view->listItems = $this->getListItems( array( $id => $view->data ), $include );
573
		}
574
575
		$view->refItems = $this->getRefItems( $view->listItems );
576
577
		$view->total = $total;
578
579
		return $view;
580
	}
581
582
	/**
583
	 * Returns the view object
584
	 *
585
	 * @return \Aimeos\MW\View\Iface View object
586
	 */
587
	protected function getView()
588
	{
589
		return $this->view;
590
	}
591
592
593
	/**
594
	 * Initializes the criteria object based on the given parameter
595
	 *
596
	 * @param \Aimeos\MW\Criteria\Iface $criteria Criteria object
597
	 * @param array $params List of criteria data with condition, sorting and paging
598
	 * @return \Aimeos\MW\Criteria\Iface Initialized criteria object
599
	 */
600
	protected function initCriteria( \Aimeos\MW\Criteria\Iface $criteria, array $params )
601
	{
602
		$this->initCriteriaConditions( $criteria, $params );
603
		$this->initCriteriaSortations( $criteria, $params );
604
		$this->initCriteriaSlice( $criteria, $params );
605
606
		return $criteria;
607
	}
608
609
610
	/**
611
	 * Initializes the criteria object with conditions based on the given parameter
612
	 *
613
	 * @param \Aimeos\MW\Criteria\Iface $criteria Criteria object
614
	 * @param array $params List of criteria data with condition, sorting and paging
615
	 */
616
	private function initCriteriaConditions( \Aimeos\MW\Criteria\Iface $criteria, array $params )
617
	{
618
		if( isset( $params['filter'] ) && is_array( $params['filter'] ) )
619
		{
620
			$existing = $criteria->getConditions();
621
			$criteria->setConditions( $criteria->toConditions( (array) $params['filter'] ) );
622
623
			$expr = array( $criteria->getConditions(), $existing );
624
			$criteria->setConditions( $criteria->combine( '&&', $expr ) );
625
		}
626
	}
627
628
629
	/**
630
	 * Initializes the criteria object with the slice based on the given parameter.
631
	 *
632
	 * @param \Aimeos\MW\Criteria\Iface $criteria Criteria object
633
	 * @param array $params List of criteria data with condition, sorting and paging
634
	 */
635
	private function initCriteriaSlice( \Aimeos\MW\Criteria\Iface $criteria, array $params )
636
	{
637
		$start = ( isset( $params['page']['offset'] ) ? $params['page']['offset'] : 0 );
638
		$size = ( isset( $params['page']['limit'] ) ? $params['page']['limit'] : 25 );
639
640
		$criteria->setSlice( $start, $size );
641
	}
642
643
644
	/**
645
	 * Initializes the criteria object with sortations based on the given parameter
646
	 *
647
	 * @param \Aimeos\MW\Criteria\Iface $criteria Criteria object
648
	 * @param array $params List of criteria data with condition, sorting and paging
649
	 */
650
	private function initCriteriaSortations( \Aimeos\MW\Criteria\Iface $criteria, array $params )
651
	{
652
		if( !isset( $params['sort'] ) ) {
653
			return;
654
		}
655
656
		$sortation = array();
657
658
		foreach( explode( ',', $params['sort'] ) as $sort )
659
		{
660
			if( $sort[0] === '-' ) {
661
				$sortation[] = $criteria->sort( '-', substr( $sort, 1 ) );
662
			} else {
663
				$sortation[] = $criteria->sort( '+', $sort ); break;
664
			}
665
		}
666
667
		$criteria->setSortations( $sortation );
668
	}
669
670
671
	/**
672
	 * Returns the list of domains that are available as resources
673
	 *
674
	 * @param \Aimeos\MW\View\Iface $view View object with "resource" parameter
675
	 * @return array List of domain names
676
	 */
677
	protected function getDomains( \Aimeos\MW\View\Iface $view )
678
	{
679
		if( ( $domains = $view->param( 'resource' ) ) == '' )
680
		{
681
			/** admin/jsonadm/domains
682
			 * A list of domain names whose clients are available for the JSON API
683
			 *
684
			 * The HTTP OPTIONS method returns a list of resources known by the
685
			 * JSON API including their URLs. The list of available resources
686
			 * can be exteded dynamically be implementing a new Jsonadm client
687
			 * class handling request for this new domain.
688
			 *
689
			 * To add the new domain client to the list of resources returned
690
			 * by the HTTP OPTIONS method, you have to add its name in lower case
691
			 * to the existing configuration.
692
			 *
693
			 * @param array List of domain names
694
			 * @since 2016.01
695
			 * @category Developer
696
			 */
697
			$default = array(
698
				'attribute', 'catalog', 'coupon', 'customer', 'locale', 'media',
699
				'order', 'plugin', 'price', 'product', 'service', 'supplier', 'tag', 'text'
700
			);
701
			$domains = $this->getContext()->getConfig()->get( 'admin/jsonadm/domains', $default );
702
		}
703
704
		return (array) $domains;
705
	}
706
707
708
	/**
709
	 * Returns the items with parent/child relationships
710
	 *
711
	 * @param array $items List of items implementing \Aimeos\MShop\Common\Item\Iface
712
	 * @param array $include List of resource types that should be fetched
713
	 * @return array List of items implementing \Aimeos\MShop\Common\Item\Iface
714
	 */
715
	protected function getChildItems( array $items, array $include )
716
	{
717
		return array();
718
	}
719
720
721
	/**
722
	 * Returns the list items for association relationships
723
	 *
724
	 * @param array $items List of items implementing \Aimeos\MShop\Common\Item\Iface
725
	 * @param array $include List of resource types that should be fetched
726
	 * @return array List of items implementing \Aimeos\MShop\Common\Item\Lists\Iface
727
	 */
728
	protected function getListItems( array $items, array $include )
729
	{
730
		return array();
731
	}
732
733
734
	/**
735
	 * Returns the items associated via a lists table
736
	 *
737
	 * @param array $listItems List of items implementing \Aimeos\MShop\Common\Item\Lists\Iface
738
	 * @return array List of items implementing \Aimeos\MShop\Common\Item\Iface
739
	 */
740
	protected function getRefItems( array $listItems )
741
	{
742
		$list = $map = array();
743
744
		foreach( $listItems as $listItem ) {
745
			$map[$listItem->getDomain()][] = $listItem->getRefId();
746
		}
747
748
		foreach( $map as $domain => $ids )
749
		{
750
			$manager = \Aimeos\MShop\Factory::createManager( $this->getContext(), $domain );
751
752
			$search = $manager->createSearch();
753
			$search->setConditions( $search->compare( '==', $domain . '.id', $ids ) );
754
755
			$list = array_merge( $list, $manager->searchItems( $search ) );
756
		}
757
758
		return $list;
759
	}
760
761
762
	/**
763
	 * Returns the context item object
764
	 *
765
	 * @return \Aimeos\MShop\Context\Item\Iface Context object
766
	 */
767
	protected function getContext()
768
	{
769
		return $this->context;
770
	}
771
772
773
	/**
774
	 * Returns the paths to the template files
775
	 *
776
	 * @return array List of file system paths
777
	 */
778
	protected function getTemplatePaths()
779
	{
780
		return $this->templatePaths;
781
	}
782
783
784
	/**
785
	 * Returns the path to the client
786
	 *
787
	 * @return string Client path, e.g. "product/stock"
788
	 */
789
	protected function getPath()
790
	{
791
		return $this->path;
792
	}
793
794
795
	/**
796
	 * Saves new attributes for one or more items
797
	 *
798
	 * @param \Aimeos\MW\View\Iface $view View that will contain the "data" and "total" properties afterwards
799
	 * @param string $body Request body
800
	 * @param array &$header Associative list of HTTP headers as value/result parameter
801
	 * @throws \Aimeos\Admin\JsonAdm\Exception If "id" parameter isn't available or the body is invalid
802
	 * @return \Aimeos\MW\View\Iface Updated view instance
803
	 */
804
	protected function patchItems( \Aimeos\MW\View\Iface $view, $body, array &$header )
805
	{
806
		if( ( $request = json_decode( $body ) ) === null || !isset( $request->data ) ) {
807
			throw new \Aimeos\Admin\JsonAdm\Exception( sprintf( 'Invalid JSON in body' ), 400 );
808
		}
809
810
		$manager = \Aimeos\MShop\Factory::createManager( $this->getContext(), $this->getPath() );
811
812
		if( is_array( $request->data ) )
813
		{
814
			$data = $this->saveData( $manager, $request );
815
816
			$view->data = $data;
817
			$view->total = count( $data );
818
			$header['Content-Type'] = 'application/vnd.api+json; ext="bulk"; supported-ext="bulk"';
819
		}
820
		else
821
		{
822
			if( ( $id = $view->param( 'id' ) ) == null ) {
823
				throw new \Aimeos\Admin\JsonAdm\Exception( sprintf( 'No ID given' ), 400 );
824
			}
825
826
			$request->data->id = $id;
827
			$data = $this->saveEntry( $manager, $request->data );
828
829
			$view->data = $data;
830
			$view->total = 1;
831
		}
832
833
		return $view;
834
	}
835
836
837
	/**
838
	 * Creates one or more new items
839
	 *
840
	 * @param \Aimeos\MW\View\Iface $view View that will contain the "data" and "total" properties afterwards
841
	 * @param string $body Request body
842
	 * @param array &$header Associative list of HTTP headers as value/result parameter
843
	 * @return \Aimeos\MW\View\Iface Updated view instance
844
	 */
845
	protected function postItems( \Aimeos\MW\View\Iface $view, $body, array &$header )
846
	{
847
		if( ( $request = json_decode( $body ) ) === null || !isset( $request->data ) ) {
848
			throw new \Aimeos\Admin\JsonAdm\Exception( sprintf( 'Invalid JSON in body' ), 400 );
849
		}
850
851
		if( isset( $request->data->id ) || $view->param( 'id' ) != null ) {
852
			throw new \Aimeos\Admin\JsonAdm\Exception( sprintf( 'Client generated IDs are not supported' ), 403 );
853
		}
854
855
856
		$manager = \Aimeos\MShop\Factory::createManager( $this->getContext(), $this->getPath() );
857
858
		if( is_array( $request->data ) )
859
		{
860
			$data = $this->saveData( $manager, $request );
861
862
			$view->data = $data;
863
			$view->total = count( $data );
864
			$header['Content-Type'] = 'application/vnd.api+json; ext="bulk"; supported-ext="bulk"';
865
		}
866
		else
867
		{
868
			$request->data->id = null;
869
			$data = $this->saveEntry( $manager, $request->data );
870
871
			$view->data = $data;
872
			$view->total = 1;
873
		}
874
875
		return $view;
876
	}
877
878
879
	/**
880
	 * Creates of updates several items at once
881
	 *
882
	 * @param \Aimeos\MShop\Common\Manager\Iface $manager Manager responsible for the items
883
	 * @param \stdClass $request Object with request body data
884
	 * @return array List of items
885
	 */
886
	protected function saveData( \Aimeos\MShop\Common\Manager\Iface $manager, \stdClass $request )
887
	{
888
		$data = array();
889
890
		if( isset( $request->data ) )
891
		{
892
			foreach( (array) $request->data as $entry ) {
893
				$data[] = $this->saveEntry( $manager, $entry );
894
			}
895
		}
896
897
		return $data;
898
	}
899
900
901
	/**
902
	 * Saves and returns the new or updated item
903
	 *
904
	 * @param \Aimeos\MShop\Common\Manager\Iface $manager Manager responsible for the items
905
	 * @param \stdClass $entry Object including "id" and "attributes" elements
906
	 * @return \Aimeos\MShop\Common\Item\Iface New or updated item
907
	 */
908
	protected function saveEntry( \Aimeos\MShop\Common\Manager\Iface $manager, \stdClass $entry )
909
	{
910
		$attr = ( isset( $entry->attributes ) ? (array) $entry->attributes : array() );
911
912
		if( isset( $entry->id ) && $entry->id !== null ) {
913
			$item = $manager->getItem( $entry->id );
914
		} else {
915
			$item = $manager->createItem();
916
		}
917
918
		$item->fromArray( $attr );
919
		$manager->saveItem( $item );
920
921
		return $manager->getItem( $item->getId() );
922
	}
923
}
924