Passed
Push — master ( 9a0039...2f021f )
by Aimeos
07:58
created

Standard   A

Complexity

Total Complexity 18

Size/Duplication

Total Lines 270
Duplicated Lines 0 %

Importance

Changes 4
Bugs 0 Features 0
Metric Value
wmc 18
eloc 53
c 4
b 0
f 0
dl 0
loc 270
rs 10

14 Methods

Rating   Name   Duplication   Size   Complexity  
A compare() 0 4 1
A get() 0 3 1
A __construct() 0 10 1
A add() 0 4 1
A __clone() 0 3 1
A parse() 0 7 2
A save() 0 3 1
A store() 0 8 1
A uses() 0 4 1
A checkLimit() 0 57 2
A search() 0 6 1
A sort() 0 11 3
A slice() 0 5 1
A getManager() 0 3 1
1
<?php
2
3
/**
4
 * @license LGPLv3, http://opensource.org/licenses/LGPL-3.0
5
 * @copyright Metaways Infosystems GmbH, 2014
6
 * @copyright Aimeos (aimeos.org), 2015-2021
7
 * @package Controller
8
 * @subpackage Frontend
9
 */
10
11
12
namespace Aimeos\Controller\Frontend\Order;
13
14
15
/**
16
 * Default implementation of the order frontend controller.
17
 *
18
 * @package Controller
19
 * @subpackage Frontend
20
 */
21
class Standard
22
	extends \Aimeos\Controller\Frontend\Base
23
	implements Iface, \Aimeos\Controller\Frontend\Common\Iface
24
{
25
	private $domains = [];
26
	private $manager;
27
	private $filter;
28
	private $item;
29
30
31
	/**
32
	 * Initializes the controller
33
	 *
34
	 * @param \Aimeos\MShop\Context\Item\Iface $context Common MShop context object
35
	 */
36
	public function __construct( \Aimeos\MShop\Context\Item\Iface $context )
37
	{
38
		parent::__construct( $context );
39
40
		$this->manager = \Aimeos\MShop::create( $context, 'order' );
41
		$this->item = $this->manager->create();
42
43
		$this->filter = $this->manager->filter( true );
44
		$this->addExpression( $this->filter->compare( '==', 'order.base.customerid', $context->getUserId() ) );
45
		$this->addExpression( $this->filter->getConditions() );
46
	}
47
48
49
	/**
50
	 * Clones objects in controller and resets values
51
	 */
52
	public function __clone()
53
	{
54
		$this->item = clone $this->item;
55
	}
56
57
58
	/**
59
	 * Adds the values to the order object (not yet stored)
60
	 *
61
	 * @param string $baseId ID of the stored basket
62
	 * @param array $values Values added to the order item (new or existing) like "order.type"
63
	 * @return \Aimeos\Controller\Frontend\Order\Iface Order controller for fluent interface
64
	 * @since 2019.04
65
	 */
66
	public function add( string $baseId, array $values = [] ) : Iface
67
	{
68
		$this->item = $this->item->fromArray( $values )->setBaseId( $baseId );
69
		return $this;
70
	}
71
72
73
	/**
74
	 * Adds generic condition for filtering orders
75
	 *
76
	 * @param string $operator Comparison operator, e.g. "==", "!=", "<", "<=", ">=", ">", "=~", "~="
77
	 * @param string $key Search key defined by the order manager, e.g. "order.type"
78
	 * @param array|string $value Value or list of values to compare to
79
	 * @return \Aimeos\Controller\Frontend\Order\Iface Order controller for fluent interface
80
	 * @since 2019.04
81
	 */
82
	public function compare( string $operator, string $key, $value ) : Iface
83
	{
84
		$this->addExpression( $this->filter->compare( $operator, $key, $value ) );
85
		return $this;
86
	}
87
88
89
	/**
90
	 * Returns the order for the given order ID
91
	 *
92
	 * @param string $id Unique order ID
93
	 * @param bool $default Use default criteria to limit orders
94
	 * @return \Aimeos\MShop\Order\Item\Iface Order item object
95
	 * @since 2019.04
96
	 */
97
	public function get( string $id, bool $default = true ) : \Aimeos\MShop\Order\Item\Iface
98
	{
99
		return $this->manager->get( $id, $this->domains, $default );
100
	}
101
102
103
	/**
104
	 * Parses the given array and adds the conditions to the list of conditions
105
	 *
106
	 * @param array $conditions List of conditions, e.g. ['&&' => [['>' => ['order.statuspayment' => 0]], ['==' => ['order.type' => 'web']]]]
107
	 * @return \Aimeos\Controller\Frontend\Order\Iface Order controller for fluent interface
108
	 * @since 2019.04
109
	 */
110
	public function parse( array $conditions ) : Iface
111
	{
112
		if( ( $cond = $this->filter->parse( $conditions ) ) !== null ) {
113
			$this->addExpression( $cond );
114
		}
115
116
		return $this;
117
	}
118
119
120
	/**
121
	 * Updates the given order item in the storage
122
	 *
123
	 * @param \Aimeos\MShop\Order\Item\Iface $orderItem Order item object
124
	 * @return \Aimeos\MShop\Order\Item\Iface $orderItem Saved order item object
125
	 * @since 2019.04
126
	 */
127
	public function save( \Aimeos\MShop\Order\Item\Iface $orderItem ) : \Aimeos\MShop\Order\Item\Iface
128
	{
129
		return $this->manager->save( $orderItem );
130
	}
131
132
	/**
133
	 * Returns the orders filtered by the previously assigned conditions
134
	 *
135
	 * @param int &$total Parameter where the total number of found attributes will be stored in
136
	 * @return \Aimeos\Map Ordered list of order items implementing \Aimeos\MShop\Order\Item\Iface
137
	 * @since 2019.04
138
	 */
139
	public function search( int &$total = null ) : \Aimeos\Map
140
	{
141
		$this->filter->setConditions( $this->filter->and( $this->getConditions() ) );
142
		$this->filter->setSortations( $this->getSortations() );
143
144
		return $this->manager->search( $this->filter, $this->domains, $total );
145
	}
146
147
148
	/**
149
	 * Sets the start value and the number of returned orders for slicing the list of found orders
150
	 *
151
	 * @param int $start Start value of the first order in the list
152
	 * @param int $limit Number of returned orders
153
	 * @return \Aimeos\Controller\Frontend\Order\Iface Order controller for fluent interface
154
	 * @since 2019.04
155
	 */
156
	public function slice( int $start, int $limit ) : Iface
157
	{
158
		$maxsize = $this->getContext()->config()->get( 'controller/frontend/common/max-size', 250 );
159
		$this->filter->slice( $start, min( $limit, $maxsize ) );
160
		return $this;
161
	}
162
163
164
	/**
165
	 * Sets the sorting of the result list
166
	 *
167
	 * @param string|null $key Sorting of the result list like "-order.id", null for no sorting
168
	 * @return \Aimeos\Controller\Frontend\Order\Iface Order controller for fluent interface
169
	 * @since 2019.04
170
	 */
171
	public function sort( string $key = null ) : Iface
172
	{
173
		$list = $this->splitKeys( $key );
174
175
		foreach( $list as $sortkey )
176
		{
177
			$direction = ( $sortkey[0] === '-' ? '-' : '+' );
178
			$this->addExpression( $this->filter->sort( $direction, ltrim( $sortkey, '+-' ) ) );
179
		}
180
181
		return $this;
182
	}
183
184
185
	/**
186
	 * Saves the modified order item in the storage and blocks the stock and coupon codes
187
	 *
188
	 * @return \Aimeos\MShop\Order\Item\Iface New or updated order item object
189
	 * @since 2019.04
190
	 */
191
	public function store() : \Aimeos\MShop\Order\Item\Iface
192
	{
193
		$this->checkLimit( $this->item->getBaseId() );
194
195
		$cntl = \Aimeos\Controller\Common\Order\Factory::create( $this->getContext() );
196
		$this->item = $this->manager->save( $this->item );
197
198
		return $cntl->block( $this->item );
199
	}
200
201
202
	/**
203
	 * Sets the referenced domains that will be fetched too when retrieving items
204
	 *
205
	 * @param array $domains Domain names of the referenced items that should be fetched too
206
	 * @return \Aimeos\Controller\Frontend\Order\Iface Order controller for fluent interface
207
	 * @since 2019.04
208
	 */
209
	public function uses( array $domains ) : Iface
210
	{
211
		$this->domains = $domains;
212
		return $this;
213
	}
214
215
216
	/**
217
	 * Checks if more orders than allowed have been created by the user
218
	 *
219
	 * @param string $baseId Unique ID of the order base item (basket)
220
	 * @return \Aimeos\Controller\Frontend\Order\Iface Order controller for fluent interface
221
	 * @throws \Aimeos\Controller\Frontend\Order\Exception If limit is exceeded
222
	 */
223
	protected function checkLimit( string $baseId ) : Iface
224
	{
225
		$config = $this->getContext()->getConfig();
226
227
		/** controller/frontend/order/limit-count
228
		 * Maximum number of invoices within the time frame
229
		 *
230
		 * Creating new invoices is limited to avoid abuse and mitigate denial of
231
		 * service attacks. The number of invoices created within the time frame
232
		 * configured by "controller/frontend/invoices/limit-seconds" are counted
233
		 * before a new invoice of the same user (either logged in or identified
234
		 * by the IP address) is created. If the number of invoices is higher than
235
		 * the configured value, an error message will be shown to the user
236
		 * instead of creating a new invoice.
237
		 *
238
		 * @param integer Number of orders allowed within the time frame
239
		 * @since 2020.10
240
		 * @category Developer
241
		 * @see controller/frontend/order/limit-seconds
242
		 * @see controller/frontend/basket/limit-count
243
		 * @see controller/frontend/basket/limit-seconds
244
		 */
245
		 $count = $config->get( 'controller/frontend/order/limit-count', 3 );
246
247
		/** controller/frontend/order/limit-seconds
248
		 * Invoice limitation time frame in seconds
249
		 *
250
		 * Creating new invoices is limited to avoid abuse and mitigate denial of
251
		 * service attacks. Within the configured time frame, only one invoice
252
		 * item can be created per order base item. All invoices for the order
253
		 * base item within the last X seconds are counted.  If there's already
254
		 * one available, an error message will be shown to the user instead of
255
		 * creating the new order item.
256
		 *
257
		 * @param integer Number of seconds to check order items within
258
		 * @since 2017.05
259
		 * @category Developer
260
		 * @see controller/frontend/order/limit-count
261
		 * @see controller/frontend/basket/limit-count
262
		 * @see controller/frontend/basket/limit-seconds
263
		 */
264
		$seconds = $config->get( 'controller/frontend/order/limit-seconds', 900 );
265
266
		$search = $this->manager->filter()->slice( 0, 0 );
267
		$search->setConditions( $search->and( [
268
			$search->compare( '==', 'order.baseid', $baseId ),
269
			$search->compare( '>=', 'order.ctime', date( 'Y-m-d H:i:s', time() - $seconds ) ),
270
		] ) );
271
272
		$total = 0;
273
		$this->manager->search( $search, [], $total );
274
275
		if( $total >= $count ) {
276
			throw new \Aimeos\Controller\Frontend\Order\Exception( sprintf( 'The order has already been created' ) );
277
		}
278
279
		return $this;
280
	}
281
282
283
	/**
284
	 * Returns the manager used by the controller
285
	 *
286
	 * @return \Aimeos\MShop\Common\Manager\Iface Manager object
287
	 */
288
	protected function getManager() : \Aimeos\MShop\Common\Manager\Iface
289
	{
290
		return $this->manager;
291
	}
292
}
293