1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/** |
4
|
|
|
* @license LGPLv3, http://opensource.org/licenses/LGPL-3.0 |
5
|
|
|
* @copyright Metaways Infosystems GmbH, 2012 |
6
|
|
|
* @copyright Aimeos (aimeos.org), 2015-2017 |
7
|
|
|
* @package Controller |
8
|
|
|
* @subpackage Frontend |
9
|
|
|
*/ |
10
|
|
|
|
11
|
|
|
|
12
|
|
|
namespace Aimeos\Controller\Frontend\Service; |
13
|
|
|
|
14
|
|
|
use \Psr\Http\Message\ServerRequestInterface; |
15
|
|
|
use \Psr\Http\Message\ResponseInterface; |
16
|
|
|
|
17
|
|
|
|
18
|
|
|
/** |
19
|
|
|
* Default implementation of the service frontend controller. |
20
|
|
|
* |
21
|
|
|
* @package Controller |
22
|
|
|
* @subpackage Frontend |
23
|
|
|
*/ |
24
|
|
|
class Standard |
25
|
|
|
extends \Aimeos\Controller\Frontend\Base |
26
|
|
|
implements Iface, \Aimeos\Controller\Frontend\Common\Iface |
27
|
|
|
{ |
28
|
|
|
private $providers = array(); |
29
|
|
|
|
30
|
|
|
|
31
|
|
|
/** |
32
|
|
|
* Returns a list of attributes that are invalid |
33
|
|
|
* |
34
|
|
|
* @param string $serviceId Unique service ID |
35
|
|
|
* @param string[] $attributes List of attribute codes as keys and strings entered by the customer as value |
36
|
|
|
* @return string[] List of attributes codes as keys and error messages as values for invalid or missing values |
37
|
|
|
*/ |
38
|
|
|
public function checkAttributes( $serviceId, array $attributes ) |
39
|
|
|
{ |
40
|
|
|
$manager = \Aimeos\MShop\Factory::createManager( $this->getContext(), 'service' ); |
41
|
|
|
$provider = $manager->getProvider( $manager->getItem( $serviceId, [], true ) ); |
|
|
|
|
42
|
|
|
|
43
|
|
|
return array_filter( $provider->checkConfigFE( $attributes ) ); |
44
|
|
|
} |
45
|
|
|
|
46
|
|
|
|
47
|
|
|
/** |
48
|
|
|
* Returns the service item for the given ID |
49
|
|
|
* |
50
|
|
|
* @param string $serviceId Unique service ID |
51
|
|
|
* @param string[] $ref List of domain names whose items should be fetched too |
52
|
|
|
* @return \Aimeos\MShop\Service\Provider\Iface Service provider object |
53
|
|
|
*/ |
54
|
|
|
public function getProvider( $serviceId, $ref = ['media', 'price', 'text'] ) |
55
|
|
|
{ |
56
|
|
|
$manager = \Aimeos\MShop\Factory::createManager( $this->getContext(), 'service' ); |
57
|
|
|
return $manager->getProvider( $manager->getItem( $serviceId, $ref, true ) ); |
|
|
|
|
58
|
|
|
} |
59
|
|
|
|
60
|
|
|
|
61
|
|
|
/** |
62
|
|
|
* Returns the service providers of the given type |
63
|
|
|
* |
64
|
|
|
* @param string|null $type Service type, e.g. "delivery" (shipping related), "payment" (payment related) or null for all |
65
|
|
|
* @param string[] $ref List of domain names whose items should be fetched too |
66
|
|
|
* @return \Aimeos\MShop\Service\Provider\Iface[] List of service IDs as keys and service provider objects as values |
67
|
|
|
*/ |
68
|
|
|
public function getProviders( $type = null, $ref = ['media', 'price', 'text'] ) |
69
|
|
|
{ |
70
|
|
|
$list = []; |
71
|
|
|
$manager = \Aimeos\MShop\Factory::createManager( $this->getContext(), 'service' ); |
72
|
|
|
|
73
|
|
|
$search = $manager->createSearch( true ); |
74
|
|
|
$search->setSortations( array( $search->sort( '+', 'service.position' ) ) ); |
75
|
|
|
|
76
|
|
|
if( $type != null ) |
|
|
|
|
77
|
|
|
{ |
78
|
|
|
$expr = array( |
79
|
|
|
$search->getConditions(), |
80
|
|
|
$search->compare( '==', 'service.type.code', $type ), |
81
|
|
|
$search->compare( '==', 'service.type.domain', 'service' ), |
82
|
|
|
); |
83
|
|
|
$search->setConditions( $search->combine( '&&', $expr ) ); |
84
|
|
|
} |
85
|
|
|
|
86
|
|
|
foreach( $manager->searchItems( $search, $ref ) as $id => $item ) { |
87
|
|
|
$list[$id] = $manager->getProvider( $item ); |
88
|
|
|
} |
89
|
|
|
|
90
|
|
|
return $list; |
91
|
|
|
} |
92
|
|
|
|
93
|
|
|
|
94
|
|
|
/** |
95
|
|
|
* Processes the service for the given order, e.g. payment and delivery services |
96
|
|
|
* |
97
|
|
|
* @param \Aimeos\MShop\Order\Item\Iface $orderItem Order which should be processed |
98
|
|
|
* @param string $serviceId Unique service item ID |
99
|
|
|
* @param array $urls Associative list of keys and the corresponding URLs |
100
|
|
|
* (keys are <type>.url-self, <type>.url-success, <type>.url-update where type can be "delivery" or "payment") |
101
|
|
|
* @param array $params Request parameters and order service attributes |
102
|
|
|
* @return \Aimeos\MShop\Common\Item\Helper\Form\Iface|null Form object with URL, parameters, etc. |
103
|
|
|
* or null if no form data is required |
104
|
|
|
*/ |
105
|
|
|
public function process( \Aimeos\MShop\Order\Item\Iface $orderItem, $serviceId, array $urls, array $params ) |
106
|
|
|
{ |
107
|
|
|
$manager = \Aimeos\MShop\Factory::createManager( $this->getContext(), 'service' ); |
108
|
|
|
|
109
|
|
|
$provider = $manager->getProvider( $manager->getItem( $serviceId, [], true ) ); |
|
|
|
|
110
|
|
|
$provider->injectGlobalConfigBE( $urls ); |
111
|
|
|
|
112
|
|
|
return $provider->process( $orderItem, $params ); |
113
|
|
|
} |
114
|
|
|
|
115
|
|
|
|
116
|
|
|
/** |
117
|
|
|
* Updates the payment or delivery status for the given request |
118
|
|
|
* |
119
|
|
|
* @param ServerRequestInterface $request Request object with parameters and request body |
120
|
|
|
* @param ResponseInterface &$response Response object that will contain HTTP status and response body |
121
|
|
|
* @param array $urls Associative list of keys and the corresponding URLs |
122
|
|
|
* (keys are <type>.url-self, <type>.url-success, <type>.url-update where type can be "delivery" or "payment") |
123
|
|
|
* @return \Aimeos\MShop\Order\Item\Iface $orderItem Order item that has been updated |
124
|
|
|
*/ |
125
|
|
|
public function updateSync( ServerRequestInterface $request, ResponseInterface &$response, array $urls ) |
126
|
|
|
{ |
127
|
|
|
$queryParams = $request->getQueryParams(); |
128
|
|
|
|
129
|
|
|
if( !isset( $queryParams['code'] ) ) { |
130
|
|
|
return; |
131
|
|
|
} |
132
|
|
|
|
133
|
|
|
$context = $this->getContext(); |
134
|
|
|
$manager = \Aimeos\MShop\Factory::createManager( $context, 'service' ); |
135
|
|
|
|
136
|
|
|
$provider = $manager->getProvider( $manager->findItem( $queryParams['code'] ) ); |
137
|
|
|
$provider->injectGlobalConfigBE( $urls ); |
138
|
|
|
|
139
|
|
|
$params = array_merge( $queryParams, (array) $request->getParsedBody() ); |
140
|
|
|
$body = (string) $request->getBody(); |
141
|
|
|
$response = null; |
142
|
|
|
$headers = []; |
143
|
|
|
|
144
|
|
|
if( ( $orderItem = $provider->updateSync( $params, $body, $response, $headers ) ) !== null ) |
145
|
|
|
{ |
146
|
|
|
if( $orderItem->getPaymentStatus() === \Aimeos\MShop\Order\Item\Base::PAY_UNFINISHED |
147
|
|
|
&& $provider->isImplemented( \Aimeos\MShop\Service\Provider\Payment\Base::FEAT_QUERY ) |
148
|
|
|
) { |
149
|
|
|
$provider->query( $orderItem ); |
150
|
|
|
} |
151
|
|
|
|
152
|
|
|
// update stock, coupons, etc. |
153
|
|
|
\Aimeos\Controller\Frontend\Factory::createController( $context, 'order' )->update( $orderItem ); |
154
|
|
|
} |
155
|
|
|
|
156
|
|
|
return $orderItem; |
157
|
|
|
} |
158
|
|
|
|
159
|
|
|
|
160
|
|
|
/** |
161
|
|
|
* Returns the service items that are available for the service type and the content of the basket. |
162
|
|
|
* |
163
|
|
|
* @param string $type Service type, e.g. "delivery" (shipping related) or "payment" (payment related) |
164
|
|
|
* @param \Aimeos\MShop\Order\Item\Base\Iface $basket Basket of the user |
165
|
|
|
* @param array $ref List of domains for which the items referenced by the services should be fetched too |
166
|
|
|
* @return array List of service items implementing \Aimeos\MShop\Service\Item\Iface with referenced items |
167
|
|
|
* @throws \Exception If an error occurs |
168
|
|
|
* @deprecated Use getProviders() instead |
169
|
|
|
*/ |
170
|
|
|
public function getServices( $type, \Aimeos\MShop\Order\Item\Base\Iface $basket, $ref = ['media', 'price', 'text'] ) |
171
|
|
|
{ |
172
|
|
|
$serviceManager = \Aimeos\MShop\Factory::createManager( $this->getContext(), 'service' ); |
173
|
|
|
|
174
|
|
|
$search = $serviceManager->createSearch( true ); |
175
|
|
|
$expr = array( |
176
|
|
|
$search->getConditions(), |
177
|
|
|
$search->compare( '==', 'service.type.domain', 'service' ), |
178
|
|
|
$search->compare( '==', 'service.type.code', $type ), |
179
|
|
|
); |
180
|
|
|
$search->setConditions( $search->combine( '&&', $expr ) ); |
181
|
|
|
$search->setSortations( array( $search->sort( '+', 'service.position' ) ) ); |
182
|
|
|
|
183
|
|
|
$items = $serviceManager->searchItems( $search, $ref ); |
184
|
|
|
|
185
|
|
|
|
186
|
|
|
foreach( $items as $id => $service ) |
187
|
|
|
{ |
188
|
|
|
try |
189
|
|
|
{ |
190
|
|
|
$provider = $serviceManager->getProvider( $service ); |
191
|
|
|
|
192
|
|
|
if( $provider->isAvailable( $basket ) ) { |
193
|
|
|
$this->providers[$type][$id] = $provider; |
194
|
|
|
} else { |
195
|
|
|
unset( $items[$id] ); |
196
|
|
|
} |
197
|
|
|
} |
198
|
|
|
catch( \Aimeos\MShop\Service\Exception $e ) |
199
|
|
|
{ |
200
|
|
|
$msg = sprintf( 'Unable to create provider "%1$s" for service with ID "%2$s"', $service->getCode(), $id ); |
201
|
|
|
$this->getContext()->getLogger()->log( $msg, \Aimeos\MW\Logger\Base::WARN ); |
202
|
|
|
} |
203
|
|
|
} |
204
|
|
|
|
205
|
|
|
return $items; |
206
|
|
|
} |
207
|
|
|
|
208
|
|
|
|
209
|
|
|
/** |
210
|
|
|
* Returns the list of attribute definitions which must be used to render the input form where the customer can |
211
|
|
|
* enter or chose the required data necessary by the service provider. |
212
|
|
|
* |
213
|
|
|
* @param string $type Service type, e.g. "delivery" (shipping related) or "payment" (payment related) |
214
|
|
|
* @param string $serviceId Identifier of one of the service option returned by getService() |
215
|
|
|
* @param \Aimeos\MShop\Order\Item\Base\Iface $basket Basket object |
216
|
|
|
* @return array List of attribute definitions implementing \Aimeos\MW\Criteria\Attribute\Iface |
217
|
|
|
* @throws \Aimeos\Controller\Frontend\Service\Exception If no active service provider for this ID is available |
218
|
|
|
* @throws \Aimeos\MShop\Exception If service provider isn't available |
219
|
|
|
* @throws \Exception If an error occurs |
220
|
|
|
* @deprecated Use getProvider() instead |
221
|
|
|
*/ |
222
|
|
|
public function getServiceAttributes( $type, $serviceId, \Aimeos\MShop\Order\Item\Base\Iface $basket ) |
223
|
|
|
{ |
224
|
|
|
if( isset( $this->providers[$type][$serviceId] ) ) { |
225
|
|
|
return $this->providers[$type][$serviceId]->getConfigFE( $basket ); |
226
|
|
|
} |
227
|
|
|
|
228
|
|
|
$serviceManager = \Aimeos\MShop\Factory::createManager( $this->getContext(), 'service' ); |
229
|
|
|
$item = $serviceManager->getItem( $serviceId, ['price'], true ); |
|
|
|
|
230
|
|
|
|
231
|
|
|
return $serviceManager->getProvider( $item )->getConfigFE( $basket ); |
232
|
|
|
} |
233
|
|
|
|
234
|
|
|
|
235
|
|
|
/** |
236
|
|
|
* Returns the price of the service. |
237
|
|
|
* |
238
|
|
|
* @param string $type Service type, e.g. "delivery" (shipping related) or "payment" (payment related) |
239
|
|
|
* @param string $serviceId Identifier of one of the service option returned by getService() |
240
|
|
|
* @param \Aimeos\MShop\Order\Item\Base\Iface $basket Basket with products |
241
|
|
|
* @return \Aimeos\MShop\Price\Item\Iface Price item |
242
|
|
|
* @throws \Aimeos\Controller\Frontend\Service\Exception If no active service provider for this ID is available |
243
|
|
|
* @throws \Aimeos\MShop\Exception If service provider isn't available |
244
|
|
|
* @throws \Exception If an error occurs |
245
|
|
|
* @deprecated Use getProvider() instead |
246
|
|
|
*/ |
247
|
|
|
public function getServicePrice( $type, $serviceId, \Aimeos\MShop\Order\Item\Base\Iface $basket ) |
248
|
|
|
{ |
249
|
|
|
if( isset( $this->providers[$type][$serviceId] ) ) { |
250
|
|
|
return $this->providers[$type][$serviceId]->calcPrice( $basket ); |
251
|
|
|
} |
252
|
|
|
|
253
|
|
|
$serviceManager = \Aimeos\MShop\Factory::createManager( $this->getContext(), 'service' ); |
254
|
|
|
$item = $serviceManager->getItem( $serviceId, ['price'], true ); |
|
|
|
|
255
|
|
|
|
256
|
|
|
return $serviceManager->getProvider( $item )->calcPrice( $basket ); |
257
|
|
|
} |
258
|
|
|
|
259
|
|
|
|
260
|
|
|
/** |
261
|
|
|
* Returns a list of attributes that are invalid. |
262
|
|
|
* |
263
|
|
|
* @param string $type Service type, e.g. "delivery" (shipping related) or "payment" (payment related) |
264
|
|
|
* @param string $serviceId Identifier of the service option chosen by the customer |
265
|
|
|
* @param array $attributes List of key/value pairs with name of the attribute from attribute definition object as |
266
|
|
|
* key and the string entered by the customer as value |
267
|
|
|
* @return array An array with the attribute keys as key and an error message as values for all attributes that are |
268
|
|
|
* known by the provider but aren't valid resp. null for attributes whose values are OK |
269
|
|
|
* @throws \Aimeos\Controller\Frontend\Service\Exception If no active service provider for this ID is available |
270
|
|
|
* @deprecated Use checkAttributes() instead |
271
|
|
|
*/ |
272
|
|
|
public function checkServiceAttributes( $type, $serviceId, array $attributes ) |
273
|
|
|
{ |
274
|
|
|
if( !isset( $this->providers[$type][$serviceId] ) ) |
275
|
|
|
{ |
276
|
|
|
$serviceManager = \Aimeos\MShop\Factory::createManager( $this->getContext(), 'service' ); |
277
|
|
|
$item = $serviceManager->getItem( $serviceId, ['price'], true ); |
|
|
|
|
278
|
|
|
|
279
|
|
|
$this->providers[$type][$serviceId] = $serviceManager->getProvider( $item ); |
280
|
|
|
} |
281
|
|
|
|
282
|
|
|
$errors = $this->providers[$type][$serviceId]->checkConfigFE( $attributes ); |
283
|
|
|
|
284
|
|
|
foreach( $errors as $key => $msg ) |
285
|
|
|
{ |
286
|
|
|
if( $msg === null ) { |
287
|
|
|
unset( $errors[$key] ); |
288
|
|
|
} |
289
|
|
|
} |
290
|
|
|
|
291
|
|
|
return $errors; |
292
|
|
|
} |
293
|
|
|
} |
294
|
|
|
|
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.
If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.
In this case you can add the
@ignore
PhpDoc annotation to the duplicate definition and it will be ignored.