Completed
Push — pull-request/8600 ( 367a7c )
by Kamil
56:28 queued 34:06
created

UpdatePage   B

Complexity

Total Complexity 41

Size/Duplication

Total Lines 330
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 10

Importance

Changes 0
Metric Value
wmc 41
lcom 1
cbo 10
dl 0
loc 330
rs 8.2769
c 0
b 0
f 0

27 Methods

Rating   Name   Duplication   Size   Complexity  
A chooseParent() 0 4 1
A describeItAs() 0 4 1
A nameIt() 0 12 2
A specifySlug() 0 4 1
A attachImage() 0 13 2
A isImageWithTypeDisplayed() 0 15 4
A isSlugReadonly() 0 7 1
A removeImageWithType() 0 10 2
A removeFirstImage() 0 15 3
A enableSlugModification() 0 7 1
A countImages() 0 6 1
A changeImageWithType() 0 7 1
A modifyFirstImageType() 0 7 1
A getParent() 0 4 1
A getSlug() 0 4 1
A getValidationMessageForImage() 0 11 2
A getValidationMessageForImageAtPlace() 0 11 2
A activateLanguageTab() 0 15 3
A getElement() 0 8 2
A getCodeElement() 0 4 1
A getDefinedElements() 0 13 1
A getLastImageElement() 0 8 1
A getFirstImageElement() 0 8 1
A getImageElements() 0 6 1
A getImageElementByType() 0 11 2
A provideImageUrlForType() 0 4 1
A saveImageUrlForType() 0 4 1

How to fix   Complexity   

Complex Class

Complex classes like UpdatePage 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 UpdatePage, 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
declare(strict_types=1);
13
14
namespace Sylius\Behat\Page\Admin\Taxon;
15
16
use Behat\Mink\Driver\Selenium2Driver;
17
use Behat\Mink\Element\NodeElement;
18
use Behat\Mink\Exception\ElementNotFoundException;
19
use Sylius\Behat\Behaviour\ChecksCodeImmutability;
20
use Sylius\Behat\Page\Admin\Crud\UpdatePage as BaseUpdatePage;
21
use Sylius\Behat\Service\AutocompleteHelper;
22
use Sylius\Behat\Service\SlugGenerationHelper;
23
use Sylius\Component\Core\Model\TaxonInterface;
24
use Webmozart\Assert\Assert;
25
26
/**
27
 * @author Arkadiusz Krakowiak <[email protected]>
28
 */
29
class UpdatePage extends BaseUpdatePage implements UpdatePageInterface
30
{
31
    use ChecksCodeImmutability;
32
33
    /** @var array */
34
    private $imageUrls = [];
35
36
    /**
37
     * {@inheritdoc}
38
     */
39
    public function chooseParent(TaxonInterface $taxon)
40
    {
41
        AutocompleteHelper::chooseValue($this->getSession(), $this->getElement('parent')->getParent(), $taxon->getName());
0 ignored issues
show
Bug introduced by
It seems like $this->getElement('parent')->getParent() can be null; however, 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...
42
    }
43
44
    /**
45
     * {@inheritdoc}
46
     */
47
    public function describeItAs($description, $languageCode)
48
    {
49
        $this->getDocument()->fillField(sprintf('sylius_taxon_translations_%s_description', $languageCode), $description);
50
    }
51
52
    /**
53
     * {@inheritdoc}
54
     */
55
    public function nameIt($name, $languageCode)
56
    {
57
        $this->activateLanguageTab($languageCode);
58
        $this->getDocument()->fillField(sprintf('sylius_taxon_translations_%s_name', $languageCode), $name);
59
60
        if ($this->getDriver() instanceof Selenium2Driver) {
61
            SlugGenerationHelper::waitForSlugGeneration(
62
                $this->getSession(),
63
                $this->getElement('slug', ['%language%' => $languageCode])
64
            );
65
        }
66
    }
67
68
    /**
69
     * {@inheritdoc}
70
     */
71
    public function specifySlug($slug, $languageCode)
72
    {
73
        $this->getDocument()->fillField(sprintf('sylius_taxon_translations_%s_slug', $languageCode), $slug);
74
    }
75
76
    /**
77
     * {@inheritdoc}
78
     */
79
    public function attachImage($path, $type = null)
80
    {
81
        $filesPath = $this->getParameter('files_path');
82
83
        $this->getDocument()->find('css', '[data-form-collection="add"]')->click();
84
85
        $imageForm = $this->getLastImageElement();
86
        if (null !== $type) {
87
            $imageForm->fillField('Type', $type);
88
        }
89
90
        $imageForm->find('css', 'input[type="file"]')->attachFile($filesPath.$path);
91
    }
92
93
    /**
94
     * {@inheritdoc}
95
     */
96
    public function isImageWithTypeDisplayed($type)
97
    {
98
        $imageElement = $this->getImageElementByType($type);
99
100
        $imageUrl = $imageElement ? $imageElement->find('css', 'img')->getAttribute('src') : $this->provideImageUrlForType($type);
101
        if (null === $imageElement && null === $imageUrl) {
102
            return false;
103
        }
104
105
        $this->getDriver()->visit($imageUrl);
106
        $pageText = $this->getDocument()->getText();
107
        $this->getDriver()->back();
108
109
        return false === stripos($pageText, '404 Not Found');
110
    }
111
112
    /**
113
     * {@inheritdoc}
114
     */
115
    public function isSlugReadonly($languageCode = 'en_US')
116
    {
117
        return SlugGenerationHelper::isSlugReadonly(
118
            $this->getSession(),
119
            $this->getElement('slug', ['%language%' => $languageCode])
120
        );
121
    }
122
123
    /**
124
     * {@inheritdoc}
125
     */
126
    public function removeImageWithType($type)
127
    {
128
        $imageElement = $this->getImageElementByType($type);
129
        $imageSourceElement = $imageElement->find('css', 'img');
130
        if (null !== $imageSourceElement) {
131
            $this->saveImageUrlForType($type, $imageSourceElement->getAttribute('src'));
132
        }
133
134
        $imageElement->clickLink('Delete');
135
    }
136
137
    public function removeFirstImage()
138
    {
139
        $imageElement = $this->getFirstImageElement();
140
        $imageTypeElement = $imageElement->find('css', 'input[type=text]');
141
        $imageSourceElement = $imageElement->find('css', 'img');
142
143
        if (null !== $imageTypeElement && null !== $imageSourceElement) {
144
            $this->saveImageUrlForType(
145
                $imageTypeElement->getValue(),
146
                $imageSourceElement->getAttribute('src')
147
            );
148
        }
149
150
        $imageElement->clickLink('Delete');
151
    }
152
153
    /**
154
     * {@inheritdoc}
155
     */
156
    public function enableSlugModification($languageCode = 'en_US')
157
    {
158
        SlugGenerationHelper::enableSlugModification(
159
            $this->getSession(),
160
            $this->getElement('toggle_taxon_slug_modification_button', ['%locale%' => $languageCode])
161
        );
162
    }
163
164
    /**
165
     * {@inheritdoc}
166
     */
167
    public function countImages()
168
    {
169
        $imageElements = $this->getImageElements();
170
171
        return count($imageElements);
172
    }
173
174
    /**
175
     * {@inheritdoc}
176
     */
177
    public function changeImageWithType($type, $path)
178
    {
179
        $filesPath = $this->getParameter('files_path');
180
181
        $imageForm = $this->getImageElementByType($type);
182
        $imageForm->find('css', 'input[type="file"]')->attachFile($filesPath.$path);
183
    }
184
185
    /**
186
     * {@inheritdoc}
187
     */
188
    public function modifyFirstImageType($type)
189
    {
190
        $firstImage = $this->getFirstImageElement();
191
192
        $typeField = $firstImage->findField('Type');
193
        $typeField->setValue($type);
194
    }
195
196
    /**
197
     * {@inheritdoc}
198
     */
199
    public function getParent()
200
    {
201
        return $this->getElement('parent')->getValue();
202
    }
203
204
    /**
205
     * {@inheritdoc}
206
     */
207
    public function getSlug($languageCode = 'en_US')
208
    {
209
        return $this->getElement('slug', ['%language%' => $languageCode])->getValue();
210
    }
211
212
    /**
213
     * {@inheritdoc}
214
     */
215
    public function getValidationMessageForImage()
216
    {
217
        $lastImageElement = $this->getLastImageElement();
218
219
        $foundElement = $lastImageElement->find('css', '.sylius-validation-error');
220
        if (null === $foundElement) {
221
            throw new ElementNotFoundException($this->getSession(), 'Tag', 'css', '.sylius-validation-error');
222
        }
223
224
        return $foundElement->getText();
225
    }
226
227
    /**
228
     * {@inheritdoc}
229
     */
230
    public function getValidationMessageForImageAtPlace($place)
231
    {
232
        $images = $this->getImageElements();
233
234
        $foundElement = $images[$place]->find('css', '.sylius-validation-error');
235
        if (null === $foundElement) {
236
            throw new ElementNotFoundException($this->getSession(), 'Tag', 'css', '.sylius-validation-error');
237
        }
238
239
        return $foundElement->getText();
240
    }
241
242
    /**
243
     * {@inheritdoc}
244
     */
245
    public function activateLanguageTab($locale)
246
    {
247
        if (!$this->getDriver() instanceof Selenium2Driver) {
248
            return;
249
        }
250
251
        $languageTabTitle = $this->getElement('language_tab', ['%locale%' => $locale]);
252
        if (!$languageTabTitle->hasClass('active')) {
253
            $languageTabTitle->click();
254
        }
255
256
        $this->getDocument()->waitFor(10, function () use ($languageTabTitle) {
257
            return $languageTabTitle->hasClass('active');
258
        });
259
    }
260
261
    /**
262
     * {@inheritdoc}
263
     */
264
    protected function getElement($name, array $parameters = [])
265
    {
266
        if (!isset($parameters['%language%'])) {
267
            $parameters['%language%'] = 'en_US';
268
        }
269
270
        return parent::getElement($name, $parameters);
271
    }
272
273
    /**
274
     * @return NodeElement
275
     */
276
    protected function getCodeElement()
277
    {
278
        return $this->getElement('code');
279
    }
280
281
    /**
282
     * {@inheritdoc}
283
     */
284
    protected function getDefinedElements()
285
    {
286
        return array_merge(parent::getDefinedElements(), [
287
            'code' => '#sylius_taxon_code',
288
            'description' => '#sylius_taxon_translations_en_US_description',
289
            'images' => '#sylius_taxon_images',
290
            'language_tab' => '[data-locale="%locale%"] .title',
291
            'name' => '#sylius_taxon_translations_en_US_name',
292
            'parent' => '#sylius_taxon_parent',
293
            'slug' => '#sylius_taxon_translations_%language%_slug',
294
            'toggle_taxon_slug_modification_button' => '[data-locale="%locale%"] .toggle-taxon-slug-modification',
295
        ]);
296
    }
297
298
    /**
299
     * @return NodeElement
300
     */
301
    private function getLastImageElement()
302
    {
303
        $imageElements = $this->getImageElements();
304
305
        Assert::notEmpty($imageElements);
306
307
        return end($imageElements);
308
    }
309
310
    /**
311
     * @return NodeElement
312
     */
313
    private function getFirstImageElement()
314
    {
315
        $imageElements = $this->getImageElements();
316
317
        Assert::notEmpty($imageElements);
318
319
        return reset($imageElements);
320
    }
321
322
    /**
323
     * @return NodeElement[]
324
     */
325
    private function getImageElements()
326
    {
327
        $images = $this->getElement('images');
328
329
        return $images->findAll('css', 'div[data-form-collection="item"]');
330
    }
331
332
    /**
333
     * @param string $type
334
     *
335
     * @return NodeElement
336
     */
337
    private function getImageElementByType($type)
338
    {
339
        $images = $this->getElement('images');
340
        $typeInput = $images->find('css', 'input[value="'.$type.'"]');
341
342
        if (null === $typeInput) {
343
            return null;
344
        }
345
346
        return $typeInput->getParent()->getParent()->getParent();
347
    }
348
349
    private function provideImageUrlForType(string $type): ?string
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
350
    {
351
        return $this->imageUrls[$type] ?? null;
352
    }
353
354
    private function saveImageUrlForType(string $type, string $imageUrl): void
355
    {
356
        $this->imageUrls[$type] = $imageUrl;
357
    }
358
}
359