|
1
|
|
|
<?php |
|
2
|
|
|
/** |
|
3
|
|
|
* (c) shopware AG <[email protected]> |
|
4
|
|
|
* For the full copyright and license information, please view the LICENSE |
|
5
|
|
|
* file that was distributed with this source code. |
|
6
|
|
|
*/ |
|
7
|
|
|
|
|
8
|
|
|
namespace ShopwarePlugins\Connect\Subscribers; |
|
9
|
|
|
|
|
10
|
|
|
use Shopware\Connect\Struct\PaymentStatus; |
|
11
|
|
|
use Shopware\Components\Model\ModelManager; |
|
12
|
|
|
use Shopware\CustomModels\Connect\Attribute; |
|
13
|
|
|
use ShopwarePlugins\Connect\Components\ErrorHandler; |
|
14
|
|
|
use ShopwarePlugins\Connect\Components\Utils; |
|
15
|
|
|
use ShopwarePlugins\Connect\Components\ConnectExport; |
|
16
|
|
|
use ShopwarePlugins\Connect\Components\Validator\ProductAttributesValidator\ProductsAttributesValidator; |
|
17
|
|
|
use Shopware\Models\Order\Order; |
|
18
|
|
|
|
|
19
|
|
|
/** |
|
20
|
|
|
* Handles article lifecycle events in order to automatically update/delete products to/from connect |
|
21
|
|
|
* |
|
22
|
|
|
* Class Lifecycle |
|
23
|
|
|
* @package ShopwarePlugins\Connect\Subscribers |
|
24
|
|
|
*/ |
|
25
|
|
|
class Lifecycle extends BaseSubscriber |
|
26
|
|
|
{ |
|
27
|
|
|
/** |
|
28
|
|
|
* @var \Shopware\Components\Model\ModelManager |
|
29
|
|
|
*/ |
|
30
|
|
|
private $manager; |
|
31
|
|
|
|
|
32
|
|
|
/** |
|
33
|
|
|
* @var int |
|
34
|
|
|
*/ |
|
35
|
|
|
private $autoUpdateProducts; |
|
36
|
|
|
|
|
37
|
|
|
/** |
|
38
|
|
|
* Lifecycle constructor. |
|
39
|
|
|
* |
|
40
|
|
|
* @param ModelManager $modelManager |
|
41
|
|
|
* @param int $autoUpdateProducts |
|
42
|
|
|
*/ |
|
43
|
|
|
public function __construct(ModelManager $modelManager, $autoUpdateProducts) |
|
44
|
|
|
{ |
|
45
|
|
|
parent::__construct(); |
|
46
|
|
|
|
|
47
|
|
|
$this->manager = $modelManager; |
|
48
|
|
|
$this->autoUpdateProducts = $autoUpdateProducts; |
|
49
|
|
|
} |
|
50
|
|
|
|
|
51
|
|
|
public function getSubscribedEvents() |
|
52
|
|
|
{ |
|
53
|
|
|
return [ |
|
54
|
|
|
'Shopware\Models\Article\Article::preUpdate' => 'onPreUpdate', |
|
55
|
|
|
'Shopware\Models\Article\Article::postPersist' => 'onUpdateArticle', |
|
56
|
|
|
'Shopware\Models\Article\Detail::postPersist' => 'onPersistDetail', |
|
57
|
|
|
'Shopware\Models\Article\Article::preRemove' => 'onDeleteArticle', |
|
58
|
|
|
'Shopware\Models\Article\Detail::preRemove' => 'onDeleteDetail', |
|
59
|
|
|
'Shopware\Models\Order\Order::postUpdate' => 'onUpdateOrder', |
|
60
|
|
|
'Shopware\Models\Shop\Shop::preRemove' => 'onDeleteShop', |
|
61
|
|
|
'Shopware\Models\Category\Category::preRemove' => 'onPreDeleteCategory', |
|
62
|
|
|
'Shopware\Models\Category\Category::postRemove' => 'onPostDeleteCategory' |
|
63
|
|
|
]; |
|
64
|
|
|
} |
|
65
|
|
|
|
|
66
|
|
|
/** |
|
67
|
|
|
* @return ConnectExport |
|
68
|
|
|
*/ |
|
69
|
|
|
public function getConnectExport() |
|
70
|
|
|
{ |
|
71
|
|
|
return new ConnectExport( |
|
72
|
|
|
$this->getHelper(), |
|
73
|
|
|
$this->getSDK(), |
|
74
|
|
|
$this->manager, |
|
75
|
|
|
new ProductsAttributesValidator(), |
|
76
|
|
|
$this->getConnectConfig(), |
|
77
|
|
|
new ErrorHandler(), |
|
78
|
|
|
Shopware()->Container()->get('events') |
|
79
|
|
|
); |
|
80
|
|
|
} |
|
81
|
|
|
|
|
82
|
|
|
public function onPreUpdate(\Enlight_Event_EventArgs $eventArgs) |
|
83
|
|
|
{ |
|
84
|
|
|
/** @var \Shopware\Models\Article\Article $entity */ |
|
85
|
|
|
$entity = $eventArgs->get('entity'); |
|
86
|
|
|
$db = Shopware()->Db(); |
|
87
|
|
|
|
|
88
|
|
|
// Check if entity is a connect product |
|
89
|
|
|
$attribute = $this->getHelper()->getConnectAttributeByModel($entity); |
|
90
|
|
|
if (!$attribute) { |
|
91
|
|
|
return; |
|
92
|
|
|
} |
|
93
|
|
|
|
|
94
|
|
|
// if article is not exported to Connect |
|
95
|
|
|
// don't need to generate changes |
|
96
|
|
|
if (!$this->getHelper()->isProductExported($attribute) || !empty($attribute->getShopId())) { |
|
97
|
|
|
return; |
|
98
|
|
|
} |
|
99
|
|
|
|
|
100
|
|
|
if (!$this->hasPriceType()) { |
|
101
|
|
|
return; |
|
102
|
|
|
} |
|
103
|
|
|
|
|
104
|
|
|
$changeSet = $eventArgs->get('entityManager')->getUnitOfWork()->getEntityChangeSet($entity); |
|
105
|
|
|
|
|
106
|
|
|
// If product propertyGroup is changed we need to store the old one, |
|
107
|
|
|
// because product property value are still not changed and |
|
108
|
|
|
// this will generate wrong Connect changes |
|
109
|
|
|
if ($changeSet['propertyGroup']) { |
|
110
|
|
|
$filterGroupId = $db->fetchOne( |
|
111
|
|
|
'SELECT filtergroupID FROM s_articles WHERE id = ?', [$entity->getId()] |
|
112
|
|
|
); |
|
113
|
|
|
|
|
114
|
|
|
$db->executeUpdate( |
|
115
|
|
|
'UPDATE `s_articles_attributes` SET `connect_property_group` = ? WHERE `articledetailsID` = ?', |
|
116
|
|
|
[$filterGroupId, $entity->getMainDetail()->getId()] |
|
117
|
|
|
); |
|
118
|
|
|
} |
|
119
|
|
|
} |
|
120
|
|
|
|
|
121
|
|
|
/** |
|
122
|
|
|
* @param \Enlight_Event_EventArgs $eventArgs |
|
123
|
|
|
*/ |
|
124
|
|
|
public function onUpdateOrder(\Enlight_Event_EventArgs $eventArgs) |
|
125
|
|
|
{ |
|
126
|
|
|
/** @var \Shopware\Models\Order\Order $order */ |
|
127
|
|
|
$order = $eventArgs->get('entity'); |
|
128
|
|
|
|
|
129
|
|
|
// Compute the changeset and return, if orderStatus did not change |
|
130
|
|
|
$changeSet = $eventArgs->get('entityManager')->getUnitOfWork()->getEntityChangeSet($order); |
|
131
|
|
|
|
|
132
|
|
|
if (isset($changeSet['paymentStatus'])) { |
|
133
|
|
|
$this->updatePaymentStatus($order); |
|
134
|
|
|
} |
|
135
|
|
|
|
|
136
|
|
|
if (isset($changeSet['orderStatus'])) { |
|
137
|
|
|
$this->updateOrderStatus($order); |
|
138
|
|
|
} |
|
139
|
|
|
} |
|
140
|
|
|
|
|
141
|
|
|
/** |
|
142
|
|
|
* Callback function to delete an product from connect |
|
143
|
|
|
* after it is going to be deleted locally |
|
144
|
|
|
* |
|
145
|
|
|
* @param \Enlight_Event_EventArgs $eventArgs |
|
146
|
|
|
*/ |
|
147
|
|
|
public function onDeleteArticle(\Enlight_Event_EventArgs $eventArgs) |
|
148
|
|
|
{ |
|
149
|
|
|
$entity = $eventArgs->get('entity'); |
|
150
|
|
|
$this->getConnectExport()->setDeleteStatusForVariants($entity); |
|
151
|
|
|
} |
|
152
|
|
|
|
|
153
|
|
|
/** |
|
154
|
|
|
* Callback function to delete an product from connect |
|
155
|
|
|
* after it is going to be deleted locally |
|
156
|
|
|
* |
|
157
|
|
|
* @param \Enlight_Event_EventArgs $eventArgs |
|
158
|
|
|
*/ |
|
159
|
|
|
public function onPreDeleteCategory(\Enlight_Event_EventArgs $eventArgs) |
|
160
|
|
|
{ |
|
161
|
|
|
$category = $eventArgs->get('entity'); |
|
162
|
|
|
$this->getConnectExport()->markProductsInToBeDeletedCategories($category); |
|
163
|
|
|
} |
|
164
|
|
|
|
|
165
|
|
|
/** |
|
166
|
|
|
* Callback function to delete an product from connect |
|
167
|
|
|
* after it is going to be deleted locally |
|
168
|
|
|
* |
|
169
|
|
|
* @param \Enlight_Event_EventArgs $eventArgs |
|
170
|
|
|
*/ |
|
171
|
|
|
public function onPostDeleteCategory(\Enlight_Event_EventArgs $eventArgs) |
|
172
|
|
|
{ |
|
173
|
|
|
$this->getConnectExport()->handleMarkedProducts(); |
|
174
|
|
|
} |
|
175
|
|
|
|
|
176
|
|
|
/** |
|
177
|
|
|
* Callback function to delete product detail from connect |
|
178
|
|
|
* after it is going to be deleted locally |
|
179
|
|
|
* |
|
180
|
|
|
* @param \Enlight_Event_EventArgs $eventArgs |
|
181
|
|
|
*/ |
|
182
|
|
|
public function onDeleteDetail(\Enlight_Event_EventArgs $eventArgs) |
|
183
|
|
|
{ |
|
184
|
|
|
/** @var \Shopware\Models\Article\Detail $entity */ |
|
185
|
|
|
$entity = $eventArgs->get('entity'); |
|
186
|
|
|
if ($entity->getKind() !== 1) { |
|
187
|
|
|
$attribute = $this->getHelper()->getConnectAttributeByModel($entity); |
|
188
|
|
|
if (!$this->getHelper()->isProductExported($attribute)) { |
|
189
|
|
|
return; |
|
190
|
|
|
} |
|
191
|
|
|
$this->getSDK()->recordDelete($attribute->getSourceId()); |
|
192
|
|
|
$this->getConnectExport()->updateConnectItemsStatus([$attribute->getSourceId()], Attribute::STATUS_DELETE); |
|
193
|
|
|
} |
|
194
|
|
|
} |
|
195
|
|
|
|
|
196
|
|
|
/** |
|
197
|
|
|
* Callback method to update changed connect products |
|
198
|
|
|
* |
|
199
|
|
|
* @param \Enlight_Event_EventArgs $eventArgs |
|
200
|
|
|
*/ |
|
201
|
|
|
public function onUpdateArticle(\Enlight_Event_EventArgs $eventArgs) |
|
202
|
|
|
{ |
|
203
|
|
|
$entity = $eventArgs->get('entity'); |
|
204
|
|
|
|
|
205
|
|
|
$this->handleChange($entity); |
|
206
|
|
|
} |
|
207
|
|
|
|
|
208
|
|
|
/** |
|
209
|
|
|
* Generate changes for Article or Detail if necessary |
|
210
|
|
|
* |
|
211
|
|
|
* @param \Shopware\Models\Article\Article | \Shopware\Models\Article\Detail $entity |
|
212
|
|
|
*/ |
|
213
|
|
|
public function handleChange($entity) |
|
214
|
|
|
{ |
|
215
|
|
|
if (!$entity instanceof \Shopware\Models\Article\Article |
|
|
|
|
|
|
216
|
|
|
&& !$entity instanceof \Shopware\Models\Article\Detail |
|
|
|
|
|
|
217
|
|
|
) { |
|
218
|
|
|
return; |
|
219
|
|
|
} |
|
220
|
|
|
|
|
221
|
|
|
$id = $entity->getId(); |
|
222
|
|
|
$className = get_class($entity); |
|
223
|
|
|
$model = $this->manager->getRepository($className)->find($id); |
|
224
|
|
|
// Check if we have a valid model |
|
225
|
|
|
if (!$model) { |
|
226
|
|
|
return; |
|
227
|
|
|
} |
|
228
|
|
|
|
|
229
|
|
|
// Check if entity is a connect product |
|
230
|
|
|
$attribute = $this->getHelper()->getConnectAttributeByModel($model); |
|
231
|
|
|
if (!$attribute) { |
|
232
|
|
|
return; |
|
233
|
|
|
} |
|
234
|
|
|
|
|
235
|
|
|
// if article is not exported to Connect |
|
236
|
|
|
// or at least one article detail from same article is not exported |
|
237
|
|
|
// don't need to generate changes |
|
238
|
|
|
if (!$this->getHelper()->isProductExported($attribute) || !empty($attribute->getShopId())) { |
|
239
|
|
|
if (!$this->getHelper()->hasExportedVariants($attribute)) { |
|
240
|
|
|
return; |
|
241
|
|
|
} |
|
242
|
|
|
} |
|
243
|
|
|
|
|
244
|
|
|
if (!$this->hasPriceType()) { |
|
245
|
|
|
return; |
|
246
|
|
|
} |
|
247
|
|
|
|
|
248
|
|
|
$forceExport = false; |
|
249
|
|
|
if ($entity instanceof \Shopware\Models\Article\Detail) { |
|
|
|
|
|
|
250
|
|
|
$changeSet = $this->manager->getUnitOfWork()->getEntityChangeSet($entity); |
|
251
|
|
|
// if detail number has been changed |
|
252
|
|
|
// sc plugin must generate & sync the change immediately |
|
253
|
|
|
if (array_key_exists('number', $changeSet)) { |
|
254
|
|
|
$forceExport = true; |
|
255
|
|
|
} |
|
256
|
|
|
} |
|
257
|
|
|
|
|
258
|
|
|
// Mark the product for connect update |
|
259
|
|
|
try { |
|
260
|
|
|
if ($model instanceof \Shopware\Models\Article\Detail) { |
|
|
|
|
|
|
261
|
|
|
$this->generateChangesForDetail($model, $forceExport); |
|
262
|
|
|
} elseif ($model instanceof \Shopware\Models\Article\Article) { |
|
|
|
|
|
|
263
|
|
|
$this->generateChangesForArticle($model, $forceExport); |
|
264
|
|
|
} |
|
265
|
|
|
} catch (\Exception $e) { |
|
266
|
|
|
// If the update fails due to missing requirements |
|
267
|
|
|
// (e.g. category assignment), continue without error |
|
268
|
|
|
} |
|
269
|
|
|
} |
|
270
|
|
|
|
|
271
|
|
|
/** |
|
272
|
|
|
* Callback method to insert new article details in Connect system |
|
273
|
|
|
* Used when article is exported and after that variants are generated |
|
274
|
|
|
* |
|
275
|
|
|
* @param \Enlight_Event_EventArgs $eventArgs |
|
276
|
|
|
*/ |
|
277
|
|
|
public function onPersistDetail(\Enlight_Event_EventArgs $eventArgs) |
|
278
|
|
|
{ |
|
279
|
|
|
/** @var \Shopware\Models\Article\Detail $detail */ |
|
280
|
|
|
$detail = $eventArgs->get('entity'); |
|
281
|
|
|
|
|
282
|
|
|
/** @var \Shopware\Models\Article\Article $article */ |
|
283
|
|
|
$article = $detail->getArticle(); |
|
284
|
|
|
$articleAttribute = $this->getHelper()->getConnectAttributeByModel($article); |
|
285
|
|
|
if (!$articleAttribute) { |
|
286
|
|
|
return; |
|
287
|
|
|
} |
|
288
|
|
|
|
|
289
|
|
|
// if article is not exported to Connect |
|
290
|
|
|
// don't need to generate changes |
|
291
|
|
|
if (!$this->getHelper()->isProductExported($articleAttribute) || !empty($articleAttribute->getShopId())) { |
|
292
|
|
|
return; |
|
293
|
|
|
} |
|
294
|
|
|
|
|
295
|
|
|
if (!$this->hasPriceType()) { |
|
296
|
|
|
return; |
|
297
|
|
|
} |
|
298
|
|
|
|
|
299
|
|
|
// Mark the article detail for connect export |
|
300
|
|
|
try { |
|
301
|
|
|
$this->getHelper()->getOrCreateConnectAttributeByModel($detail); |
|
302
|
|
|
$forceExport = false; |
|
303
|
|
|
$changeSet = $eventArgs->get('entityManager')->getUnitOfWork()->getEntityChangeSet($detail); |
|
304
|
|
|
// if detail number has been changed |
|
305
|
|
|
// sc plugin must generate & sync the change immediately |
|
306
|
|
|
if (array_key_exists('number', $changeSet)) { |
|
307
|
|
|
$forceExport = true; |
|
308
|
|
|
} |
|
309
|
|
|
|
|
310
|
|
|
$this->generateChangesForDetail($detail, $forceExport); |
|
311
|
|
|
} catch (\Exception $e) { |
|
312
|
|
|
// If the update fails due to missing requirements |
|
313
|
|
|
// (e.g. category assignment), continue without error |
|
314
|
|
|
} |
|
315
|
|
|
} |
|
316
|
|
|
|
|
317
|
|
|
/** |
|
318
|
|
|
* Callback function to shop from export languages |
|
319
|
|
|
* |
|
320
|
|
|
* @param \Enlight_Event_EventArgs $eventArgs |
|
321
|
|
|
*/ |
|
322
|
|
|
public function onDeleteShop(\Enlight_Event_EventArgs $eventArgs) |
|
323
|
|
|
{ |
|
324
|
|
|
/** @var \Shopware\Models\Shop\Shop $shop */ |
|
325
|
|
|
$shop = $eventArgs->get('entity'); |
|
326
|
|
|
$shopId = $shop->getId(); |
|
327
|
|
|
$exportLanguages = $this->getConnectConfig()->getConfig('exportLanguages'); |
|
|
|
|
|
|
328
|
|
|
$exportLanguages = $exportLanguages ?: []; |
|
329
|
|
|
|
|
330
|
|
|
if (!in_array($shopId, $exportLanguages)) { |
|
331
|
|
|
return; |
|
332
|
|
|
} |
|
333
|
|
|
|
|
334
|
|
|
$exportLanguages = array_splice($exportLanguages, array_search($shopId, $exportLanguages), 1); |
|
335
|
|
|
$this->getConnectConfig()->setConfig('exportLanguages', $exportLanguages, null, 'export'); |
|
336
|
|
|
} |
|
337
|
|
|
|
|
338
|
|
|
/** |
|
339
|
|
|
* @param \Shopware\Models\Article\Detail $detail |
|
340
|
|
|
* @param bool $force |
|
341
|
|
|
*/ |
|
342
|
|
View Code Duplication |
private function generateChangesForDetail(\Shopware\Models\Article\Detail $detail, $force = false) |
|
|
|
|
|
|
343
|
|
|
{ |
|
344
|
|
|
$attribute = $this->getHelper()->getConnectAttributeByModel($detail); |
|
345
|
|
|
if (!$detail->getActive() && $this->getConnectConfig()->getConfig('excludeInactiveProducts')) { |
|
346
|
|
|
$this->getConnectExport()->syncDeleteDetail($detail); |
|
347
|
|
|
|
|
348
|
|
|
return; |
|
349
|
|
|
} |
|
350
|
|
|
|
|
351
|
|
|
if ($this->autoUpdateProducts == 1 || $force === true) { |
|
352
|
|
|
$this->getConnectExport()->export( |
|
353
|
|
|
[$attribute->getSourceId()], null, true |
|
|
|
|
|
|
354
|
|
|
); |
|
355
|
|
|
} elseif ($this->autoUpdateProducts == 2) { |
|
356
|
|
|
$this->manager->getConnection()->update( |
|
357
|
|
|
's_plugin_connect_items', |
|
358
|
|
|
['cron_update' => 1], |
|
359
|
|
|
['article_detail_id' => $detail->getId()] |
|
360
|
|
|
); |
|
361
|
|
|
} |
|
362
|
|
|
} |
|
363
|
|
|
|
|
364
|
|
View Code Duplication |
private function generateChangesForArticle(\Shopware\Models\Article\Article $article, $force = false) |
|
|
|
|
|
|
365
|
|
|
{ |
|
366
|
|
|
if (!$article->getActive() && $this->getConnectConfig()->getConfig('excludeInactiveProducts')) { |
|
367
|
|
|
$this->getConnectExport()->setDeleteStatusForVariants($article); |
|
368
|
|
|
|
|
369
|
|
|
return; |
|
370
|
|
|
} |
|
371
|
|
|
|
|
372
|
|
|
if ($this->autoUpdateProducts == 1 || $force === true) { |
|
373
|
|
|
$sourceIds = $this->getHelper()->getSourceIdsFromArticleId($article->getId()); |
|
374
|
|
|
|
|
375
|
|
|
$this->getConnectExport()->export($sourceIds, null, true); |
|
|
|
|
|
|
376
|
|
|
} elseif ($this->autoUpdateProducts == 2) { |
|
377
|
|
|
$this->manager->getConnection()->update( |
|
378
|
|
|
's_plugin_connect_items', |
|
379
|
|
|
['cron_update' => 1], |
|
380
|
|
|
['article_id' => $article->getId()] |
|
381
|
|
|
); |
|
382
|
|
|
} |
|
383
|
|
|
} |
|
384
|
|
|
|
|
385
|
|
|
/** |
|
386
|
|
|
* Sends the new order status when supplier change it |
|
387
|
|
|
* |
|
388
|
|
|
* @param Order $order |
|
389
|
|
|
*/ |
|
390
|
|
|
private function updateOrderStatus(Order $order) |
|
391
|
|
|
{ |
|
392
|
|
|
$attribute = $order->getAttribute(); |
|
393
|
|
|
if (!$attribute || !$attribute->getConnectShopId()) { |
|
394
|
|
|
return; |
|
395
|
|
|
} |
|
396
|
|
|
|
|
397
|
|
|
$orderStatusMapper = new Utils\OrderStatusMapper(); |
|
398
|
|
|
$orderStatus = $orderStatusMapper->getOrderStatusStructFromOrder($order); |
|
399
|
|
|
|
|
400
|
|
|
try { |
|
401
|
|
|
$this->getSDK()->updateOrderStatus($orderStatus); |
|
402
|
|
|
} catch (\Exception $e) { |
|
403
|
|
|
// if sn is not available, proceed without exception |
|
404
|
|
|
} |
|
405
|
|
|
} |
|
406
|
|
|
|
|
407
|
|
|
/** |
|
408
|
|
|
* Sends the new payment status when merchant change it |
|
409
|
|
|
* |
|
410
|
|
|
* @param Order $order |
|
411
|
|
|
*/ |
|
412
|
|
|
private function updatePaymentStatus(Order $order) |
|
413
|
|
|
{ |
|
414
|
|
|
$orderUtil = new Utils\ConnectOrderUtil(); |
|
415
|
|
|
if (!$orderUtil->hasLocalOrderConnectProducts($order->getId())) { |
|
416
|
|
|
return; |
|
417
|
|
|
} |
|
418
|
|
|
|
|
419
|
|
|
$paymentStatusMapper = new Utils\OrderPaymentStatusMapper(); |
|
420
|
|
|
$paymentStatus = $paymentStatusMapper->getPaymentStatus($order); |
|
421
|
|
|
|
|
422
|
|
|
$this->generateChangeForPaymentStatus($paymentStatus); |
|
423
|
|
|
} |
|
424
|
|
|
|
|
425
|
|
|
/** |
|
426
|
|
|
* @param PaymentStatus $paymentStatus |
|
427
|
|
|
*/ |
|
428
|
|
|
private function generateChangeForPaymentStatus(PaymentStatus $paymentStatus) |
|
429
|
|
|
{ |
|
430
|
|
|
try { |
|
431
|
|
|
$this->getSDK()->updatePaymentStatus($paymentStatus); |
|
432
|
|
|
} catch (\Exception $e) { |
|
433
|
|
|
// if sn is not available, proceed without exception |
|
434
|
|
|
} |
|
435
|
|
|
} |
|
436
|
|
|
} |
|
437
|
|
|
|
This error could be the result of:
1. Missing dependencies
PHP Analyzer uses your
composer.jsonfile (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects thecomposer.jsonto be in the root folder of your repository.Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the
requireorrequire-devsection?2. Missing use statement
PHP does not complain about undefined classes in
ìnstanceofchecks. For example, the following PHP code will work perfectly fine:If you have not tested against this specific condition, such errors might go unnoticed.