Completed
Push — master ( 1df7b3...55696d )
by Aimeos
14:53
created

Base::saveRelationships()   B

Complexity

Conditions 5
Paths 5

Size

Total Lines 26
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 26
rs 8.439
c 0
b 0
f 0
cc 5
eloc 13
nc 5
nop 3
1
<?php
2
3
/**
4
 * @license LGPLv3, http://opensource.org/licenses/LGPL-3.0
5
 * @copyright Aimeos (aimeos.org), 2015-2017
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
abstract class Base
21
{
22
	private $context;
23
	private $aimeos;
24
	private $view;
25
	private $path;
26
27
28
	/**
29
	 * Initializes the client
30
	 *
31
	 * @param \Aimeos\MShop\Context\Item\Iface $context MShop context object
32
	 * @param string $path Name of the client separated by slashes, e.g "product/property"
33
	 */
34
	public function __construct( \Aimeos\MShop\Context\Item\Iface $context, $path )
35
	{
36
		$this->context = $context;
37
		$this->path = $path;
38
	}
39
40
41
	/**
42
	 * Catch unknown methods
43
	 *
44
	 * @param string $name Name of the method
45
	 * @param array $param List of method parameter
46
	 * @throws \Aimeos\Admin\JsonAdm\Exception If method call failed
47
	 */
48
	public function __call( $name, array $param )
49
	{
50
		throw new \Aimeos\Admin\JsonAdm\Exception( sprintf( 'Unable to call method "%1$s"', $name ) );
51
	}
52
53
54
	/**
55
	 * Returns the Aimeos bootstrap object
56
	 *
57
	 * @return \Aimeos\Bootstrap The Aimeos bootstrap object
58
	 */
59
	public function getAimeos()
60
	{
61
		if( !isset( $this->aimeos ) ) {
62
			throw new \Aimeos\Admin\JsonAdm\Exception( sprintf( 'Aimeos object not available' ) );
63
		}
64
65
		return $this->aimeos;
66
	}
67
68
69
	/**
70
	 * Sets the Aimeos bootstrap object
71
	 *
72
	 * @param \Aimeos\Bootstrap $aimeos The Aimeos bootstrap object
73
	 * @return \Aimeos\Admin\JQAdm\Iface Reference to this object for fluent calls
74
	 */
75
	public function setAimeos( \Aimeos\Bootstrap $aimeos )
76
	{
77
		$this->aimeos = $aimeos;
78
		return $this;
79
	}
80
81
82
	/**
83
	 * Returns the view object that will generate the admin output.
84
	 *
85
	 * @return \Aimeos\MW\View\Iface The view object which generates the admin output
86
	 */
87
	public function getView()
88
	{
89
		if( !isset( $this->view ) ) {
90
			throw new \Aimeos\Admin\JsonAdm\Exception( sprintf( 'No view available' ) );
91
		}
92
93
		return $this->view;
94
	}
95
96
97
	/**
98
	 * Sets the view object that will generate the admin output.
99
	 *
100
	 * @param \Aimeos\MW\View\Iface $view The view object which generates the admin output
101
	 * @return \Aimeos\Admin\JQAdm\Iface Reference to this object for fluent calls
102
	 */
103
	public function setView( \Aimeos\MW\View\Iface $view )
104
	{
105
		$this->view = $view;
106
		return $this;
107
	}
108
109
110
	/**
111
	 * Returns the items with parent/child relationships
112
	 *
113
	 * @param array $items List of items implementing \Aimeos\MShop\Common\Item\Iface
114
	 * @param array $include List of resource types that should be fetched
115
	 * @return array List of items implementing \Aimeos\MShop\Common\Item\Iface
116
	 */
117
	protected function getChildItems( array $items, array $include )
118
	{
119
		return [];
120
	}
121
122
123
	/**
124
	 * Returns the context item object
125
	 *
126
	 * @return \Aimeos\MShop\Context\Item\Iface Context object
127
	 */
128
	protected function getContext()
129
	{
130
		return $this->context;
131
	}
132
133
134
	/**
135
	 * Returns the list of domains that are available as resources
136
	 *
137
	 * @param \Aimeos\MW\View\Iface $view View object with "resource" parameter
138
	 * @return array List of domain names
139
	 */
140
	protected function getDomains( \Aimeos\MW\View\Iface $view )
141
	{
142
		if( ( $domains = $view->param( 'resource' ) ) == '' )
143
		{
144
			/** admin/jsonadm/domains
145
			 * A list of domain names whose clients are available for the JSON API
146
			 *
147
			 * The HTTP OPTIONS method returns a list of resources known by the
148
			 * JSON API including their URLs. The list of available resources
149
			 * can be exteded dynamically be implementing a new Jsonadm client
150
			 * class handling request for this new domain.
151
			 *
152
			 * To add the new domain client to the list of resources returned
153
			 * by the HTTP OPTIONS method, you have to add its name in lower case
154
			 * to the existing configuration.
155
			 *
156
			 * @param array List of domain names
157
			 * @since 2016.01
158
			 * @category Developer
159
			 * @see admin/jsonadm/resources
160
			 */
161
			$default = array(
162
				'attribute', 'catalog', 'coupon', 'customer', 'locale', 'media', 'order',
163
				'plugin', 'price', 'product', 'service', 'supplier', 'stock', 'tag', 'text'
164
			);
165
			$domains = $this->getContext()->getConfig()->get( 'admin/jsonadm/domains', $default );
166
		}
167
168
		return (array) $domains;
169
	}
170
171
172
	/**
173
	 * Returns the IDs sent in the request body
174
	 *
175
	 * @param \stdClass $request Decoded request body
176
	 * @return array List of item IDs
177
	 */
178
	protected function getIds( $request )
179
	{
180
		$ids = [];
181
182
		if( isset( $request->data ) )
183
		{
184
			foreach( (array) $request->data as $entry )
185
			{
186
				if( isset( $entry->id ) ) {
187
					$ids[] = $entry->id;
188
				}
189
			}
190
		}
191
192
		return $ids;
193
	}
194
195
196
	/**
197
	 * Returns the list items for association relationships
198
	 *
199
	 * @param array $items List of items implementing \Aimeos\MShop\Common\Item\Iface
200
	 * @param array $include List of resource types that should be fetched
201
	 * @return array List of items implementing \Aimeos\MShop\Common\Item\Lists\Iface
202
	 */
203
	protected function getListItems( array $items, array $include )
204
	{
205
		return [];
206
	}
207
208
209
	/**
210
	 * Returns the path to the client
211
	 *
212
	 * @return string Client path, e.g. "product/property"
213
	 */
214
	protected function getPath()
215
	{
216
		return $this->path;
217
	}
218
219
220
	/**
221
	 * Returns the items associated via a lists table
222
	 *
223
	 * @param array $listItems List of items implementing \Aimeos\MShop\Common\Item\Lists\Iface
224
	 * @return array List of items implementing \Aimeos\MShop\Common\Item\Iface
225
	 */
226
	protected function getRefItems( array $listItems )
227
	{
228
		$list = $map = [];
229
		$context = $this->getContext();
230
231
		foreach( $listItems as $listItem ) {
232
			$map[$listItem->getDomain()][] = $listItem->getRefId();
233
		}
234
235
		foreach( $map as $domain => $ids )
236
		{
237
			$manager = \Aimeos\MShop\Factory::createManager( $context, $domain );
238
239
			$search = $manager->createSearch();
240
			$search->setConditions( $search->compare( '==', $domain . '.id', $ids ) );
241
242
			$list = array_merge( $list, $manager->searchItems( $search ) );
243
		}
244
245
		return $list;
246
	}
247
248
249
	/**
250
	 * Returns the list of allowed resources
251
	 *
252
	 * @param \Aimeos\MW\View\Iface $view View object with "access" helper
253
	 * @param array List of all available resources
254
	 * @return array List of allowed resources
255
	 */
256
	protected function getAllowedResources( \Aimeos\MW\View\Iface $view, array $resources )
257
	{
258
		$config = $this->getContext()->getConfig();
259
		$allowed = [];
260
261
		foreach( $resources as $resource )
262
		{
263
			if( $view->access( $config->get( 'admin/jsonadm/resource/' . $resource . '/groups', [] ) ) === true ) {
264
				$allowed[] = $resource;
265
			}
266
		}
267
268
		return $allowed;
269
	}
270
271
272
	/**
273
	 * Returns the list of additional resources
274
	 *
275
	 * @param \Aimeos\MW\View\Iface $view View object with "resource" parameter
276
	 * @return array List of domain names
277
	 */
278
	protected function getResources( \Aimeos\MW\View\Iface $view )
279
	{
280
		/** admin/jsonadm/resources
281
		 * A list of additional resources name whose clients are available for the JSON API
282
		 *
283
		 * The HTTP OPTIONS method returns a list of resources known by the
284
		 * JSON API including their URLs. The list of available resources
285
		 * can be exteded dynamically be implementing a new Jsonadm client
286
		 * class handling request for this new domain.
287
		 *
288
		 * The resource config lists the resources that are not automatically
289
		 * derived from the admin/jsonadm/domains configuration.
290
		 *
291
		 * @param array List of domain names
292
		 * @since 2017.07
293
		 * @category Developer
294
		 * @see admin/jsonadm/domains
295
		 */
296
		return (array) $view->config( 'admin/jsonadm/resources', ['coupon/config', 'plugin/config', 'service/config'] );
297
	}
298
299
300
	/**
301
	 * Initializes the criteria object based on the given parameter
302
	 *
303
	 * @param \Aimeos\MW\Criteria\Iface $criteria Criteria object
304
	 * @param array $params List of criteria data with condition, sorting and paging
305
	 * @return \Aimeos\MW\Criteria\Iface Initialized criteria object
306
	 */
307
	protected function initCriteria( \Aimeos\MW\Criteria\Iface $criteria, array $params )
308
	{
309
		$this->initCriteriaConditions( $criteria, $params );
310
		$this->initCriteriaSortations( $criteria, $params );
311
		$this->initCriteriaSlice( $criteria, $params );
312
313
		return $criteria;
314
	}
315
316
317
	/**
318
	 * Initializes the criteria object with conditions based on the given parameter
319
	 *
320
	 * @param \Aimeos\MW\Criteria\Iface $criteria Criteria object
321
	 * @param array $params List of criteria data with condition, sorting and paging
322
	 */
323
	protected function initCriteriaConditions( \Aimeos\MW\Criteria\Iface $criteria, array $params )
324
	{
325
		if( !isset( $params['filter'] ) ) {
326
			return;
327
		}
328
329
		$existing = $criteria->getConditions();
330
		$criteria->setConditions( $criteria->toConditions( (array) $params['filter'] ) );
331
332
		$expr = array( $criteria->getConditions(), $existing );
333
		$criteria->setConditions( $criteria->combine( '&&', $expr ) );
334
	}
335
336
337
	/**
338
	 * Initializes the criteria object with the slice based on the given parameter.
339
	 *
340
	 * @param \Aimeos\MW\Criteria\Iface $criteria Criteria object
341
	 * @param array $params List of criteria data with condition, sorting and paging
342
	 */
343
	protected function initCriteriaSlice( \Aimeos\MW\Criteria\Iface $criteria, array $params )
344
	{
345
		$start = ( isset( $params['page']['offset'] ) ? (int) $params['page']['offset'] : 0 );
346
		$size = ( isset( $params['page']['limit'] ) ? (int) $params['page']['limit'] : 25 );
347
348
		$criteria->setSlice( $start, $size );
349
	}
350
351
352
	/**
353
	 * Initializes the criteria object with sortations based on the given parameter
354
	 *
355
	 * @param \Aimeos\MW\Criteria\Iface $criteria Criteria object
356
	 * @param array $params List of criteria data with condition, sorting and paging
357
	 */
358
	protected function initCriteriaSortations( \Aimeos\MW\Criteria\Iface $criteria, array $params )
359
	{
360
		if( !isset( $params['sort'] ) ) {
361
			return;
362
		}
363
364
		$sortation = [];
365
366
		foreach( explode( ',', $params['sort'] ) as $sort )
367
		{
368
			if( $sort[0] === '-' ) {
369
				$sortation[] = $criteria->sort( '-', substr( $sort, 1 ) );
370
			} else {
371
				$sortation[] = $criteria->sort( '+', $sort );
372
			}
373
		}
374
375
		$criteria->setSortations( $sortation );
376
	}
377
378
379
	/**
380
	 * Creates of updates several items at once
381
	 *
382
	 * @param \Aimeos\MShop\Common\Manager\Iface $manager Manager responsible for the items
383
	 * @param \stdClass $request Object with request body data
384
	 * @return array List of items
385
	 */
386
	protected function saveData( \Aimeos\MShop\Common\Manager\Iface $manager, \stdClass $request )
387
	{
388
		$data = [];
389
390
		if( isset( $request->data ) )
391
		{
392
			foreach( (array) $request->data as $entry ) {
393
				$data[] = $this->saveEntry( $manager, $entry );
394
			}
395
		}
396
397
		return $data;
398
	}
399
400
401
	/**
402
	 * Saves and returns the new or updated item
403
	 *
404
	 * @param \Aimeos\MShop\Common\Manager\Iface $manager Manager responsible for the items
405
	 * @param \stdClass $entry Object including "id" and "attributes" elements
406
	 * @return \Aimeos\MShop\Common\Item\Iface New or updated item
407
	 */
408
	protected function saveEntry( \Aimeos\MShop\Common\Manager\Iface $manager, \stdClass $entry )
409
	{
410
		if( isset( $entry->id ) ) {
411
			$item = $manager->getItem( $entry->id );
412
		} else {
413
			$item = $manager->createItem();
414
		}
415
416
		$item = $this->addItemData( $manager, $item, $entry, $item->getResourceType() );
417
		$item = $manager->saveItem( $item );
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $item is correct as $manager->saveItem($item) (which targets Aimeos\MShop\Common\Manager\Iface::saveItem()) seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
418
419
		if( isset( $entry->relationships ) ) {
420
			$this->saveRelationships( $manager, $item, $entry->relationships );
0 ignored issues
show
Documentation introduced by
$item is of type null, but the function expects a object<Aimeos\MShop\Common\Item\Iface>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
421
		}
422
423
		return $manager->getItem( $item->getId() );
0 ignored issues
show
Bug introduced by
The method getId cannot be called on $item (of type null).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
424
	}
425
426
427
	/**
428
	 * Saves the item references associated via the list
429
	 *
430
	 * @param \Aimeos\MShop\Common\Manager\Iface $manager Manager responsible for the items
431
	 * @param \Aimeos\MShop\Common\Item\Iface $item Domain item with an unique ID set
432
	 * @param \stdClass $relationships Object including the <domain>/data/attributes structure
433
	 */
434
	protected function saveRelationships( \Aimeos\MShop\Common\Manager\Iface $manager,
435
		\Aimeos\MShop\Common\Item\Iface $item, \stdClass $relationships )
436
	{
437
		$id = $item->getId();
438
		$listManager = $manager->getSubManager( 'lists' );
439
440
		foreach( (array) $relationships as $domain => $list )
441
		{
442
			if( isset( $list->data ) )
443
			{
444
				foreach( (array) $list->data as $data )
445
				{
446
					$listItem = $this->addItemData( $listManager, $listManager->createItem(), $data, $domain );
447
448
					if( isset( $data->id ) ) {
449
						$listItem->setRefId( $data->id );
450
					}
451
452
					$listItem->setParentId( $id );
453
					$listItem->setDomain( $domain );
454
455
					$listManager->saveItem( $listItem, false );
456
				}
457
			}
458
		}
459
	}
460
461
462
	/**
463
	 * Adds the data from the given object to the item
464
	 *
465
	 * @param \Aimeos\MShop\Common\Manager\Iface $manager Manager object
466
	 * @param \Aimeos\MShop\Common\Item\Iface $item Item object to add the data to
467
	 * @param \stdClass $data Object with "attributes" property
468
	 * @param string $domain Domain of the type item
469
	 * @return \Aimeos\MShop\Common\Item\Iface Item including the data
470
	 */
471
	protected function addItemData(\Aimeos\MShop\Common\Manager\Iface $manager,
472
		\Aimeos\MShop\Common\Item\Iface $item, \stdClass $data, $domain )
473
	{
474
		if( isset( $data->attributes ) )
475
		{
476
			$attr = (array) $data->attributes;
477
			$key = str_replace( '/', '.', $item->getResourceType() );
478
479
			if( isset( $attr[$key.'.type'] ) )
480
			{
481
				$typeItem = $manager->getSubManager( 'type' )->findItem( $attr[$key.'.type'], [], $domain );
482
				$attr[$key.'.typeid'] = $typeItem->getId();
483
			}
484
485
			$item->fromArray( $attr );
486
		}
487
488
		return $item;
489
	}
490
}
491