Issues (244)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

Ui/Admin/ManagingProductVariantsContext.php (2 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
/*
4
 * This file is part of the Sylius package.
5
 *
6
 * (c) Paweł Jędrzejewski
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
declare(strict_types=1);
13
14
namespace Sylius\Behat\Context\Ui\Admin;
15
16
use Behat\Behat\Context\Context;
17
use Sylius\Behat\NotificationType;
18
use Sylius\Behat\Page\Admin\ProductVariant\CreatePageInterface;
19
use Sylius\Behat\Page\Admin\ProductVariant\GeneratePageInterface;
20
use Sylius\Behat\Page\Admin\ProductVariant\IndexPageInterface;
21
use Sylius\Behat\Page\Admin\ProductVariant\UpdatePageInterface;
22
use Sylius\Behat\Service\NotificationCheckerInterface;
23
use Sylius\Behat\Service\Resolver\CurrentPageResolverInterface;
24
use Sylius\Behat\Service\SharedStorageInterface;
25
use Sylius\Component\Core\Model\ProductInterface;
26
use Sylius\Component\Core\Model\ProductVariantInterface;
27
use Webmozart\Assert\Assert;
28
29
final class ManagingProductVariantsContext implements Context
30
{
31
    /**
32
     * @var SharedStorageInterface
33
     */
34
    private $sharedStorage;
35
36
    /**
37
     * @var CreatePageInterface
38
     */
39
    private $createPage;
40
41
    /**
42
     * @var IndexPageInterface
43
     */
44
    private $indexPage;
45
46
    /**
47
     * @var UpdatePageInterface
48
     */
49
    private $updatePage;
50
51
    /**
52
     * @var GeneratePageInterface
53
     */
54
    private $generatePage;
55
56
    /**
57
     * @var CurrentPageResolverInterface
58
     */
59
    private $currentPageResolver;
60
61
    /**
62
     * @var NotificationCheckerInterface
63
     */
64
    private $notificationChecker;
65
66
    /**
67
     * @param SharedStorageInterface $sharedStorage
68
     * @param CreatePageInterface $createPage
69
     * @param IndexPageInterface $indexPage
70
     * @param UpdatePageInterface $updatePage
71
     * @param GeneratePageInterface $generatePage
72
     * @param CurrentPageResolverInterface $currentPageResolver
73
     * @param NotificationCheckerInterface $notificationChecker
74
     */
75
    public function __construct(
76
        SharedStorageInterface $sharedStorage,
77
        CreatePageInterface $createPage,
78
        IndexPageInterface $indexPage,
79
        UpdatePageInterface $updatePage,
80
        GeneratePageInterface $generatePage,
81
        CurrentPageResolverInterface $currentPageResolver,
82
        NotificationCheckerInterface $notificationChecker
83
    ) {
84
        $this->sharedStorage = $sharedStorage;
85
        $this->createPage = $createPage;
86
        $this->indexPage = $indexPage;
87
        $this->updatePage = $updatePage;
88
        $this->generatePage = $generatePage;
89
        $this->currentPageResolver = $currentPageResolver;
90
        $this->notificationChecker = $notificationChecker;
91
    }
92
93
    /**
94
     * @Given /^I want to create a new variant of (this product)$/
95
     */
96
    public function iWantToCreateANewProduct(ProductInterface $product)
97
    {
98
        $this->createPage->open(['productId' => $product->getId()]);
99
    }
100
101
    /**
102
     * @When I specify its code as :code
103
     * @When I do not specify its code
104
     */
105
    public function iSpecifyItsCodeAs($code = null)
106
    {
107
        $this->createPage->specifyCode($code);
108
    }
109
110
    /**
111
     * @When I name it :name in :language
112
     */
113
    public function iNameItIn($name, $language)
114
    {
115
        $this->createPage->nameItIn($name, $language);
116
    }
117
118
    /**
119
     * @When I add it
120
     * @When I try to add it
121
     */
122
    public function iAddIt()
123
    {
124
        $this->createPage->create();
125
    }
126
127
    /**
128
     * @When I disable its inventory tracking
129
     */
130
    public function iDisableItsTracking()
131
    {
132
        $this->updatePage->disableTracking();
133
    }
134
135
    /**
136
     * @When I enable its inventory tracking
137
     */
138
    public function iEnableItsTracking()
139
    {
140
        $this->updatePage->enableTracking();
141
    }
142
143
    /**
144
     * @When /^I set its(?:| default) price to "(?:€|£|\$)([^"]+)" for "([^"]+)" channel$/
145
     * @When I do not set its price
146
     */
147
    public function iSetItsPriceTo($price = null, $channelName = null)
148
    {
149
        $this->createPage->specifyPrice($price, $channelName ?? $this->sharedStorage->get('channel'));
150
    }
151
152
    /**
153
     * @When /^I set its original price to "(?:€|£|\$)([^"]+)" for "([^"]+)" channel$/
154
     */
155
    public function iSetItsOriginalPriceTo($originalPrice, $channelName)
156
    {
157
        $this->createPage->specifyOriginalPrice($originalPrice, $channelName);
158
    }
159
160
    /**
161
     * @When I set its height, width, depth and weight to :number
162
     */
163
    public function iSetItsDimensionsTo($value)
164
    {
165
        $this->createPage->specifyHeightWidthDepthAndWeight($value, $value, $value, $value);
166
    }
167
168
    /**
169
     * @When I do not specify its current stock
170
     */
171
    public function iDoNetSetItsCurrentStockTo()
172
    {
173
        $this->createPage->specifyCurrentStock('');
174
    }
175
176
    /**
177
     * @When I choose :calculatorName calculator
178
     */
179
    public function iChooseCalculator($calculatorName)
180
    {
181
        $this->createPage->choosePricingCalculator($calculatorName);
182
    }
183
184
    /**
185
     * @When I set its :optionName option to :optionValue
186
     */
187
    public function iSetItsOptionAs($optionName, $optionValue)
188
    {
189
        $this->createPage->selectOption($optionName, $optionValue);
190
    }
191
192
    /**
193
     * @When I set the position of :name to :position
194
     */
195
    public function iSetThePositionOfTo($name, $position)
196
    {
197
        $this->indexPage->setPosition($name, $position);
198
    }
199
200
    /**
201
     * @When I save my new configuration
202
     */
203
    public function iSaveMyNewConfiguration()
204
    {
205
        $this->indexPage->savePositions();
206
    }
207
208
    /**
209
     * @When I do not want to have shipping required for this product
210
     */
211
    public function iDoNotWantToHaveShippingRequiredForThisProduct()
212
    {
213
        $this->createPage->setShippingRequired(false);
214
    }
215
216
    /**
217
     * @When I check (also) the :productVariantName product variant
218
     */
219
    public function iCheckTheProductVariantName(string $productVariantName): void
220
    {
221
        $this->indexPage->checkResourceOnPage(['name' => $productVariantName]);
222
    }
223
224
    /**
225
     * @When I delete them
226
     */
227
    public function iDeleteThem(): void
228
    {
229
        $this->indexPage->bulkDelete();
230
    }
231
232
    /**
233
     * @Then /^the (variant with code "[^"]+") should be priced at (?:€|£|\$)([^"]+) for channel "([^"]+)"$/
234
     */
235
    public function theVariantWithCodeShouldBePricedAtForChannel(ProductVariantInterface $productVariant, $price, $channelName)
236
    {
237
        $this->updatePage->open(['id' => $productVariant->getId(), 'productId' => $productVariant->getProduct()->getId()]);
238
239
        Assert::same($this->updatePage->getPriceForChannel($channelName), $price);
240
    }
241
242
    /**
243
     * @Then /^the (variant with code "[^"]+") should be named "([^"]+)" in ("([^"]+)" locale)$/
244
     */
245
    public function theVariantWithCodeShouldBeNamedIn(ProductVariantInterface $productVariant, $name, $language)
246
    {
247
        $this->updatePage->open(['id' => $productVariant->getId(), 'productId' => $productVariant->getProduct()->getId()]);
248
249
        Assert::same($this->updatePage->getNameInLanguage($language), $name);
250
    }
251
252
    /**
253
     * @Then /^the (variant with code "[^"]+") should have an original price of (?:€|£|\$)([^"]+) for channel "([^"]+)"$/
254
     */
255
    public function theVariantWithCodeShouldHaveAnOriginalPriceOfForChannel(ProductVariantInterface $productVariant, $originalPrice, $channelName)
256
    {
257
        $this->updatePage->open(['id' => $productVariant->getId(), 'productId' => $productVariant->getProduct()->getId()]);
258
259
        Assert::same(
260
            $this->updatePage->getOriginalPriceForChannel($channelName),
261
            $originalPrice
262
        );
263
    }
264
265
    /**
266
     * @When /^I delete the ("[^"]+" variant of product "[^"]+")$/
267
     * @When /^I try to delete the ("[^"]+" variant of product "[^"]+")$/
268
     */
269
    public function iDeleteTheVariantOfProduct(ProductVariantInterface $productVariant)
270
    {
271
        $this->indexPage->open(['productId' => $productVariant->getProduct()->getId()]);
272
273
        $this->indexPage->deleteResourceOnPage(['code' => $productVariant->getCode()]);
274
    }
275
276
    /**
277
     * @Then I should be notified that this variant is in use and cannot be deleted
278
     */
279
    public function iShouldBeNotifiedOfFailure()
280
    {
281
        $this->notificationChecker->checkNotification(
282
            'Cannot delete, the product variant is in use.',
283
            NotificationType::failure()
284
        );
285
    }
286
287
    /**
288
     * @When /^I want to modify the ("[^"]+" product variant)$/
289
     */
290
    public function iWantToModifyAProduct(ProductVariantInterface $productVariant)
291
    {
292
        $this->updatePage->open(['id' => $productVariant->getId(), 'productId' => $productVariant->getProduct()->getId()]);
293
    }
294
295
    /**
296
     * @Then the code field should be disabled
297
     */
298
    public function theCodeFieldShouldBeDisabled()
299
    {
300
        Assert::true($this->updatePage->isCodeDisabled());
301
    }
302
303
    /**
304
     * @Then I should be notified that :element is required
305
     */
306
    public function iShouldBeNotifiedThatIsRequired($element)
307
    {
308
        $this->assertValidationMessage($element, sprintf('Please enter the %s.', $element));
309
    }
310
311
    /**
312
     * @Then I should be notified that code has to be unique
313
     */
314
    public function iShouldBeNotifiedThatCodeHasToBeUnique()
315
    {
316
        $this->assertValidationMessage('code', 'Product variant code must be unique.');
317
    }
318
319
    /**
320
     * @Then I should be notified that current stock is required
321
     */
322
    public function iShouldBeNotifiedThatOnHandIsRequired()
323
    {
324
        $this->assertValidationMessage('on_hand', 'Please enter on hand.');
325
    }
326
327
    /**
328
     * @Then I should be notified that height, width, depth and weight cannot be lower than 0
329
     */
330
    public function iShouldBeNotifiedThatIsHeightWidthDepthWeightCannotBeLowerThan()
331
    {
332
        $this->assertValidationMessage('height', 'Height cannot be negative.');
333
        $this->assertValidationMessage('width', 'Width cannot be negative.');
334
        $this->assertValidationMessage('depth', 'Depth cannot be negative.');
335
        $this->assertValidationMessage('weight', 'Weight cannot be negative.');
336
    }
337
338
    /**
339
     * @Then I should be notified that price cannot be lower than 0.01
340
     */
341
    public function iShouldBeNotifiedThatPriceCannotBeLowerThen()
342
    {
343
        /** @var CreatePageInterface|UpdatePageInterface $currentPage */
344
        $currentPage = $this->currentPageResolver->getCurrentPageWithForm([$this->createPage, $this->updatePage]);
345
346
        Assert::contains($currentPage->getPricesValidationMessage(), 'Price must be at least 0.01.');
0 ignored issues
show
The method getPricesValidationMessage does only exist in Sylius\Behat\Page\Admin\...ant\CreatePageInterface, but not in Sylius\Behat\Page\Admin\...ant\UpdatePageInterface.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
347
    }
348
349
    /**
350
     * @Then I should be notified that this variant already exists
351
     */
352
    public function iShouldBeNotifiedThatThisVariantAlreadyExists()
353
    {
354
        /** @var CreatePageInterface|UpdatePageInterface $currentPage */
355
        $currentPage = $this->currentPageResolver->getCurrentPageWithForm([$this->createPage, $this->updatePage]);
356
357
        Assert::same($currentPage->getValidationMessageForForm(), 'Variant with this option set already exists.');
0 ignored issues
show
The method getValidationMessageForForm does only exist in Sylius\Behat\Page\Admin\...ant\CreatePageInterface, but not in Sylius\Behat\Page\Admin\...ant\UpdatePageInterface.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
358
    }
359
360
    /**
361
     * @Then /^I should be notified that code is required for the (\d)(?:st|nd|rd|th) variant$/
362
     */
363
    public function iShouldBeNotifiedThatCodeIsRequiredForVariant($position)
364
    {
365
        Assert::same(
366
            $this->generatePage->getValidationMessage('code', $position - 1),
367
            'Please enter the code.'
368
        );
369
    }
370
371
    /**
372
     * @Then /^I should be notified that prices in all channels must be defined for the (\d)(?:st|nd|rd|th) variant$/
373
     */
374
    public function iShouldBeNotifiedThatPricesInAllChannelsMustBeDefinedForTheVariant($position)
375
    {
376
        Assert::same(
377
            $this->generatePage->getPricesValidationMessage($position - 1),
378
            'You must define price for every channel.'
379
        );
380
    }
381
382
    /**
383
     * @Then /^I should be notified that variant code must be unique within this product for the (\d)(?:st|nd|rd|th) variant$/
384
     */
385
    public function iShouldBeNotifiedThatVariantCodeMustBeUniqueWithinThisProductForYheVariant($position)
386
    {
387
        Assert::same(
388
            $this->generatePage->getValidationMessage('code', $position - 1),
389
            'This code must be unique within this product.'
390
        );
391
    }
392
393
    /**
394
     * @Then I should be notified that prices in all channels must be defined
395
     */
396
    public function iShouldBeNotifiedThatPricesInAllChannelsMustBeDefined()
397
    {
398
        Assert::contains(
399
            $this->createPage->getPricesValidationMessage(),
400
            'You must define price for every channel.'
401
        );
402
    }
403
404
    /**
405
     * @When I save my changes
406
     * @When I try to save my changes
407
     */
408
    public function iSaveMyChanges()
409
    {
410
        $this->updatePage->saveChanges();
411
    }
412
413
    /**
414
     * @Then /^inventory of (this variant) should not be tracked$/
415
     */
416
    public function thisProductVariantShouldNotBeTracked(ProductVariantInterface $productVariant)
417
    {
418
        $this->iWantToModifyAProduct($productVariant);
419
420
        Assert::false($this->updatePage->isTracked());
421
    }
422
423
    /**
424
     * @Then /^inventory of (this variant) should be tracked$/
425
     */
426
    public function thisProductVariantShouldBeTracked(ProductVariantInterface $productVariant)
427
    {
428
        $this->iWantToModifyAProduct($productVariant);
429
430
        Assert::true($this->updatePage->isTracked());
431
    }
432
433
    /**
434
     * @When /^I want to generate new variants for (this product)$/
435
     */
436
    public function iWantToGenerateNewVariantsForThisProduct(ProductInterface $product)
437
    {
438
        $this->generatePage->open(['productId' => $product->getId()]);
439
    }
440
441
    /**
442
     * @When I generate it
443
     * @When I try to generate it
444
     */
445
    public function iClickGenerate()
446
    {
447
        $this->generatePage->generate();
448
    }
449
450
    /**
451
     * @When /^I specify that the (\d)(?:st|nd|rd|th) variant is identified by "([^"]+)" code and costs "(?:€|£|\$)([^"]+)" in ("[^"]+") channel$/
452
     */
453
    public function iSpecifyThereAreVariantsIdentifiedByCodeWithCost($nthVariant, $code, $price, $channelName)
454
    {
455
        $this->generatePage->specifyCode($nthVariant - 1, $code);
456
        $this->generatePage->specifyPrice($nthVariant - 1, $price, $channelName);
457
    }
458
459
    /**
460
     * @When /^I specify that the (\d)(?:st|nd|rd|th) variant is identified by "([^"]+)" code$/
461
     */
462
    public function iSpecifyThereAreVariantsIdentifiedByCode($nthVariant, $code)
463
    {
464
        $this->generatePage->specifyCode($nthVariant - 1, $code);
465
    }
466
467
    /**
468
     * @When /^I specify that the (\d)(?:st|nd|rd|th) variant costs "(?:€|£|\$)([^"]+)" in ("[^"]+") channel$/
469
     */
470
    public function iSpecifyThereAreVariantsWithCost($nthVariant, $price, $channelName)
471
    {
472
        $this->generatePage->specifyPrice($nthVariant - 1, $price, $channelName);
473
    }
474
475
    /**
476
     * @When /^I remove (\d)(?:st|nd|rd|th) variant from the list$/
477
     */
478
    public function iRemoveVariantFromTheList($nthVariant)
479
    {
480
        $this->generatePage->removeVariant($nthVariant - 1);
481
    }
482
483
    /**
484
     * @Then I should be notified that it has been successfully generated
485
     */
486
    public function iShouldBeNotifiedThatItHasBeenSuccessfullyGenerated()
487
    {
488
        $this->notificationChecker->checkNotification('Success Product variants have been successfully generated.', NotificationType::success());
489
    }
490
491
    /**
492
     * @When I set its shipping category as :shippingCategoryName
493
     */
494
    public function iSetItsShippingCategoryAs($shippingCategoryName)
495
    {
496
        $this->createPage->selectShippingCategory($shippingCategoryName);
497
    }
498
499
    /**
500
     * @When I do not specify any information about variants
501
     */
502
    public function iDoNotSpecifyAnyInformationAboutVariants()
503
    {
504
        // Intentionally left blank to fulfill context expectation
505
    }
506
507
    /**
508
     * @When I change its quantity of inventory to :amount
509
     */
510
    public function iChangeItsQuantityOfInventoryTo($amount)
511
    {
512
        $this->updatePage->specifyCurrentStock($amount);
513
    }
514
515
    /**
516
     * @Then /^the (variant with code "[^"]+") should not have shipping required$/
517
     */
518
    public function theVariantWithCodeShouldNotHaveShippingRequired(ProductVariantInterface $productVariant)
519
    {
520
        $this->updatePage->open(['productId' => $productVariant->getProduct()->getId(), 'id' => $productVariant->getId()]);
521
522
        Assert::false($this->updatePage->isShippingRequired());
523
    }
524
525
    /**
526
     * @Then I should be notified that on hand quantity must be greater than the number of on hold units
527
     */
528
    public function iShouldBeNotifiedThatOnHandQuantityMustBeGreaterThanTheNumberOfOnHoldUnits()
529
    {
530
        Assert::same(
531
            $this->updatePage->getValidationMessage('on_hand'),
532
            'On hand must be greater than the number of on hold units'
533
        );
534
    }
535
536
    /**
537
     * @param string $element
538
     * @param string $message
539
     */
540
    private function assertValidationMessage($element, $message)
541
    {
542
        /** @var CreatePageInterface|UpdatePageInterface $currentPage */
543
        $currentPage = $this->currentPageResolver->getCurrentPageWithForm([$this->createPage, $this->updatePage]);
544
545
        Assert::same($currentPage->getValidationMessage($element), $message);
546
    }
547
}
548