Completed
Push — master ( 56f888...ae1907 )
by Aimeos
03:01
created

Standard::sort()   A

Complexity

Conditions 6
Paths 14

Size

Total Lines 25
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 16
c 1
b 0
f 0
dl 0
loc 25
rs 9.1111
cc 6
nc 14
nop 1
1
<?php
2
3
/**
4
 * @license LGPLv3, http://opensource.org/licenses/LGPL-3.0
5
 * @copyright Aimeos (aimeos.org), 2018-2020
6
 * @package Controller
7
 * @subpackage Frontend
8
 */
9
10
11
namespace Aimeos\Controller\Frontend\Review;
12
13
14
/**
15
 * Default implementation of the review 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
28
29
	/**
30
	 * Common initialization for controller classes
31
	 *
32
	 * @param \Aimeos\MShop\Context\Item\Iface $context Common MShop context object
33
	 */
34
	public function __construct( \Aimeos\MShop\Context\Item\Iface $context )
35
	{
36
		parent::__construct( $context );
37
38
		$this->manager = \Aimeos\MShop::create( $context, 'review' );
39
		$this->filter = $this->manager->filter( true );
40
	}
41
42
43
	/**
44
	 * Clones objects in controller and resets values
45
	 */
46
	public function __clone()
47
	{
48
		$this->filter = clone $this->filter;
49
	}
50
51
52
	/**
53
	 * Returns the aggregated count of products for the given key.
54
	 *
55
	 * @param string $key Search key to aggregate for, e.g. "review.rating"
56
	 * @param string|null $value Search key for aggregating the value column
57
	 * @param string|null $type Type of the aggregation, empty string for count or "sum"
58
	 * @return \Aimeos\Map Associative list of key values as key and the product count for this key as value
59
	 * @since 2020.10
60
	 */
61
	public function aggregate( string $key, string $value = null, string $type = null ) : \Aimeos\Map
62
	{
63
		$filter = clone $this->filter;
64
		$cond = $filter->is( 'review.status', '>', 0 );
65
66
		$this->filter->setConditions( $this->filter->combine( '&&', array_merge( $this->conditions, [$cond] ) ) );
67
		return $this->manager->aggregate( $this->filter, $key, $value, $type );
68
	}
69
70
71
	/**
72
	 * Adds generic condition for filtering
73
	 *
74
	 * @param string $operator Comparison operator, e.g. "==", "!=", "<", "<=", ">=", ">", "=~", "~="
75
	 * @param string $key Search key defined by the review manager, e.g. "review.status"
76
	 * @param array|string $value Value or list of values to compare to
77
	 * @return \Aimeos\Controller\Frontend\Review\Iface Review controller for fluent interface
78
	 * @since 2020.10
79
	 */
80
	public function compare( string $operator, string $key, $value ) : Iface
81
	{
82
		$this->conditions[] = $this->filter->compare( $operator, $key, $value );
83
		return $this;
84
	}
85
86
87
	/**
88
	 * Returns a new rating item
89
	 *
90
	 * @param array $vals Associative list of key/value pairs to initialize the item
91
	 * @return \Aimeos\MShop\Review\Item\Iface New review item
92
	 */
93
	public function create( array $vals = [] ) : \Aimeos\MShop\Review\Item\Iface
94
	{
95
		return $this->manager->create()->setOrderProductId( $vals['review.orderproductid'] ?? '' )->fromArray( $vals );
96
	}
97
98
99
	/**
100
	 * Deletes the review item for the given ID or IDs
101
	 *
102
	 * @param array|string $id Unique review ID or list of IDs
103
	 * @return \Aimeos\Controller\Frontend\Review\Iface Review controller for fluent interface
104
	 * @since 2020.10
105
	 */
106
	public function delete( $ids ) : Iface
107
	{
108
		$ids = (array) $ids;
109
		$filter = $this->manager->filter()->add( ['review.id' => $ids] );
110
		$this->manager->delete( $this->manager->search( $filter->slice( 0, count( $ids ) ) )->toArray() );
111
112
		return $this;
113
	}
114
115
116
	/**
117
	 * Sets the review domain for filtering
118
	 *
119
	 * @param string $domain Domain (e.g. "product") of the reviewed items
120
	 * @return \Aimeos\Controller\Frontend\Review\Iface Review controller for fluent interface
121
	 * @since 2020.10
122
	 */
123
	public function domain( string $domain ) : Iface
124
	{
125
		$this->conditions['domain'] = $this->filter->compare( '==', 'review.domain', $domain );
126
		return $this;
127
	}
128
129
130
	/**
131
	 * Restricts the reviews to a specific domain item
132
	 *
133
	 * @param string $domain Domain the reviews belong to (e.g. "product")
134
	 * @param string|null $refid Id of the item the reviews belong to or NULL for all reviews from the domain
135
	 * @return \Aimeos\Controller\Frontend\Review\Iface Review controller for fluent interface
136
	 * @since 2020.10
137
	 */
138
	public function for( string $domain, ?string $refid ) : Iface
139
	{
140
		$this->conditions['domain'] = $this->filter->compare( '==', 'review.domain', $domain );
141
142
		if( $refid !== null ) {
143
			$this->conditions['refid'] = $this->filter->compare( '==', 'review.refid', $refid );
144
		}
145
146
		return $this;
147
	}
148
149
150
	/**
151
	 * Returns the review item for the given ID
152
	 *
153
	 * @param string $id Unique review ID
154
	 * @return \Aimeos\MShop\Review\Item\Iface Review object
155
	 */
156
	public function get( string $id ) : \Aimeos\MShop\Review\Item\Iface
157
	{
158
		return $this->manager->getItem( $id, [], true );
159
	}
160
161
162
	/**
163
	 * Returns the reviews for the logged-in user
164
	 *
165
	 * @param int &$total Parameter where the total number of found reviews will be stored in
166
	 * @return \Aimeos\Map Ordered list of review items implementing \Aimeos\MShop\Review\Item\Iface
167
	 * @since 2020.10
168
	 */
169
	public function list( int &$total = null ) : \Aimeos\Map
170
	{
171
		$filter = clone $this->filter;
172
		$cond = $filter->is( 'review.customerid', '==', $this->getContext()->getUserId() );
173
174
		$filter->setConditions( $filter->combine( '&&', array_merge( $this->conditions, [$cond] ) ) );
175
		return $this->manager->searchItems( $filter, [], $total );
176
	}
177
178
179
	/**
180
	 * Parses the given array and adds the conditions to the list of conditions
181
	 *
182
	 * @param array $conditions List of conditions, e.g. ['>' => ['review.rating' => 3]]
183
	 * @return \Aimeos\Controller\Frontend\Review\Iface Review controller for fluent interface
184
	 * @since 2020.10
185
	 */
186
	public function parse( array $conditions ) : Iface
187
	{
188
		if( ( $cond = $this->filter->toConditions( $conditions ) ) !== null ) {
189
			$this->conditions[] = $cond;
190
		}
191
192
		return $this;
193
	}
194
195
196
	/**
197
	 * Adds or updates a review
198
	 *
199
	 * @param \Aimeos\MShop\Review\Item\Iface $item Review item including required data
200
	 * @return \Aimeos\Controller\Frontend\Review\Iface Review controller for fluent interface
201
	 * @since 2020.10
202
	 */
203
	public function save( \Aimeos\MShop\Review\Item\Iface $item ) : \Aimeos\MShop\Review\Item\Iface
204
	{
205
		if( !in_array( $item->getDomain(), ['product'] ) )
206
		{
207
			$msg = sprintf( 'Domain "%1$s" is not supported', $item->getDomain() );
208
			throw new \Aimeos\Controller\Frontend\Review\Exception( $msg );
209
		}
210
211
		$context = $this->getContext();
212
		$manager = \Aimeos\MShop::create( $context, 'order/base' );
213
214
		$filter = $manager->filter( true )->add( [
215
			'order.base.product.id' => $item->getOrderProductId(),
216
			'order.base.customerid' => $context->getUserId()
217
		] );
218
		$manager->search( $filter->slice( 0, 1 ) )->first( new \Aimeos\Controller\Frontend\Review\Exception(
219
			sprintf( 'You can only add a review if you have ordered a product' )
220
		) );
221
222
		$orderProductItem = \Aimeos\MShop::create( $context, 'order/base/product' )->get( $item->getOrderProductId() );
0 ignored issues
show
Bug introduced by
It seems like $item->getOrderProductId() can also be of type null; however, parameter $id of Aimeos\MShop\Common\Manager\Iface::get() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

222
		$orderProductItem = \Aimeos\MShop::create( $context, 'order/base/product' )->get( /** @scrutinizer ignore-type */ $item->getOrderProductId() );
Loading history...
223
224
		$filter = $this->manager->filter()->add( [
225
			'review.customerid' => $context->getUserId(),
226
			'review.id' => $item->getId()
227
		] );
228
229
		$real = $this->manager->search( $filter->slice( 0, 1 ) )->first( $this->manager->create() );
230
231
		$real = $real->setCustomerId( $context->getUserId() )
232
			->setOrderProductId( $orderProductItem->getId() )
233
			->setRefId( $orderProductItem->getProductId() )
234
			->setComment( $item->getComment() )
235
			->setRating( $item->getRating() )
236
			->setName( $item->getName() )
237
			->setDomain( 'product' );
238
239
		$item = $this->manager->save( $real );
240
241
		$filter = $this->manager->filter( true )->add( [
242
			'review.domain' => $item->getDomain(),
243
			'review.refid' => $item->getRefId()
0 ignored issues
show
Bug introduced by
The method getRefId() does not exist on Aimeos\MShop\Common\Item\Iface. Did you maybe mean getId()? ( Ignorable by Annotation )

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

243
			'review.refid' => $item->/** @scrutinizer ignore-call */ getRefId()

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
244
		] );
245
246
		if( $entry = $this->manager->aggregate( $filter, 'review.refid', 'review.rating', 'rate' )->first() )
247
		{
248
			$rateManager = \Aimeos\MShop::create( $context, $item->getDomain() );
249
			$rateManager->rate( $item->getId(), $entry['sum'], $entry['count'] );
250
		}
251
252
		return $item;
253
	}
254
255
256
	/**
257
	 * Returns the reviews filtered by the previously assigned conditions
258
	 *
259
	 * @param int &$total Parameter where the total number of found reviews will be stored in
260
	 * @return \Aimeos\Map Ordered list of review items implementing \Aimeos\MShop\Review\Item\Iface
261
	 * @since 2020.10
262
	 */
263
	public function search( int &$total = null ) : \Aimeos\Map
264
	{
265
		$filter = clone $this->filter;
266
		$cond = $filter->is( 'review.status', '>', 0 );
267
268
		$filter->setConditions( $filter->combine( '&&', array_merge( $this->conditions, [$cond] ) ) );
269
		return $this->manager->searchItems( $filter, [], $total );
270
	}
271
272
273
	/**
274
	 * Sets the start value and the number of returned review items for slicing the list of found review items
275
	 *
276
	 * @param int $start Start value of the first review item in the list
277
	 * @param int $limit Number of returned review items
278
	 * @return \Aimeos\Controller\Frontend\Review\Iface Review controller for fluent interface
279
	 * @since 2020.10
280
	 */
281
	public function slice( int $start, int $limit ) : Iface
282
	{
283
		$this->filter->setSlice( $start, $limit );
284
		return $this;
285
	}
286
287
288
	/**
289
	 * Sets the sorting of the result list
290
	 *
291
	 * @param string|null $key Sorting key of the result list like "mtime" or "rating", null for no sorting
292
	 * @return \Aimeos\Controller\Frontend\Review\Iface Review controller for fluent interface
293
	 * @since 2020.10
294
	 */
295
	public function sort( string $key = null ) : Iface
296
	{
297
		$sort = [];
298
		$list = ( $key ? explode( ',', $key ) : [] );
299
300
		foreach( $list as $sortkey )
301
		{
302
			$direction = ( $sortkey[0] === '-' ? '-' : '+' );
303
			$sortkey = ltrim( $sortkey, '+-' );
304
305
			switch( $sortkey )
306
			{
307
				case 'ctime':
308
					$sort[] = $this->filter->sort( $direction, 'review.ctime' );
309
					break;
310
				case 'rating':
311
					$sort[] = $this->filter->sort( $direction, 'review.rating' );
312
					break;
313
				default:
314
					$sort[] = $this->filter->sort( $direction, $sortkey );
315
			}
316
		}
317
318
		$this->filter->setSortations( $sort );
319
		return $this;
320
	}
321
}
322