Passed
Push — master ( 596853...253ba3 )
by Aimeos
16:40
created

Standard::delete()   A

Complexity

Conditions 5
Paths 16

Size

Total Lines 39
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 5
eloc 21
c 1
b 0
f 0
nc 16
nop 0
dl 0
loc 39
rs 9.2728
1
<?php
2
3
/**
4
 * @license LGPLv3, http://opensource.org/licenses/LGPL-3.0
5
 * @copyright Aimeos (aimeos.org), 2020-2021
6
 * @package Admin
7
 * @subpackage JQAdm
8
 */
9
10
11
namespace Aimeos\Admin\JQAdm\Review;
12
13
sprintf( 'marketing' ); // for translation
14
sprintf( 'review' ); // for translation
15
16
17
/**
18
 * Default implementation of review JQAdm client.
19
 *
20
 * @package Admin
21
 * @subpackage JQAdm
22
 */
23
class Standard
24
	extends \Aimeos\Admin\JQAdm\Common\Admin\Factory\Base
25
	implements \Aimeos\Admin\JQAdm\Common\Admin\Factory\Iface
26
{
27
	/**
28
	 * Deletes a resource
29
	 *
30
	 * @return string|null HTML output
31
	 */
32
	public function delete() : ?string
33
	{
34
		$view = $this->getView();
35
36
		if( !$view->access( ['super', 'admin', 'test'] ) ) {
37
			throw new \Aimeos\Admin\JQAdm\Exception( 'Deleting reviews is not allowed' );
38
		}
39
40
		$manager = \Aimeos\MShop::create( $this->getContext(), 'review' );
41
		$manager->begin();
42
43
		try
44
		{
45
			if( ( $ids = $view->param( 'id' ) ) === null ) {
46
				throw new \Aimeos\Admin\JQAdm\Exception( sprintf( 'Required parameter "%1$s" is missing', 'id' ) );
47
			}
48
49
			$search = $manager->filter()->slice( 0, count( (array) $ids ) );
50
			$search->setConditions( $search->compare( '==', 'review.id', $ids ) );
51
			$items = $manager->search( $search );
52
53
			foreach( $items as $item )
54
			{
55
				$view->item = $item;
56
				parent::delete();
57
			}
58
59
			$manager->delete( $items->toArray() );
60
			$manager->commit();
61
62
			$this->update( $items->toArray() )->redirect( 'review', 'search', null, 'delete' );
63
		}
64
		catch( \Exception $e )
65
		{
66
			$manager->rollback();
67
			$this->report( $e, 'delete' );
68
		}
69
70
		return $this->search();
71
	}
72
73
74
	/**
75
	 * Returns a single resource
76
	 *
77
	 * @return string|null HTML output
78
	 */
79
	public function get() : ?string
80
	{
81
		$view = $this->getObject()->addData( $this->getView() );
82
83
		try
84
		{
85
			if( ( $id = $view->param( 'id' ) ) === null ) {
86
				throw new \Aimeos\Admin\JQAdm\Exception( sprintf( 'Required parameter "%1$s" is missing', 'id' ) );
87
			}
88
89
			$manager = \Aimeos\MShop::create( $this->getContext(), 'review' );
90
91
			$view->item = $manager->get( $id );
92
			$view->itemSubparts = $this->getSubClientNames();
93
			$view->itemData = $this->toArray( $view->item );
94
			$view->itemBody = parent::get();
95
		}
96
		catch( \Exception $e )
97
		{
98
			$this->report( $e, 'get' );
99
		}
100
101
		return $this->render( $view );
102
	}
103
104
105
	/**
106
	 * Saves the data
107
	 *
108
	 * @return string|null HTML output
109
	 */
110
	public function save() : ?string
111
	{
112
		$view = $this->getView();
113
114
		$manager = \Aimeos\MShop::create( $this->getContext(), 'review' );
115
		$manager->begin();
116
117
		try
118
		{
119
			$item = $this->fromArray( $view->param( 'item', [] ) );
120
			$view->item = $item->getId() ? $item : $manager->save( $item );
121
			$view->itemBody = parent::save();
122
123
			$item = $manager->save( clone $view->item );
124
			$manager->commit();
125
126
			return $this->update( [$item] )->redirect( 'review', $view->param( 'next' ), $view->item->getId(), 'save' );
0 ignored issues
show
Bug introduced by
It seems like $view->item->getId() can also be of type Aimeos\Map; however, parameter $id of Aimeos\Admin\JQAdm\Base::redirect() does only seem to accept null|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

126
			return $this->update( [$item] )->redirect( 'review', $view->param( 'next' ), /** @scrutinizer ignore-type */ $view->item->getId(), 'save' );
Loading history...
127
		}
128
		catch( \Exception $e )
129
		{
130
			$manager->rollback();
131
			$this->report( $e, 'save' );
132
		}
133
134
		return $this->create();
135
	}
136
137
138
	/**
139
	 * Returns a list of resource according to the conditions
140
	 *
141
	 * @return string|null HTML output
142
	 */
143
	public function search() : ?string
144
	{
145
		$view = $this->getView();
146
147
		try
148
		{
149
			$total = 0;
150
			$params = $this->storeFilter( $view->param(), 'review' );
151
			$manager = \Aimeos\MShop::create( $this->getContext(), 'review' );
152
153
			$search = $manager->filter();
154
			$search->setSortations( [$search->sort( '-', 'review.ctime' )] );
155
			$search = $this->initCriteria( $search, $params );
156
157
			$view->items = $manager->search( $search, [], $total );
158
			$view->filterAttributes = $manager->getSearchAttributes( true );
159
			$view->filterOperators = $search->getOperators();
160
			$view->itemBody = parent::search();
161
			$view->total = $total;
162
		}
163
		catch( \Exception $e )
164
		{
165
			$this->report( $e, 'search' );
166
		}
167
168
		/** admin/jqadm/review/template-list
169
		 * Relative path to the HTML body template for the review list.
170
		 *
171
		 * The template file contains the HTML code and processing instructions
172
		 * to generate the result shown in the body of the frontend. The
173
		 * configuration string is the path to the template file relative
174
		 * to the templates directory (usually in admin/jqadm/templates).
175
		 *
176
		 * You can overwrite the template file configuration in extensions and
177
		 * provide alternative templates. These alternative templates should be
178
		 * named like the default one but with the string "default" replaced by
179
		 * an unique name. You may use the name of your project for this. If
180
		 * you've implemented an alternative client class as well, "default"
181
		 * should be replaced by the name of the new class.
182
		 *
183
		 * @param string Relative path to the template creating the HTML code
184
		 * @since 2016.04
185
		 * @category Developer
186
		 */
187
		$tplconf = 'admin/jqadm/review/template-list';
188
		$default = 'review/list-standard';
189
190
		return $view->render( $view->config( $tplconf, $default ) );
191
	}
192
193
194
	/**
195
	 * Returns the sub-client given by its name.
196
	 *
197
	 * @param string $type Name of the client type
198
	 * @param string|null $name Name of the sub-client (Default if null)
199
	 * @return \Aimeos\Admin\JQAdm\Iface Sub-client object
200
	 */
201
	public function getSubClient( string $type, string $name = null ) : \Aimeos\Admin\JQAdm\Iface
202
	{
203
		/** admin/jqadm/review/decorators/excludes
204
		 * Excludes decorators added by the "common" option from the review JQAdm client
205
		 *
206
		 * Decorators extend the functionality of a class by adding new aspects
207
		 * (e.g. log what is currently done), executing the methods of the underlying
208
		 * class only in certain conditions (e.g. only for logged in users) or
209
		 * modify what is returned to the caller.
210
		 *
211
		 * This option allows you to remove a decorator added via
212
		 * "client/jqadm/common/decorators/default" before they are wrapped
213
		 * around the JQAdm client.
214
		 *
215
		 *  admin/jqadm/review/decorators/excludes = array( 'decorator1' )
216
		 *
217
		 * This would remove the decorator named "decorator1" from the list of
218
		 * common decorators ("\Aimeos\Admin\JQAdm\Common\Decorator\*") added via
219
		 * "client/jqadm/common/decorators/default" to the JQAdm client.
220
		 *
221
		 * @param array List of decorator names
222
		 * @since 2020.10
223
		 * @category Developer
224
		 * @see admin/jqadm/common/decorators/default
225
		 * @see admin/jqadm/review/decorators/global
226
		 * @see admin/jqadm/review/decorators/local
227
		 */
228
229
		/** admin/jqadm/review/decorators/global
230
		 * Adds a list of globally available decorators only to the review JQAdm client
231
		 *
232
		 * Decorators extend the functionality of a class by adding new aspects
233
		 * (e.g. log what is currently done), executing the methods of the underlying
234
		 * class only in certain conditions (e.g. only for logged in users) or
235
		 * modify what is returned to the caller.
236
		 *
237
		 * This option allows you to wrap global decorators
238
		 * ("\Aimeos\Admin\JQAdm\Common\Decorator\*") around the JQAdm client.
239
		 *
240
		 *  admin/jqadm/review/decorators/global = array( 'decorator1' )
241
		 *
242
		 * This would add the decorator named "decorator1" defined by
243
		 * "\Aimeos\Admin\JQAdm\Common\Decorator\Decorator1" only to the JQAdm client.
244
		 *
245
		 * @param array List of decorator names
246
		 * @since 2020.10
247
		 * @category Developer
248
		 * @see admin/jqadm/common/decorators/default
249
		 * @see admin/jqadm/review/decorators/excludes
250
		 * @see admin/jqadm/review/decorators/local
251
		 */
252
253
		/** admin/jqadm/review/decorators/local
254
		 * Adds a list of local decorators only to the review JQAdm client
255
		 *
256
		 * Decorators extend the functionality of a class by adding new aspects
257
		 * (e.g. log what is currently done), executing the methods of the underlying
258
		 * class only in certain conditions (e.g. only for logged in users) or
259
		 * modify what is returned to the caller.
260
		 *
261
		 * This option allows you to wrap local decorators
262
		 * ("\Aimeos\Admin\JQAdm\Review\Decorator\*") around the JQAdm client.
263
		 *
264
		 *  admin/jqadm/review/decorators/local = array( 'decorator2' )
265
		 *
266
		 * This would add the decorator named "decorator2" defined by
267
		 * "\Aimeos\Admin\JQAdm\Review\Decorator\Decorator2" only to the JQAdm client.
268
		 *
269
		 * @param array List of decorator names
270
		 * @since 2020.10
271
		 * @category Developer
272
		 * @see admin/jqadm/common/decorators/default
273
		 * @see admin/jqadm/review/decorators/excludes
274
		 * @see admin/jqadm/review/decorators/global
275
		 */
276
		return $this->createSubClient( 'review/' . $type, $name );
277
	}
278
279
280
	/**
281
	 * Returns the list of sub-client names configured for the client.
282
	 *
283
	 * @return array List of JQAdm client names
284
	 */
285
	protected function getSubClientNames() : array
286
	{
287
		/** admin/jqadm/review/subparts
288
		 * List of JQAdm sub-clients rendered within the review section
289
		 *
290
		 * The output of the frontend is composed of the code generated by the JQAdm
291
		 * clients. Each JQAdm client can consist of serveral (or none) sub-clients
292
		 * that are responsible for rendering certain sub-parts of the output. The
293
		 * sub-clients can contain JQAdm clients themselves and therefore a
294
		 * hierarchical tree of JQAdm clients is composed. Each JQAdm client creates
295
		 * the output that is placed inside the container of its parent.
296
		 *
297
		 * At first, always the JQAdm code generated by the parent is printed, then
298
		 * the JQAdm code of its sub-clients. The order of the JQAdm sub-clients
299
		 * determines the order of the output of these sub-clients inside the parent
300
		 * container. If the configured list of clients is
301
		 *
302
		 *  array( "subclient1", "subclient2" )
303
		 *
304
		 * you can easily change the order of the output by reordering the subparts:
305
		 *
306
		 *  admin/jqadm/<clients>/subparts = array( "subclient1", "subclient2" )
307
		 *
308
		 * You can also remove one or more parts if they shouldn't be rendered:
309
		 *
310
		 *  admin/jqadm/<clients>/subparts = array( "subclient1" )
311
		 *
312
		 * As the clients only generates structural JQAdm, the layout defined via CSS
313
		 * should support adding, removing or reordering content by a fluid like
314
		 * design.
315
		 *
316
		 * @param array List of sub-client names
317
		 * @since 2020.10
318
		 * @category Developer
319
		 */
320
		return $this->getContext()->getConfig()->get( 'admin/jqadm/review/subparts', [] );
321
	}
322
323
324
	/**
325
	 * Creates new and updates existing items using the data array
326
	 *
327
	 * @param array $data Data array
328
	 * @return \Aimeos\MShop\Review\Item\Iface New review item object
329
	 */
330
	protected function fromArray( array $data ) : \Aimeos\MShop\Review\Item\Iface
331
	{
332
		$manager = \Aimeos\MShop::create( $this->getContext(), 'review' );
333
334
		if( ( $id = $data['review.id'] ?? null ) == null ) {
335
			throw new \Aimeos\Admin\JQAdm\Exception( 'Creating new reviews is not allowed' );
336
		}
337
338
		$item = $manager->get( $id );
339
340
		if( $this->getView()->access( ['super', 'admin'] ) ) {
341
			$item->setStatus( (int) $data['review.status'] ?? 1 );
342
		}
343
344
		return $item->setResponse( $data['review.response'] ?? '' )->setName( $data['review.name'] ?? '' );
345
	}
346
347
348
	/**
349
	 * Constructs the data array for the view from the given item
350
	 *
351
	 * @param \Aimeos\MShop\Review\Item\Iface $item Review item object
352
	 * @return string[] Multi-dimensional associative list of item data
353
	 */
354
	protected function toArray( \Aimeos\MShop\Review\Item\Iface $item, bool $copy = false ) : array
355
	{
356
		return $item->toArray( true );
357
	}
358
359
360
	/**
361
	 * Returns the rendered template including the view data
362
	 *
363
	 * @param \Aimeos\MW\View\Iface $view View object with data assigned
364
	 * @return string HTML output
365
	 */
366
	protected function render( \Aimeos\MW\View\Iface $view ) : string
367
	{
368
		/** admin/jqadm/review/template-item
369
		 * Relative path to the HTML body template for the review item.
370
		 *
371
		 * The template file contains the HTML code and processing instructions
372
		 * to generate the result shown in the body of the frontend. The
373
		 * configuration string is the path to the template file relative
374
		 * to the templates directory (usually in admin/jqadm/templates).
375
		 *
376
		 * You can overwrite the template file configuration in extensions and
377
		 * provide alternative templates. These alternative templates should be
378
		 * named like the default one but with the string "default" replaced by
379
		 * an unique name. You may use the name of your project for this. If
380
		 * you've implemented an alternative client class as well, "default"
381
		 * should be replaced by the name of the new class.
382
		 *
383
		 * @param string Relative path to the template creating the HTML code
384
		 * @since 2016.04
385
		 * @category Developer
386
		 */
387
		$tplconf = 'admin/jqadm/review/template-item';
388
		$default = 'review/item-standard';
389
390
		return $view->render( $view->config( $tplconf, $default ) );
391
	}
392
393
394
	/**
395
	 * Updates the average rating and the number of ratings in the domain item
396
	 *
397
	 * @param \Aimeos\MShop\Review\Item\Iface[] $item List of review items with domain and refid
398
	 * @return \Aimeos\Admin\JQAdm\Iface Admin client for fluent interface
399
	 */
400
	protected function update( array $items ) : \Aimeos\Admin\JQAdm\Iface
401
	{
402
		$context = $this->getContext();
403
		$manager = \Aimeos\MShop::create( $context, 'review' );
404
405
		foreach( $items as $item )
406
		{
407
			$filter = $manager->filter( true )->add( [
408
				'review.domain' => $item->getDomain(),
409
				'review.refid' => $item->getRefId(),
410
				'review.status' => 1
411
			] );
412
413
			$rateManager = \Aimeos\MShop::create( $context, $item->getDomain() );
414
415
			if( $entry = $manager->aggregate( $filter, 'review.refid', 'review.rating', 'rate' )->first() ) {
416
				$rateManager->rate( $item->getRefId(), $entry['sum'] / $entry['count'], $entry['count'] );
417
			} else {
418
				$rateManager->rate( $item->getRefId(), 0, 0 );
419
			}
420
421
			$context->cache()->deleteByTags( [$item->getDomain() . '-' . $item->getRefId()] );
422
		}
423
424
		return $this;
425
	}
426
}
427