Completed
Push — master ( 75d10e...433dcb )
by Aimeos
01:39
created

Standard::__construct()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 26

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 26
rs 9.504
c 0
b 0
f 0
cc 2
nc 2
nop 1
1
<?php
2
3
/**
4
 * @license LGPLv3, http://opensource.org/licenses/LGPL-3.0
5
 * @copyright Aimeos (aimeos.org), 2017-2019
6
 * @package Controller
7
 * @subpackage Frontend
8
 */
9
10
11
namespace Aimeos\Controller\Frontend\Product;
12
13
14
/**
15
 * Default implementation of the product frontend controller.
16
 *
17
 * @package Controller
18
 * @subpackage Frontend
19
 */
20
class Standard
21
	extends \Aimeos\Controller\Frontend\Base
22
	implements Iface, \Aimeos\Controller\Frontend\Common\Iface
23
{
24
	private $conditions = [];
25
	private $filter;
26
	private $manager;
27
	private $sort;
28
29
30
	/**
31
	 * Common initialization for controller classes.
32
	 *
33
	 * @param \Aimeos\MShop\Context\Item\Iface $context Common MShop context object
34
	 */
35
	public function __construct( \Aimeos\MShop\Context\Item\Iface $context )
36
	{
37
		parent::__construct( $context );
38
39
		$this->manager = \Aimeos\MShop::create( $context, 'index' );
40
		$this->filter = $this->manager->createSearch( true );
41
		$this->conditions[] = $this->filter->compare( '!=', 'index.catalog.id', null );
42
43
		/** controller/frontend/order/ignore-dates
44
		 * Ignore start and end dates of products
45
		 *
46
		 * Usually, products are only shown in the product list if their start/end
47
		 * dates are not set or if the current date is withing the start/end date
48
		 * range of the product. This settings will list all products that wouldn't
49
		 * be shown due to their start/end dates but they still can't be bought.
50
		 *
51
		 * @param boolean True to show products whose start/end date range doesn't match the current date, false to hide them
52
		 * @since 2017.08
53
		 * @category Developer
54
		 */
55
		if( $context->getConfig()->get( 'controller/frontend/product/ignore-dates', false ) ) {
56
			$this->conditions[] = $this->filter->compare( '>', 'product.status', 0 );
57
		} else {
58
			$this->conditions[] = $this->filter->getConditions();
59
		}
60
	}
61
62
63
	/**
64
	 * Returns the aggregated count of products for the given key.
65
	 *
66
	 * @param \Aimeos\MW\Criteria\Iface $filter Critera object which contains the filter conditions
0 ignored issues
show
Bug introduced by
There is no parameter named $filter. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
67
	 * @param string $key Search key to aggregate for, e.g. "index.attribute.id"
68
	 * @return array Associative list of key values as key and the product count for this key as value
69
	 * @since 2019.04
70
	 */
71
	public function aggregate( $key )
72
	{
73
		$this->filter->setConditions( $this->filter->combine( '&&', $this->conditions ) );
74
		return $this->manager->aggregate( $this->filter, $key );
75
	}
76
77
78
	/**
79
	 * Adds attribute IDs for filtering where products must reference all IDs
80
	 *
81
	 * @param array|string $attrIds Attribute ID or list of IDs
82
	 * @return \Aimeos\Controller\Frontend\Product\Iface Product controller for fluent interface
83
	 * @since 2019.04
84
	 */
85
	public function allOf( $attrIds )
86
	{
87
		if( ( $ids = array_unique( $this->validateIds( (array) $attrIds ) ) ) !== [] )
88
		{
89
			$func = $this->filter->createFunction( 'index.attribute:all', [$ids] );
90
			$this->conditions[] = $this->filter->compare( '!=', $func, null );
91
		}
92
93
		return $this;
94
	}
95
96
97
	/**
98
	 * Adds catalog IDs for filtering
99
	 *
100
	 * @param array|string $catIds Catalog ID or list of IDs
101
	 * @param string $listtype List type of the products referenced by the categories
102
	 * @param integer $level Constant from \Aimeos\MW\Tree\Manager\Base if products in subcategories are matched too
103
	 * @return \Aimeos\Controller\Frontend\Product\Iface Product controller for fluent interface
104
	 * @since 2019.04
105
	 */
106
	public function category( $catIds, $listtype = 'default', $level = \Aimeos\MW\Tree\Manager\Base::LEVEL_ONE )
107
	{
108
		if( ( $ids = $this->validateIds( (array) $catIds ) ) !== [] )
109
		{
110
			if( $level != \Aimeos\MW\Tree\Manager\Base::LEVEL_ONE )
111
			{
112
				$list = [];
113
				$cntl = \Aimeos\Controller\Frontend::create( $this->getContext(), 'catalog' );
114
115
				foreach( $ids as $catId )
116
				{
117
					$tree = $cntl->getTree( $catId, [], $level );
118
					$list = array_merge( $list, $this->getCatalogIdsFromTree( $tree ) );
119
				}
120
121
				$ids = array_unique( $list );
122
			}
123
124
			$func = $this->filter->createFunction( 'index.catalog:position', [$listtype, $ids] );
125
126
			$this->conditions[] = $this->filter->compare( '==', 'index.catalog.id', $ids );
127
			$this->conditions[] = $this->filter->compare( '>=', $func, 0 );
128
129
			$func = $this->filter->createFunction( 'sort:index.catalog:position', [$listtype, $ids] );
130
			$this->sort = $this->filter->sort( '+', $func );
131
		}
132
133
		return $this;
134
	}
135
136
137
	/**
138
	 * Adds generic condition for filtering products
139
	 *
140
	 * @param string $operator Comparison operator, e.g. "==", "!=", "<", "<=", ">=", ">", "=~", "~="
141
	 * @param string $key Search key defined by the product manager, e.g. "product.status"
142
	 * @param array|string $value Value or list of values to compare to
143
	 * @return \Aimeos\Controller\Frontend\Product\Iface Product controller for fluent interface
144
	 * @since 2019.04
145
	 */
146
	public function compare( $operator, $key, $value )
147
	{
148
		$this->conditions[] = $this->filter->compare( $operator, $key, $value );
149
		return $this;
150
	}
151
152
153
	/**
154
	 * Returns the product for the given product ID
155
	 *
156
	 * @param string $id Unique product ID
157
	 * @param string[] $domains Domain names of items that are associated with the products and that should be fetched too
158
	 * @return \Aimeos\MShop\Product\Item\Iface Product item including the referenced domains items
159
	 * @since 2019.04
160
	 */
161
	public function get( $id, $domains = ['media', 'price', 'text'] )
162
	{
163
		return $this->manager->getItem( $id, $domains );
164
	}
165
166
167
	/**
168
	 * Returns the product for the given product code
169
	 *
170
	 * @param string $code Unique product code
171
	 * @param string[] $domains Domain names of items that are associated with the products and that should be fetched too
172
	 * @return \Aimeos\MShop\Product\Item\Iface Product item including the referenced domains items
173
	 * @since 2019.04
174
	 */
175
	public function find( $code, $domains = ['media', 'price', 'text'] )
176
	{
177
		return $this->manager->findItem( $code, $domains );
178
	}
179
180
181
	/**
182
	 * Adds attribute IDs for filtering where products must reference at least one ID
183
	 *
184
	 * @param array|string $attrIds Attribute ID or list of IDs
185
	 * @return \Aimeos\Controller\Frontend\Product\Iface Product controller for fluent interface
186
	 * @since 2019.04
187
	 */
188
	public function oneOf( $attrIds )
189
	{
190
		if( ( $ids = array_unique( $this->validateIds( (array) $attrIds ) ) ) !== [] ) {
191
			$this->conditions[] = $this->filter->compare( '==', 'index.attribute.id', $ids );
192
		}
193
194
		return $this;
195
	}
196
197
198
	/**
199
	 * Parses the given array and adds the conditions to the list of conditions
200
	 *
201
	 * @param array $conditions List of conditions, e.g. [['>' => ['product.status' => 0]], ['==' => ['product.type' => 'default']]]
202
	 * @return \Aimeos\Controller\Frontend\Product\Iface Product controller for fluent interface
203
	 * @since 2019.04
204
	 */
205
	public function parse( array $conditions )
206
	{
207
		$this->conditions[] = $this->filter->toConditions( $conditions );
208
		return $this;
209
	}
210
211
212
	/**
213
	 * Adds product IDs for filtering
214
	 *
215
	 * @param array|string $prodIds Product ID or list of IDs
216
	 * @return \Aimeos\Controller\Frontend\Product\Iface Product controller for fluent interface
217
	 * @since 2019.04
218
	 */
219
	public function product( $prodIds )
220
	{
221
		if( ( $ids = array_unique( $this->validateIds( (array) $prodIds ) ) ) !== [] ) {
222
			$this->conditions[] = $this->filter->compare( '==', 'product.id', $ids );
223
		}
224
225
		return $this;
226
	}
227
228
229
	/**
230
	 * Returns the products filtered by the previously assigned conditions
231
	 *
232
	 * @param string[] $domains Domain names of items that are associated with the products and that should be fetched too
233
	 * @param integer &$total Parameter where the total number of found products will be stored in
234
	 * @return array Ordered list of product items implementing \Aimeos\MShop\Product\Item\Iface
235
	 * @since 2019.04
236
	 */
237
	public function search( $domains = ['media', 'price', 'text'], &$total = null )
238
	{
239
		$this->filter->setConditions( $this->filter->combine( '&&', $this->conditions ) );
240
		return $this->manager->searchItems( $this->filter, $domains, $total );
241
	}
242
243
244
	/**
245
	 * Sets the start value and the number of returned products for slicing the list of found products
246
	 *
247
	 * @param integer $start Start value of the first product in the list
248
	 * @param integer $limit Number of returned products
249
	 * @return \Aimeos\Controller\Frontend\Product\Iface Product controller for fluent interface
250
	 * @since 2019.04
251
	 */
252
	public function slice( $start, $limit )
253
	{
254
		$this->filter->setSlice( $start, $limit );
255
		return $this;
256
	}
257
258
259
	/**
260
	 * Sets the sorting of the product list
261
	 *
262
	 * @param string|null $sort Sortation of the product list like "name", "-name", "price", "-price", "code", "-code", "ctime, "-ctime" and "relevance", null for no sortation
0 ignored issues
show
Bug introduced by
There is no parameter named $sort. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
263
	 * @return \Aimeos\Controller\Frontend\Product\Iface Product controller for fluent interface
264
	 * @since 2019.04
265
	 */
266
	public function sort( $key = null )
267
	{
268
		$direction = '+';
269
270
		if( $key != null && $key[0] === '-' )
271
		{
272
			$key = substr( $key, 1 );
273
			$direction = '-';
274
		}
275
276
		switch( $key )
277
		{
278
			case 'code':
279
				$this->sort = $this->filter->sort( $direction, 'product.code' );
280
				break;
281
282
			case 'ctime':
283
				$this->sort = $this->filter->sort( $direction, 'product.ctime' );
284
				break;
285
286
			case 'name':
287
				$langid = $this->getContext()->getLocale()->getLanguageId();
288
289
				$cmpfunc = $this->filter->createFunction( 'index.text:name', [$langid] );
290
				$this->conditions[] = $this->filter->compare( '!=', $cmpfunc, null );
291
292
				$sortfunc = $this->filter->createFunction( 'sort:index.text:name', [$langid] );
293
				$this->sort = $this->filter->sort( $direction, $sortfunc );
294
				break;
295
296
			case 'price':
297
				$currencyid = $this->getContext()->getLocale()->getCurrencyId();
298
299
				$cmpfunc = $this->filter->createFunction( 'index.price:value', [$currencyid] );
300
				$this->conditions[] = $this->filter->compare( '!=', $cmpfunc, null );
301
302
				$sortfunc = $this->filter->createFunction( 'sort:index.price:value', [$currencyid] );
303
				$this->sort = $this->filter->sort( $direction, $sortfunc );
304
				break;
305
306
			case null:
307
				$this->sort = null;
308
				break;
309
		}
310
311
		if( $this->sort ) {
312
			$this->filter->setSortations( [$this->sort] );
313
		}
314
315
		return $this;
316
	}
317
318
319
	/**
320
	 * Adds supplier IDs for filtering
321
	 *
322
	 * @param array|string $supIds Supplier ID or list of IDs
323
	 * @param string $listtype List type of the products referenced by the suppliers
324
	 * @return \Aimeos\Controller\Frontend\Product\Iface Product controller for fluent interface
325
	 * @since 2019.04
326
	 */
327
	public function supplier( $supIds, $listtype = 'default' )
328
	{
329
		if( ( $ids = array_unique( $this->validateIds( (array) $supIds ) ) ) !== [] )
330
		{
331
			$func = $this->filter->createFunction( 'index.supplier:position', [$listtype, $ids] );
332
333
			$this->conditions[] = $this->filter->compare( '==', 'index.supplier.id', $ids );
334
			$this->conditions[] = $this->filter->compare( '>=', $func, 0 );
335
336
			$func = $this->filter->createFunction( 'sort:index.supplier:position', [$listtype, $ids] );
337
			$this->sort = $this->filter->sort( '+', $func );
338
		}
339
340
		return $this;
341
	}
342
343
344
	/**
345
	 * Adds input string for full text search
346
	 *
347
	 * @param string|null $text User input for full text search
348
	 * @return \Aimeos\Controller\Frontend\Product\Iface Product controller for fluent interface
349
	 * @since 2019.04
350
	 */
351
	public function text( $text )
352
	{
353
		if( $text )
0 ignored issues
show
Bug Best Practice introduced by
The expression $text of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
354
		{
355
			$langid = $this->getContext()->getLocale()->getLanguageId();
356
			$func = $this->filter->createFunction( 'index.text:relevance', [$langid, $text] );
357
358
			$this->conditions[] = $this->filter->compare( '>', $func, 0 );
359
		}
360
361
		return $this;
362
	}
363
364
365
	/**
366
	 * Returns the list of catalog IDs for the given catalog tree
367
	 *
368
	 * @param \Aimeos\MShop\Catalog\Item\Iface $item Catalog item with children
369
	 * @return array List of catalog IDs
370
	 */
371
	protected function getCatalogIdsFromTree( \Aimeos\MShop\Catalog\Item\Iface $item )
372
	{
373
		if( $item->getStatus() < 1 ) {
374
			return [];
375
		}
376
377
		$list = [ $item->getId() ];
378
379
		foreach( $item->getChildren() as $child ) {
380
			$list = array_merge( $list, $this->getCatalogIdsFromTree( $child ) );
381
		}
382
383
		return $list;
384
	}
385
386
387
	/**
388
	 * Validates the given IDs as integers
389
	 *
390
	 * @param array $ids List of IDs to validate
391
	 * @return array List of validated IDs
392
	 */
393
	protected function validateIds( array $ids )
394
	{
395
		$list = [];
396
397
		foreach( $ids as $id )
398
		{
399
			if( $id != '' && preg_match( '/^[A-Za-z0-9\-\_]+$/', $id ) === 1 ) {
400
				$list[] = (string) $id;
401
			}
402
		}
403
404
		return $list;
405
	}
406
}
407