Completed
Push — master ( f8cfd0...9703dd )
by Aimeos
09:46
created

Base::getAllowedResources()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 14
rs 9.7998
c 0
b 0
f 0
cc 3
nc 3
nop 2
1
<?php
2
3
/**
4
 * @license LGPLv3, http://opensource.org/licenses/LGPL-3.0
5
 * @copyright Aimeos (aimeos.org), 2015-2021
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, string $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( string $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() : \Aimeos\Bootstrap
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\JsonAdm\Iface Reference to this object for fluent calls
0 ignored issues
show
Documentation introduced by
Should the return type not be Base?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
74
	 */
75
	public function setAimeos( \Aimeos\Bootstrap $aimeos ) : \Aimeos\Admin\JsonAdm\Iface
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() : \Aimeos\MW\View\Iface
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\JsonAdm\Iface Reference to this object for fluent calls
0 ignored issues
show
Documentation introduced by
Should the return type not be Base?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
102
	 */
103
	public function setView( \Aimeos\MW\View\Iface $view ) : \Aimeos\Admin\JsonAdm\Iface
104
	{
105
		$this->view = $view;
106
		return $this;
107
	}
108
109
110
	/**
111
	 * Returns the items with parent/child relationships
112
	 *
113
	 * @param \Aimeos\Map $items List of items implementing \Aimeos\MShop\Common\Item\Iface
114
	 * @param array $include List of resource types that should be fetched
115
	 * @return \Aimeos\Map List of items implementing \Aimeos\MShop\Common\Item\Iface
116
	 */
117
	protected function getChildItems( \Aimeos\Map $items, array $include ) : \Aimeos\Map
118
	{
119
		return map();
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() : \Aimeos\MShop\Context\Item\Iface
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 ) : array
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
			$domains = $this->getContext()->getConfig()->get( 'admin/jsonadm/domains', [] );
162
		}
163
164
		return (array) $domains;
165
	}
166
167
168
	/**
169
	 * Returns the list items for association relationships
170
	 *
171
	 * @param \Aimeos\Map $items List of items implementing \Aimeos\MShop\Common\Item\Iface
172
	 * @param array $include List of resource types that should be fetched
173
	 * @return array List of items implementing \Aimeos\MShop\Common\Item\Lists\Iface
0 ignored issues
show
Documentation introduced by
Should the return type not be \Aimeos\Map?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
174
	 */
175
	protected function getListItems( \Aimeos\Map $items, array $include ) : \Aimeos\Map
0 ignored issues
show
Unused Code introduced by
The parameter $include is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
176
	{
177
		return $items->filter( function( $item ) {
178
			return $item instanceof \Aimeos\MShop\Common\Item\Lists\Iface;
179
		} );
180
	}
181
182
183
	/**
184
	 * Returns the path to the client
185
	 *
186
	 * @return string Client path, e.g. "product/property"
187
	 */
188
	protected function getPath() : string
189
	{
190
		return $this->path;
191
	}
192
193
194
	/**
195
	 * Returns the items associated via a lists table
196
	 *
197
	 * @param \Aimeos\Map $listItems List of items implementing \Aimeos\MShop\Common\Item\Lists\Iface
198
	 * @return \Aimeos\Map List of items implementing \Aimeos\MShop\Common\Item\Iface
199
	 */
200
	protected function getRefItems( \Aimeos\Map $listItems ) : \Aimeos\Map
201
	{
202
		$list = [];
203
204
		foreach( $listItems as $listItem )
205
		{
206
			if( $refItem = $listItem->getRefItem() ) {
207
				$list[$refItem->getResourceType() . '-' . $refItem->getId()] = $refItem;
208
			}
209
		}
210
211
		return map( $list );
212
	}
213
214
215
	/**
216
	 * Returns the list of allowed resources
217
	 *
218
	 * @param \Aimeos\MW\View\Iface $view View object with "access" helper
219
	 * @param array List of all available resources
220
	 * @return array List of allowed resources
221
	 */
222
	protected function getAllowedResources( \Aimeos\MW\View\Iface $view, array $resources ) : array
223
	{
224
		$config = $this->getContext()->getConfig();
225
		$allowed = [];
226
227
		foreach( $resources as $resource )
228
		{
229
			if( $view->access( $config->get( 'admin/jsonadm/resource/' . $resource . '/groups', [] ) ) === true ) {
230
				$allowed[] = $resource;
231
			}
232
		}
233
234
		return $allowed;
235
	}
236
237
238
	/**
239
	 * Returns the list of additional resources
240
	 *
241
	 * @param \Aimeos\MW\View\Iface $view View object with "resource" parameter
242
	 * @return array List of domain names
243
	 */
244
	protected function getResources( \Aimeos\MW\View\Iface $view ) : array
245
	{
246
		/** admin/jsonadm/resources
247
		 * A list of additional resources name whose clients are available for the JSON API
248
		 *
249
		 * The HTTP OPTIONS method returns a list of resources known by the
250
		 * JSON API including their URLs. The list of available resources
251
		 * can be exteded dynamically be implementing a new Jsonadm client
252
		 * class handling request for this new domain.
253
		 *
254
		 * The resource config lists the resources that are not automatically
255
		 * derived from the admin/jsonadm/domains configuration.
256
		 *
257
		 * @param array List of domain names
258
		 * @since 2017.07
259
		 * @category Developer
260
		 * @see admin/jsonadm/domains
261
		 */
262
		return (array) $view->config( 'admin/jsonadm/resources', [] );
263
	}
264
265
266
	/**
267
	 * Initializes the criteria object based on the given parameter
268
	 *
269
	 * @param \Aimeos\MW\Criteria\Iface $criteria Criteria object
270
	 * @param array $params List of criteria data with condition, sorting and paging
271
	 * @return \Aimeos\MW\Criteria\Iface Initialized criteria object
272
	 */
273
	protected function initCriteria( \Aimeos\MW\Criteria\Iface $criteria, array $params ) : \Aimeos\MW\Criteria\Iface
274
	{
275
		return $criteria->order( $params['sort'] ?? [] )
276
			->add( $criteria->parse( $params['filter'] ?? [] ) )
277
			->slice( $params['page']['offset'] ?? 0, $params['page']['limit'] ?? 25 );
278
	}
279
280
281
	/**
282
	 * Creates of updates several items at once
283
	 *
284
	 * @param \Aimeos\MShop\Common\Manager\Iface $manager Manager responsible for the items
285
	 * @param \stdClass $request Object with request body data
286
	 * @return \Aimeos\Map List of items
287
	 */
288
	protected function saveData( \Aimeos\MShop\Common\Manager\Iface $manager, \stdClass $request ) : \Aimeos\Map
289
	{
290
		$data = [];
291
292
		if( isset( $request->data ) )
293
		{
294
			foreach( (array) $request->data as $entry ) {
295
				$data[] = $this->saveEntry( $manager, $entry );
296
			}
297
		}
298
299
		return map( $data );
300
	}
301
302
303
	/**
304
	 * Saves and returns the new or updated item
305
	 *
306
	 * @param \Aimeos\MShop\Common\Manager\Iface $manager Manager responsible for the items
307
	 * @param \stdClass $entry Object including "id" and "attributes" elements
308
	 * @return \Aimeos\MShop\Common\Item\Iface New or updated item
309
	 */
310
	protected function saveEntry( \Aimeos\MShop\Common\Manager\Iface $manager, \stdClass $entry ) : \Aimeos\MShop\Common\Item\Iface
311
	{
312
		if( isset( $entry->id ) ) {
313
			$item = $manager->get( $entry->id );
314
		} else {
315
			$item = $manager->create();
316
		}
317
318
		if( isset( $entry->attributes ) && ( $attr = (array) $entry->attributes ) )
319
		{
320
			if( $item instanceof \Aimeos\MShop\Common\Item\Config\Iface )
321
			{
322
				$key = str_replace( '/', '.', $this->path ) . '.config';
323
				$attr[$key] = (array) ( $attr[$key] ?? [] );
324
			}
325
326
			$item = $item->fromArray( $attr, true );
327
		}
328
329
		$item = $manager->save( $item );
330
331
		if( isset( $entry->relationships ) ) {
332
			$this->saveRelationships( $manager, $item, $entry->relationships );
0 ignored issues
show
Bug introduced by
It seems like $item defined by $manager->save($item) on line 329 can also be of type object<Aimeos\Map>; however, Aimeos\Admin\JsonAdm\Base::saveRelationships() does only seem to accept object<Aimeos\MShop\Common\Item\Iface>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
333
		}
334
335
		return $manager->get( $item->getId() );
0 ignored issues
show
Bug introduced by
The method getId does only exist in Aimeos\MShop\Common\Item\Iface, but not in Aimeos\Map.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
336
	}
337
338
339
	/**
340
	 * Saves the item references associated via the list
341
	 *
342
	 * @param \Aimeos\MShop\Common\Manager\Iface $manager Manager responsible for the items
343
	 * @param \Aimeos\MShop\Common\Item\Iface $item Domain item with an unique ID set
344
	 * @param \stdClass $relationships Object including the <domain>/data/attributes structure
345
	 */
346
	protected function saveRelationships( \Aimeos\MShop\Common\Manager\Iface $manager,
347
		\Aimeos\MShop\Common\Item\Iface $item, \stdClass $relationships )
348
	{
349
		$id = $item->getId();
350
		$listManager = $manager->getSubManager( 'lists' );
351
352
		foreach( (array) $relationships as $domain => $list )
353
		{
354
			if( isset( $list->data ) )
355
			{
356
				foreach( (array) $list->data as $data )
357
				{
358
					$listItem = $listManager->create()->setType( 'default' );
359
360
					if( isset( $data->attributes ) && ( $attr = (array) $data->attributes ) ) {
361
						$key = str_replace( '/', '.', $this->path ) . '.config';
362
						$attr[$key] = (array) ( $attr[$key] ?? [] );
363
						$listItem = $listItem->fromArray( $attr, true );
364
					}
365
366
					if( isset( $data->id ) ) {
367
						$listItem->setRefId( $data->id );
368
					}
369
370
					$listItem->setParentId( $id )->setDomain( $domain );
371
					$listManager->save( $listItem, false );
372
				}
373
			}
374
		}
375
	}
376
}
377