Completed
Push — master ( 0e5809...a07fab )
by Aimeos
07:49
created

Standard::getBasket()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 16
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 16
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 9
nc 2
nop 1
1
<?php
2
3
/**
4
 * @license LGPLv3, http://opensource.org/licenses/LGPL-3.0
5
 * @copyright Aimeos (aimeos.org), 2017
6
 * @package Client
7
 * @subpackage JsonApi
8
 */
9
10
11
namespace Aimeos\Client\JsonApi\Order;
12
13
use Psr\Http\Message\ResponseInterface;
14
use Psr\Http\Message\ServerRequestInterface;
15
16
17
/**
18
 * JSON API standard client
19
 *
20
 * @package Client
21
 * @subpackage JsonApi
22
 */
23
class Standard
24
	extends \Aimeos\Client\JsonApi\Base
25
	implements \Aimeos\Client\JsonApi\Iface
26
{
27
	/**
28
	 * Returns the resource or the resource list
29
	 *
30
	 * @param \Psr\Http\Message\ServerRequestInterface $request Request object
31
	 * @param \Psr\Http\Message\ResponseInterface $response Response object
32
	 * @param string|null $prefix Form parameter prefix when nesting parameters is required
33
	 * @return \Psr\Http\Message\ResponseInterface Modified response object
34
	 */
35
	public function get( ServerRequestInterface $request, ResponseInterface $response, $prefix = null )
36
	{
37
		$view = $this->getView();
38
		$view->prefix = $prefix;
39
40
		try
41
		{
42
			$cntl = \Aimeos\Controller\Frontend\Factory::createController( $this->getContext(), 'order' );
43
44
			if( ( $id = $view->param( 'id' ) ) != '' )
45
			{
46
				$view->items = $cntl->getItem( $id );
47
				$view->total = 1;
48
			}
49
			else
50
			{
51
				$total = 0;
52
				$filter = $cntl->createFilter();
53
				$this->initCriteria( $filter, $view->param() );
54
55
				$view->items = $cntl->searchItems( $filter, $total );
56
				$view->total = $total;
57
			}
58
59
			$status = 200;
60
		}
61
		catch( \Aimeos\Controller\Frontend\Exception $e )
62
		{
63
			$status = 403;
64
			$view->errors = $this->getErrorDetails( $e, 'controller/frontend' );
65
		}
66
		catch( \Aimeos\MShop\Exception $e )
67
		{
68
			$status = 404;
69
			$view->errors = $this->getErrorDetails( $e, 'mshop' );
70
		}
71
		catch( \Exception $e )
72
		{
73
			$status = 500;
74
			$view->errors = $this->getErrorDetails( $e );
75
		}
76
77
		return $this->render( $response, $view, $status );
78
	}
79
80
81
	/**
82
	 * Creates or updates the resource or the resource list
83
	 *
84
	 * @param \Psr\Http\Message\ServerRequestInterface $request Request object
85
	 * @param \Psr\Http\Message\ResponseInterface $response Response object
86
	 * @param string|null $prefix Form parameter prefix when nesting parameters is required
87
	 * @return \Psr\Http\Message\ResponseInterface Modified response object
88
	 */
89
	public function post( ServerRequestInterface $request, ResponseInterface $response, $prefix = null )
90
	{
91
		$view = $this->getView();
92
		$view->prefix = $prefix;
93
94
		try
95
		{
96
			$body = (string) $request->getBody();
97
98
			if( ( $payload = json_decode( $body ) ) === null || !isset( $payload->data->attributes ) ) {
99
				throw new \Aimeos\Client\JsonApi\Exception( sprintf( 'Invalid JSON in body' ), 400 );
100
			}
101
102
			if( !isset( $payload->data->attributes->{'order.baseid'} ) ) {
103
				throw new \Aimeos\Client\JsonApi\Exception( sprintf( 'Required attribute "order.baseid" is missing' ), 400 );
104
			}
105
106
			$basket = $this->getBasket( $payload->data->attributes->{'order.baseid'} );
107
			$item = $this->createOrder( $payload->data->attributes->{'order.baseid'} );
108
109
			$view->form = $this->getPaymentForm( $basket, $item, (array) $payload->data->attributes );
110
			$view->items = $item;
111
			$view->total = 1;
112
113
			$status = 201;
114
		}
115
		catch( \Aimeos\Client\JsonApi\Exception $e )
116
		{
117
			$status = $e->getCode();
118
			$view->errors = $this->getErrorDetails( $e, 'client/jsonapi' );
119
		}
120
		catch( \Aimeos\Controller\Frontend\Exception $e )
121
		{
122
			$status = 403;
123
			$view->errors = $this->getErrorDetails( $e, 'controller/frontend' );
124
		}
125
		catch( \Aimeos\MShop\Exception $e )
126
		{
127
			$status = 404;
128
			$view->errors = $this->getErrorDetails( $e, 'mshop' );
129
		}
130
		catch( \Exception $e )
131
		{
132
			$status = 500;
133
			$view->errors = $this->getErrorDetails( $e );
134
		}
135
136
		return $this->render( $response, $view, $status );
137
	}
138
139
140
	/**
141
	 * Returns the available REST verbs and the available parameters
142
	 *
143
	 * @param \Psr\Http\Message\ServerRequestInterface $request Request object
144
	 * @param \Psr\Http\Message\ResponseInterface $response Response object
145
	 * @param string|null $prefix Form parameter prefix when nesting parameters is required
146
	 * @return \Psr\Http\Message\ResponseInterface Modified response object
147
	 */
148
	public function options( ServerRequestInterface $request, ResponseInterface $response, $prefix = null )
149
	{
150
		$view = $this->getView();
151
		$view->prefix = $prefix;
152
153
		$view->attributes = [
154
			'order.baseid' => [
155
				'label' => 'ID of the stored basket (POST only)',
156
				'type' => 'string', 'default' => '', 'required' => true,
157
			],
158
		];
159
160
		$tplconf = 'client/jsonapi/standard/template-options';
161
		$default = 'options-standard.php';
162
163
		$body = $view->render( $view->config( $tplconf, $default ) );
164
165
		return $response->withHeader( 'Allow', 'GET,OPTIONS,POST' )
166
			->withHeader( 'Cache-Control', 'max-age=300' )
167
			->withHeader( 'Content-Type', 'application/vnd.api+json' )
168
			->withBody( $view->response()->createStreamFromString( $body ) )
169
			->withStatus( 200 );
170
	}
171
172
173
	/**
174
	 * Adds and returns a new order item for the given order base ID
175
	 *
176
	 * @param string $baseId Unique order base ID
177
	 * @return \Aimeos\MShop\Order\Item\Iface New order item
178
	 */
179
	protected function createOrder( $baseId )
180
	{
181
		$context = $this->getContext();
182
		$cntl = \Aimeos\Controller\Frontend\Factory::createController( $context, 'order' );
183
184
		$item = $cntl->addItem( $baseId, 'jsonapi' );
185
		$cntl->block( $item );
186
187
		$context->getSession()->set( 'aimeos/orderid', $item->getId() );
188
189
		return $item;
190
	}
191
192
193
	/**
194
	 * Returns the basket object for the given ID
195
	 *
196
	 * @param string $basketId Unique order base ID
197
	 * @return \Aimeos\MShop\Order\Item\Base\Iface Basket object including only the services
198
	 * @throws \Aimeos\Client\JsonApi\Exception If basket ID is not the same as stored before in the current session
199
	 */
200
	protected function getBasket( $basketId )
201
	{
202
		$context = $this->getContext();
203
		$baseId = $context->getSession()->get( 'aimeos/order.baseid' );
204
205
		if( $baseId != $basketId )
206
		{
207
			$msg = sprintf( 'No basket for the "order.baseid" ("%1$s") found', $basketId );
208
			throw new \Aimeos\Client\JsonApi\Exception( $msg, 403 );
209
		}
210
211
		$parts = \Aimeos\MShop\Order\Manager\Base\Base::PARTS_SERVICE;
212
		$cntl = \Aimeos\Controller\Frontend\Factory::createController( $context, 'basket' );
213
214
		return $cntl->load( $baseId, $parts, false );
215
	}
216
217
218
	/**
219
	 * Returns the form helper object for building the payment form in the frontend
220
	 *
221
	 * @param \Aimeos\MShop\Order\Item\Base\Iface $basket Saved basket object including payment service object
222
	 * @param \Aimeos\MShop\Order\Item\Iface $orderItem Saved order item created for the basket object
223
	 * @param array $attributes Associative list of payment data pairs
224
	 * @return \Aimeos\MShop\Common\Item\Helper\Form\Iface|null Form object with URL, parameters, etc.
225
	 * 	or null if no form data is required
226
	 */
227
	protected function getPaymentForm( \Aimeos\MShop\Order\Item\Base\Iface $basket,
228
		\Aimeos\MShop\Order\Item\Iface $orderItem, array $attributes )
229
	{
230
		$view = $this->getView();
231
		$service = $basket->getService( \Aimeos\MShop\Order\Item\Base\Service\Base::TYPE_PAYMENT );
232
233
		if( $basket->getPrice()->getValue() + $basket->getPrice()->getCosts() <= '0.00' )
234
		{
235
			$manager = \Aimeos\MShop\Factory::createManager( $context, 'order' );
0 ignored issues
show
Bug introduced by
The variable $context does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
236
237
			$orderItem->setPaymentStatus( \Aimeos\MShop\Order\Item\Base::PAY_RECEIVED );
238
			$orderItem->setDatePayment( date( 'Y-m-d H:i:s' ) );
239
			$orderItem = $manager->saveItem( $orderItem );
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $orderItem is correct as $manager->saveItem($orderItem) (which targets Aimeos\MShop\Common\Manager\Iface::saveItem()) seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
Unused Code introduced by
$orderItem is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
240
241
			$config = ['absoluteUri' => true, 'namespace' => false];
242
			return new \Aimeos\MShop\Common\Item\Helper\Form\Standard( $this->getUrlConfirm( $view, [], $config ) );
243
		}
244
245
		$config = array( 'absoluteUri' => true, 'namespace' => false );
246
		$args = array( 'code' => $service->getCode(), 'orderid' => $orderItem->getId() );
247
		$urls = array(
248
			'payment.url-success' => $this->getUrlConfirm( $view, $args, $config ),
249
			'payment.url-update' => $this->getUrlUpdate( $view, $args, $config ),
250
		);
251
252
		foreach( $service->getAttributes() as $item ) {
253
			$attributes[$item->getCode()] = $item->getValue();
254
		}
255
256
		$serviceCntl = \Aimeos\Controller\Frontend\Factory::createController( $this->getContext(), 'service' );
257
		return $serviceCntl->process( $orderItem, $service->getServiceId(), $urls, $attributes );
258
	}
259
260
261
	/**
262
	 * Returns the URL to the confirm page.
263
	 *
264
	 * @param \Aimeos\MW\View\Iface $view View object
265
	 * @param array $params Parameters that should be part of the URL
266
	 * @param array $config Default URL configuration
267
	 * @return string URL string
268
	 */
269
	protected function getUrlConfirm( \Aimeos\MW\View\Iface $view, array $params, array $config )
270
	{
271
		$target = $view->config( 'client/html/checkout/confirm/url/target' );
272
		$cntl = $view->config( 'client/html/checkout/confirm/url/controller', 'checkout' );
273
		$action = $view->config( 'client/html/checkout/confirm/url/action', 'confirm' );
274
		$config = $view->config( 'client/html/checkout/confirm/url/config', $config );
275
276
		return $view->url( $target, $cntl, $action, $params, [], $config );
277
	}
278
279
280
	/**
281
	 * Returns the URL to the update page.
282
	 *
283
	 * @param \Aimeos\MW\View\Iface $view View object
284
	 * @param array $params Parameters that should be part of the URL
285
	 * @param array $config Default URL configuration
286
	 * @return string URL string
287
	 */
288
	protected function getUrlUpdate( \Aimeos\MW\View\Iface $view, array $params, array $config )
289
	{
290
		$target = $view->config( 'client/html/checkout/update/url/target' );
291
		$cntl = $view->config( 'client/html/checkout/update/url/controller', 'checkout' );
292
		$action = $view->config( 'client/html/checkout/update/url/action', 'update' );
293
		$config = $view->config( 'client/html/checkout/update/url/config', $config );
294
295
		return $view->url( $target, $cntl, $action, $params, [], $config );
296
	}
297
298
299
	/**
300
	 * Returns the response object with the rendered header and body
301
	 *
302
	 * @param \Psr\Http\Message\ResponseInterface $response Response object
303
	 * @param \Aimeos\MW\View\Iface $view View instance
304
	 * @param integer $status HTTP status code
305
	 * @return \Psr\Http\Message\ResponseInterface Modified response object
306
	 */
307
	protected function render( ResponseInterface $response, \Aimeos\MW\View\Iface $view, $status )
308
	{
309
		/** client/jsonapi/order/standard/template
310
		 * Relative path to the order JSON API template
311
		 *
312
		 * The template file contains the code and processing instructions
313
		 * to generate the result shown in the JSON API body. The
314
		 * configuration string is the path to the template file relative
315
		 * to the templates directory (usually in client/jsonapi/templates).
316
		 *
317
		 * You can overwrite the template file configuration in extensions and
318
		 * provide alternative templates. These alternative templates should be
319
		 * named like the default one but with the string "standard" replaced by
320
		 * an unique name. You may use the name of your project for this. If
321
		 * you've implemented an alternative client class as well, "standard"
322
		 * should be replaced by the name of the new class.
323
		 *
324
		 * @param string Relative path to the template creating the body of the JSON API
325
		 * @since 2017.03
326
		 * @category Developer
327
		 */
328
		$tplconf = 'client/jsonapi/order/standard/template';
329
		$default = 'order/standard.php';
330
331
		$body = $view->render( $view->config( $tplconf, $default ) );
332
333
		return $response->withHeader( 'Allow', 'GET,OPTIONS,POST' )
334
			->withHeader( 'Cache-Control', 'no-cache, private' )
335
			->withHeader( 'Content-Type', 'application/vnd.api+json' )
336
			->withBody( $view->response()->createStreamFromString( $body ) )
337
			->withStatus( $status );
338
	}
339
}
340