Completed
Push — master ( 1d849e...3a997f )
by Paweł
09:48
created

UpdateSimpleProductPage   B

Complexity

Total Complexity 54

Size/Duplication

Total Lines 510
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 12

Importance

Changes 0
Metric Value
wmc 54
lcom 1
cbo 12
dl 0
loc 510
rs 7.0642
c 0
b 0
f 0

44 Methods

Rating   Name   Duplication   Size   Complexity  
B associateProducts() 0 26 2
A hasAssociatedProduct() 0 9 1
A removeAssociatedProduct() 0 13 1
A getPricingConfigurationForChannelAndCurrencyCalculator() 0 8 1
A getSlug() 0 6 1
A specifySlugIn() 0 6 1
A activateLanguageTab() 0 11 3
A attachImage() 0 15 2
A nameItIn() 0 12 2
A specifyPrice() 0 4 1
A specifyOriginalPrice() 0 4 1
A addSelectedAttributes() 0 11 1
A removeAttribute() 0 6 1
A getAttributeValue() 0 7 1
A getNumberOfAttributes() 0 4 1
A hasAttribute() 0 4 1
A selectMainTaxon() 0 8 1
A isMainTaxonChosen() 0 6 1
A disableTracking() 0 4 1
A enableTracking() 0 4 1
A isTracked() 0 4 1
A enableSlugModification() 0 7 1
A isImageWithTypeDisplayed() 0 15 2
A changeImageWithType() 0 7 1
A removeImageWithType() 0 7 1
A removeFirstImage() 0 7 1
A modifyFirstImageType() 0 7 1
A countImages() 0 6 1
A isSlugReadonlyIn() 0 7 1
A getPriceForChannel() 0 4 1
A getOriginalPriceForChannel() 0 4 1
A isShippingRequired() 0 4 1
A getCodeElement() 0 4 1
A getElement() 0 8 2
B getDefinedElements() 0 25 1
A openTaxonBookmarks() 0 4 1
A clickTabIfItsNotActive() 0 7 2
A clickTab() 0 5 1
A clickLocaleTabIfItsNotActive() 0 7 2
A getImageElementByType() 0 11 2
A getImageElements() 0 6 1
A getLastImageElement() 0 8 1
A getFirstImageElement() 0 8 1
A setImageType() 0 5 1

How to fix   Complexity   

Complex Class

Complex classes like UpdateSimpleProductPage often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use UpdateSimpleProductPage, and based on these observations, apply Extract Interface, too.

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
namespace Sylius\Behat\Page\Admin\Product;
13
14
use Behat\Mink\Driver\Selenium2Driver;
15
use Behat\Mink\Element\NodeElement;
16
use Sylius\Behat\Behaviour\ChecksCodeImmutability;
17
use Sylius\Behat\Page\Admin\Crud\UpdatePage as BaseUpdatePage;
18
use Sylius\Behat\Service\AutocompleteHelper;
19
use Sylius\Behat\Service\SlugGenerationHelper;
20
use Sylius\Component\Core\Model\ChannelInterface;
21
use Sylius\Component\Core\Model\TaxonInterface;
22
use Sylius\Component\Currency\Model\CurrencyInterface;
23
use Sylius\Component\Product\Model\ProductAssociationTypeInterface;
24
use Webmozart\Assert\Assert;
25
26
/**
27
 * @author Łukasz Chruściel <[email protected]>
28
 * @author Gorka Laucirica <[email protected]>
29
 */
30
class UpdateSimpleProductPage extends BaseUpdatePage implements UpdateSimpleProductPageInterface
31
{
32
    use ChecksCodeImmutability;
33
34
    /**
35
     * {@inheritdoc}
36
     */
37
    public function nameItIn($name, $localeCode)
38
    {
39
        $this->activateLanguageTab($localeCode);
40
        $this->getElement('name', ['%locale%' => $localeCode])->setValue($name);
41
42
        if ($this->getDriver() instanceof Selenium2Driver) {
43
            SlugGenerationHelper::waitForSlugGeneration(
44
                $this->getSession(),
45
                $this->getElement('slug', ['%locale%' => $localeCode])
46
            );
47
        }
48
    }
49
50
    /**
51
     * {@inheritdoc}
52
     */
53
    public function specifyPrice($channelName, $price)
54
    {
55
        $this->getElement('price', ['%channelName%' => $channelName])->setValue($price);
56
    }
57
58
    /**
59
     * {@inheritdoc}
60
     */
61
    public function specifyOriginalPrice($channelName, $originalPrice)
62
    {
63
        $this->getElement('original_price', ['%channelName%' => $channelName])->setValue($originalPrice);
64
    }
65
66
    public function addSelectedAttributes()
67
    {
68
        $this->clickTabIfItsNotActive('attributes');
69
        $this->getDocument()->pressButton('Add attributes');
70
71
        $form = $this->getDocument()->find('css', 'form');
72
73
        $this->getDocument()->waitFor(1, function () use ($form) {
74
            return $form->hasClass('loading');
75
        });
76
    }
77
78
    /**
79
     * {@inheritdoc}
80
     */
81
    public function removeAttribute($attributeName, $localeCode)
82
    {
83
        $this->clickTabIfItsNotActive('attributes');
84
85
        $this->getElement('attribute_delete_button', ['%attributeName%' => $attributeName, '$localeCode%' => $localeCode])->press();
86
    }
87
88
    /**
89
     * {@inheritdoc}
90
     */
91
    public function getAttributeValue($attribute, $localeCode)
92
    {
93
        $this->clickTabIfItsNotActive('attributes');
94
        $this->clickLocaleTabIfItsNotActive($localeCode);
95
96
        return $this->getElement('attribute', ['%attributeName%' => $attribute, '%localeCode%' => $localeCode])->getValue();
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this->getElement...caleCode))->getValue(); (string|boolean|array) is incompatible with the return type declared by the interface Sylius\Behat\Page\Admin\...face::getAttributeValue of type string.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
97
    }
98
99
    /**
100
     * {@inheritdoc}
101
     */
102
    public function getNumberOfAttributes()
103
    {
104
        return count($this->getDocument()->findAll('css', '.attribute'));
105
    }
106
107
    /**
108
     * {@inheritdoc}
109
     */
110
    public function hasAttribute($attributeName)
111
    {
112
        return null !== $this->getDocument()->find('css', sprintf('.attribute .label:contains("%s")', $attributeName));
113
    }
114
115
    /**
116
     * {@inheritdoc}
117
     */
118
    public function selectMainTaxon(TaxonInterface $taxon)
119
    {
120
        $this->openTaxonBookmarks();
121
122
        $mainTaxonElement = $this->getElement('main_taxon')->getParent();
123
124
        AutocompleteHelper::chooseValue($this->getSession(), $mainTaxonElement, $taxon->getName());
0 ignored issues
show
Bug introduced by
It seems like $mainTaxonElement defined by $this->getElement('main_taxon')->getParent() on line 122 can be null; however, Sylius\Behat\Service\Aut...teHelper::chooseValue() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
125
    }
126
127
    /**
128
     * {@inheritdoc}
129
     */
130
    public function isMainTaxonChosen($taxonName)
131
    {
132
        $this->openTaxonBookmarks();
133
134
        return $taxonName === $this->getDocument()->find('css', '.search > .text')->getText();
135
    }
136
137
    public function disableTracking()
138
    {
139
        $this->getElement('tracked')->uncheck();
140
    }
141
142
    public function enableTracking()
143
    {
144
        $this->getElement('tracked')->check();
145
    }
146
147
    /**
148
     * {@inheritdoc}
149
     */
150
    public function isTracked()
151
    {
152
        return $this->getElement('tracked')->isChecked();
153
    }
154
155
    /**
156
     * {@inheritdoc}
157
     */
158
    public function enableSlugModification($locale)
159
    {
160
        SlugGenerationHelper::enableSlugModification(
161
            $this->getSession(),
162
            $this->getElement('toggle_slug_modification_button', ['%locale%' => $locale])
163
        );
164
    }
165
166
    /**
167
     * {@inheritdoc}
168
     */
169
    public function isImageWithTypeDisplayed($type)
170
    {
171
        $imageElement = $this->getImageElementByType($type);
172
173
        if (null === $imageElement) {
174
            return false;
175
        }
176
177
        $imageUrl = $imageElement->find('css', 'img')->getAttribute('src');
178
        $this->getDriver()->visit($imageUrl);
179
        $pageText = $this->getDocument()->getText();
180
        $this->getDriver()->back();
181
182
        return false === stripos($pageText, '404 Not Found');
183
    }
184
185
    /**
186
     * {@inheritdoc}
187
     */
188
    public function attachImage($path, $type = null)
189
    {
190
        $this->clickTabIfItsNotActive('media');
191
192
        $filesPath = $this->getParameter('files_path');
193
194
        $this->getDocument()->clickLink('Add');
195
196
        $imageForm = $this->getLastImageElement();
197
        if (null !== $type) {
198
            $imageForm->fillField('Type', $type);
199
        }
200
201
        $imageForm->find('css', 'input[type="file"]')->attachFile($filesPath.$path);
202
    }
203
204
    /**
205
     * {@inheritdoc}
206
     */
207
    public function changeImageWithType($type, $path)
208
    {
209
        $filesPath = $this->getParameter('files_path');
210
211
        $imageForm = $this->getImageElementByType($type);
212
        $imageForm->find('css', 'input[type="file"]')->attachFile($filesPath.$path);
213
    }
214
215
    /**
216
     * {@inheritdoc}
217
     */
218
    public function removeImageWithType($type)
219
    {
220
        $this->clickTabIfItsNotActive('media');
221
222
        $imageElement = $this->getImageElementByType($type);
223
        $imageElement->clickLink('Delete');
224
    }
225
226
    public function removeFirstImage()
227
    {
228
        $this->clickTabIfItsNotActive('media');
229
230
        $imageElement = $this->getFirstImageElement();
231
        $imageElement->clickLink('Delete');
232
    }
233
234
    /**
235
     * {@inheritdoc}
236
     */
237
    public function modifyFirstImageType($type)
238
    {
239
        $this->clickTabIfItsNotActive('media');
240
241
        $firstImage = $this->getFirstImageElement();
242
        $this->setImageType($firstImage, $type);
243
    }
244
245
    /**
246
     * {@inheritdoc}
247
     */
248
    public function countImages()
249
    {
250
        $imageElements = $this->getImageElements();
251
252
        return count($imageElements);
253
    }
254
255
    /**
256
     * {@inheritdoc}
257
     */
258
    public function isSlugReadonlyIn($locale)
259
    {
260
        return SlugGenerationHelper::isSlugReadonly(
261
            $this->getSession(),
262
            $this->getElement('slug', ['%locale%' => $locale])
263
        );
264
    }
265
266
    /**
267
     * {@inheritdoc}
268
     */
269
    public function associateProducts(ProductAssociationTypeInterface $productAssociationType, array $productsNames)
270
    {
271
        $this->clickTab('associations');
272
273
        Assert::isInstanceOf($this->getDriver(), Selenium2Driver::class);
274
275
        $dropdown = $this->getElement('association_dropdown', [
276
            '%association%' => $productAssociationType->getName()
277
        ]);
278
        $dropdown->click();
279
280
        foreach ($productsNames as $productName) {
281
            $dropdown->waitFor(5, function () use ($productName, $productAssociationType) {
282
                return $this->hasElement('association_dropdown_item', [
283
                    '%association%' => $productAssociationType->getName(),
284
                    '%item%' => $productName,
285
                ]);
286
            });
287
288
            $item = $this->getElement('association_dropdown_item', [
289
                '%association%' => $productAssociationType->getName(),
290
                '%item%' => $productName,
291
            ]);
292
            $item->click();
293
        }
294
    }
295
296
    /**
297
     * {@inheritdoc}
298
     */
299
    public function hasAssociatedProduct($productName, ProductAssociationTypeInterface $productAssociationType)
300
    {
301
        $this->clickTabIfItsNotActive('associations');
302
303
        return $this->hasElement('association_dropdown_item', [
304
            '%association%' => $productAssociationType->getName(),
305
            '%item%' => $productName,
306
        ]);
307
    }
308
309
    /**
310
     * {@inheritdoc}
311
     */
312
    public function removeAssociatedProduct($productName, ProductAssociationTypeInterface $productAssociationType)
313
    {
314
        $this->clickTabIfItsNotActive('associations');
315
316
        $item = $this->getElement('association_dropdown_item_selected', [
317
            '%association%' => $productAssociationType->getName(),
318
            '%item%' => $productName,
319
        ]);
320
321
        $deleteIcon = $item->find('css', 'i.delete');
322
        Assert::notNull($deleteIcon);
323
        $deleteIcon->click();
324
    }
325
326
    /**
327
     * {@inheritdoc}
328
     */
329
    public function getPricingConfigurationForChannelAndCurrencyCalculator(ChannelInterface $channel, CurrencyInterface $currency)
330
    {
331
        $priceConfigurationElement = $this->getElement('pricing_configuration');
332
        $priceElement = $priceConfigurationElement
333
            ->find('css', sprintf('label:contains("%s %s")', $channel->getCode(), $currency->getCode()))->getParent();
334
335
        return $priceElement->find('css', 'input')->getValue();
336
    }
337
338
    /**
339
     * {@inheritdoc}
340
     */
341
    public function getSlug($locale)
342
    {
343
        $this->activateLanguageTab($locale);
344
345
        return $this->getElement('slug', ['%locale%' => $locale])->getValue();
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this->getElement... $locale))->getValue(); (string|boolean|array) is incompatible with the return type declared by the interface Sylius\Behat\Page\Admin\...tPageInterface::getSlug of type string.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
346
    }
347
348
    /**
349
     * {@inheritdoc}
350
     */
351
    public function specifySlugIn($slug, $locale)
352
    {
353
        $this->activateLanguageTab($locale);
354
355
        $this->getElement('slug', ['%locale%' => $locale])->setValue($slug);
356
    }
357
358
    /**
359
     * {@inheritdoc}
360
     */
361
    public function activateLanguageTab($locale)
362
    {
363
        if (!$this->getDriver() instanceof Selenium2Driver) {
364
            return;
365
        }
366
367
        $languageTabTitle = $this->getElement('language_tab', ['%locale%' => $locale]);
368
        if (!$languageTabTitle->hasClass('active')) {
369
            $languageTabTitle->click();
370
        }
371
    }
372
373
    public function getPriceForChannel($channelName)
374
    {
375
        return $this->getElement('price', ['%channelName%' => $channelName])->getValue();
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this->getElement...nnelName))->getValue(); (string|boolean|array) is incompatible with the return type declared by the interface Sylius\Behat\Page\Admin\...ace::getPriceForChannel of type string.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
376
    }
377
378
    /**
379
     * {@inheritdoc}
380
     */
381
    public function getOriginalPriceForChannel($channelName)
382
    {
383
        return $this->getElement('original_price', ['%channelName%' => $channelName])->getValue();
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this->getElement...nnelName))->getValue(); (string|boolean|array) is incompatible with the return type declared by the interface Sylius\Behat\Page\Admin\...OriginalPriceForChannel of type string.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
384
    }
385
386
    /**
387
     * {@inheritdoc}
388
     */
389
    public function isShippingRequired()
390
    {
391
        return $this->getElement('shipping_required')->isChecked();
392
    }
393
394
    /**
395
     * {@inheritdoc}
396
     */
397
    protected function getCodeElement()
398
    {
399
        return $this->getElement('code');
400
    }
401
402
    /**
403
     * {@inheritdoc}
404
     */
405
    protected function getElement($name, array $parameters = [])
406
    {
407
        if (!isset($parameters['%locale%'])) {
408
            $parameters['%locale%'] = 'en_US';
409
        }
410
411
        return parent::getElement($name, $parameters);
412
    }
413
414
    /**
415
     * {@inheritdoc}
416
     */
417
    protected function getDefinedElements()
418
    {
419
        return array_merge(parent::getDefinedElements(), [
420
            'association_dropdown' => '.field > label:contains("%association%") ~ .product-select',
421
            'association_dropdown_item' => '.field > label:contains("%association%") ~ .product-select > div.menu > div.item:contains("%item%")',
422
            'association_dropdown_item_selected' => '.field > label:contains("%association%") ~ .product-select > a.label:contains("%item%")',
423
            'attribute' => '.tab[data-tab="%localeCode%"] .attribute .label:contains("%attributeName%") ~ input',
424
            'attribute_delete_button' => '.tab[data-tab="%localeCode%"] .attribute .label:contains("%attributeName%") ~ button',
425
            'code' => '#sylius_product_code',
426
            'images' => '#sylius_product_images',
427
            'language_tab' => '[data-locale="%locale%"] .title',
428
            'locale_tab' => '#attributesContainer .menu [data-tab="%localeCode%"]',
429
            'name' => '#sylius_product_translations_%locale%_name',
430
            'original_price' => '#sylius_product_variant_channelPricings > .field:contains("%channelName%") input[name$="[originalPrice]"]',
431
            'price' => '#sylius_product_variant_channelPricings > .field:contains("%channelName%") input[name$="[price]"]',
432
            'pricing_configuration' => '#sylius_calculator_container',
433
            'main_taxon' => '#sylius_product_mainTaxon',
434
            'shipping_required' => '#sylius_product_variant_shippingRequired',
435
            'slug' => '#sylius_product_translations_%locale%_slug',
436
            'tab' => '.menu [data-tab="%name%"]',
437
            'taxonomy' => 'a[data-tab="taxonomy"]',
438
            'tracked' => '#sylius_product_variant_tracked',
439
            'toggle_slug_modification_button' => '[data-locale="%locale%"] .toggle-product-slug-modification',
440
        ]);
441
    }
442
443
    private function openTaxonBookmarks()
444
    {
445
        $this->getElement('taxonomy')->click();
446
    }
447
448
    /**
449
     * @param string $tabName
450
     */
451
    private function clickTabIfItsNotActive($tabName)
452
    {
453
        $attributesTab = $this->getElement('tab', ['%name%' => $tabName]);
454
        if (!$attributesTab->hasClass('active')) {
455
            $attributesTab->click();
456
        }
457
    }
458
459
    /**
460
     * @param string $tabName
461
     */
462
    private function clickTab($tabName)
463
    {
464
        $attributesTab = $this->getElement('tab', ['%name%' => $tabName]);
465
        $attributesTab->click();
466
    }
467
468
    /**
469
     * @param string $localeCode
470
     */
471
    private function clickLocaleTabIfItsNotActive($localeCode)
472
    {
473
        $localeTab = $this->getElement('locale_tab', ['%localeCode%' => $localeCode]);
474
        if (!$localeTab->hasClass('active')) {
475
            $localeTab->click();
476
        }
477
    }
478
479
    /**
480
     * @param string $type
481
     *
482
     * @return NodeElement
483
     */
484
    private function getImageElementByType($type)
485
    {
486
        $images = $this->getElement('images');
487
        $typeInput = $images->find('css', 'input[value="'.$type.'"]');
488
489
        if (null === $typeInput) {
490
            return null;
491
        }
492
493
        return $typeInput->getParent()->getParent()->getParent();
494
    }
495
496
    /**
497
     * @return NodeElement[]
498
     */
499
    private function getImageElements()
500
    {
501
        $images = $this->getElement('images');
502
503
        return $images->findAll('css', 'div[data-form-collection="item"]');
504
    }
505
506
    /**
507
     * @return NodeElement
508
     */
509
    private function getLastImageElement()
510
    {
511
        $imageElements = $this->getImageElements();
512
513
        Assert::notEmpty($imageElements);
514
515
        return end($imageElements);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The expression end($imageElements); of type Behat\Mink\Element\NodeElement|false adds false to the return on line 515 which is incompatible with the return type documented by Sylius\Behat\Page\Admin\...ge::getLastImageElement of type Behat\Mink\Element\NodeElement. It seems like you forgot to handle an error condition.
Loading history...
516
    }
517
518
    /**
519
     * @return NodeElement
520
     */
521
    private function getFirstImageElement()
522
    {
523
        $imageElements = $this->getImageElements();
524
525
        Assert::notEmpty($imageElements);
526
527
        return reset($imageElements);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The expression reset($imageElements); of type Behat\Mink\Element\NodeElement|false adds false to the return on line 527 which is incompatible with the return type documented by Sylius\Behat\Page\Admin\...e::getFirstImageElement of type Behat\Mink\Element\NodeElement. It seems like you forgot to handle an error condition.
Loading history...
528
    }
529
530
    /**
531
     * @param NodeElement $imageElement
532
     * @param string $type
533
     */
534
    private function setImageType(NodeElement $imageElement, $type)
535
    {
536
        $typeField = $imageElement->findField('Type');
537
        $typeField->setValue($type);
538
    }
539
}
540