Completed
Push — master ( 59db0f...abafe8 )
by Kamil
18:55
created

MetadataContext::getFormWithFields()   B

Complexity

Conditions 5
Paths 7

Size

Total Lines 20
Code Lines 10

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 20
rs 8.8571
cc 5
eloc 10
nc 7
nop 2
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\Bundle\CoreBundle\Behat;
13
14
use Behat\Gherkin\Node\TableNode;
15
use Behat\Mink\Element\ElementInterface;
16
use Behat\Mink\Element\NodeElement;
17
use Sylius\Bundle\ResourceBundle\Behat\DefaultContext;
18
use Sylius\Component\Core\Model\ProductInterface;
19
use Sylius\Component\Metadata\Model\Custom\PageMetadata;
20
use Sylius\Component\Metadata\Model\Custom\PageMetadataInterface;
21
use Sylius\Component\Metadata\Model\MetadataContainerInterface;
22
use Sylius\Component\Metadata\Model\Twitter\AppCard;
23
use Sylius\Component\Metadata\Model\Twitter\CardInterface;
24
use Sylius\Component\Metadata\Model\Twitter\PlayerCard;
25
use Sylius\Component\Metadata\Model\Twitter\SummaryCard;
26
use Sylius\Component\Metadata\Model\Twitter\SummaryLargeImageCard;
27
use Symfony\Component\PropertyAccess\PropertyAccessor;
28
29
/**
30
 * @author Kamil Kokot <[email protected]>
31
 */
32
class MetadataContext extends DefaultContext
33
{
34
    /**
35
     * @var PropertyAccessor
36
     */
37
    private $propertyAccessor;
38
39
    /**
40
     * {@inheritdoc}
41
     */
42
    public function __construct($applicationName = null)
43
    {
44
        parent::__construct($applicationName);
45
46
        $this->propertyAccessor = new PropertyAccessor();
47
    }
48
49
    /**
50
     * @When I am customizing metadata
51
     * @When I am customizing metadata with identifier :identifier
52
     */
53
    public function iAmCustomizingMetadata($identifier = 'FooBar')
54
    {
55
        $this->getSession()->visit($this->generateUrl('sylius_backend_metadata_container_customize', ['id' => $identifier]));
56
    }
57
58
    /**
59
     * @Then I should see metadata customization form
60
     */
61
    public function iShouldSeeMetadataCustomizationForm()
62
    {
63
        $this->assertThereIsFormWithFields(
64
            $this->getSession()->getPage(),
65
            ['Title', 'Description', 'Keywords', 'Twitter Card']
66
        );
67
    }
68
69
    /**
70
     * @Then I should see the following metadata:
71
     */
72
    public function iShouldSeeTheFollowingMetadata(TableNode $metadata)
73
    {
74
        /** @var NodeElement $table */
75
        $table = $this->getSession()->getPage()->find('css', '#content > table');
76
77
        /** @var NodeElement $row */
78
        $row = $table->findAll('css', 'tr')[1];
79
80
        /** @var NodeElement[] $columns */
81
        $columns = $row->findAll('css', 'td');
82
83
        $contentIndex = $this->getColumnIndex($table, 'Content');
84
85
        /** @var NodeElement $list */
86
        $list = $columns[$contentIndex];
87
        foreach ($metadata->getRowsHash() as $key => $value) {
88
            $currentElement = $list;
89
            $parts = explode('.', $key);
90
91
            foreach ($parts as $part) {
92
                $currentElement = $currentElement->find('xpath', sprintf('/ul/li[starts-with(normalize-space(.), "%s:")]', $part));
93
            }
94
95
            $exploded = explode(':', $currentElement->getText());
96
            $text = trim(end($exploded));
97
98
            $expectedValue = $value;
99
            if ('<empty>' === $expectedValue) {
100
                $expectedValue = 'empty';
101
            } elseif (false !== strpos($expectedValue, ',')) {
102
                $expectedValue = str_replace([', ', ','], [' ', ' '], $expectedValue);
103
            }
104
105
            if ($text !== $expectedValue) {
106
                throw new \Exception(sprintf(
107
                    'Expected "%s", got "%s" (item: "%s", original value: "%s")',
108
                    $expectedValue,
109
                    $text,
110
                    $key,
111
                    $value
112
                ));
113
            }
114
        }
115
    }
116
117
    /**
118
     * @Then I should be customizing default metadata
119
     */
120
    public function iShouldBeCustomizingDefaultMetadata()
121
    {
122
        $this->assertItIsMetadataCustomizationPage(
123
            $this->getSession()->getPage(),
124
            '/DefaultPage/'
125
        );
126
    }
127
128
    /**
129
     * @Then I should be customizing products metadata
130
     */
131
    public function iShouldBeCustomizingProductsMetadata()
132
    {
133
        $this->assertItIsMetadataCustomizationPage(
134
            $this->getSession()->getPage(),
135
            '/Product(?!\-)/'
136
        );
137
    }
138
139
    /**
140
     * @Then I should be customizing specific product metadata
141
     */
142
    public function iShouldBeCustomizingSpecificProductMetadata()
143
    {
144
        $this->assertItIsMetadataCustomizationPage(
145
            $this->getSession()->getPage(),
146
            '/Product-\d+/'
147
        );
148
    }
149
150
    /**
151
     * @Then I should be customizing specific product variant metadata
152
     */
153
    public function iShouldBeCustomizingSpecificProductVariantMetadata()
154
    {
155
        $this->assertItIsMetadataCustomizationPage(
156
            $this->getSession()->getPage(),
157
            '/ProductVariant-\d+/'
158
        );
159
    }
160
161
    /**
162
     * @Then I should see Twitter's application card form
163
     */
164
    public function iShouldSeeTwitterApplicationCardForm()
165
    {
166
        $this->assertSession()->fieldExists('Iphone application name');
167
        $this->assertSession()->fieldExists('Ipad application url');
168
    }
169
170
    /**
171
     * @Then I should not see Twitter's application card form
172
     */
173
    public function iShouldNotSeeTwitterApplicationCardForm()
174
    {
175
        $this->assertSession()->fieldNotExists('Iphone application name');
176
        $this->assertSession()->fieldNotExists('Ipad application url');
177
    }
178
179
    /**
180
     * @Given there is the following metadata :metadataName:
181
     */
182
    public function thereIsTheFollowingMetadata($metadataName, TableNode $table)
183
    {
184
        /** @var MetadataContainerInterface $metadata */
185
        $metadata = $this->getFactory('metadata_container')->createNew();
186
187
        $pageMetadata = new PageMetadata();
188
189
        $metadata->setId($metadataName);
190
        $metadata->setMetadata($pageMetadata);
191
192
        foreach ($table->getRowsHash() as $key => $value) {
193
            if ($this->createNewMetadataObjectIfNeeded($pageMetadata, $key, $value)) {
194
                continue;
195
            }
196
197
            if (false !== strpos($value, ',')) {
198
                $value = array_map('trim', explode(',', $value));
199
            }
200
201
            $this->propertyAccessor->setValue($pageMetadata, $key, $value);
202
        }
203
204
        $em = $this->getEntityManager();
205
        $em->persist($metadata);
206
        $em->flush();
207
    }
208
209
    /**
210
     * @Given product :productName has the following page metadata:
211
     */
212
    public function productHasTheFollowingPageMetadata($productName, TableNode $table)
213
    {
214
        /** @var ProductInterface $product */
215
        $product = $this->getRepository('product')->findOneByName($productName);
216
217
        $this->thereIsTheFollowingMetadata($product->getMetadataIdentifier(), $table);
218
    }
219
220
    /**
221
     * @Then I should see :title as page title
222
     */
223
    public function iShouldSeeAsPageTitle($title)
224
    {
225
        $this->assertSession()->elementTextContains('css', 'title', $title);
226
    }
227
228
    /**
229
     * @Then the page keywords should contain :keyword
230
     */
231
    public function thePageKeywordsShouldContain($keyword)
232
    {
233
        $this->assertSession()->elementExists('css', sprintf('meta[name="keywords"][content*="%s"]', $keyword));
234
    }
235
236
    /**
237
     * @Then there should be Twitter summary card metadata on this page
238
     */
239
    public function thereShouldBeTwitterSummaryCardMetadataOnThisPage()
240
    {
241
        $this->assertSession()->elementExists('css', 'meta[name="twitter:card"][content="summary"]');
242
    }
243
244
    /**
245
     * @Then Twitter site should be :site
246
     */
247
    public function twitterSiteShouldBe($site)
248
    {
249
        $this->assertSession()->elementExists('css', sprintf('meta[name="twitter:site"][content="%s"]', $site));
250
    }
251
252
    /**
253
     * @Then Twitter image should be :image
254
     */
255
    public function twitterImageShouldBe($image)
256
    {
257
        $this->assertSession()->elementExists('css', sprintf('meta[name="twitter:image"][content="%s"]', $image));
258
    }
259
260
    /**
261
     * @When /I deselect "([^"]+)"/
262
     */
263
    public function iDeselectSelectField($fieldName)
264
    {
265
        $this->selectOption($fieldName, '');
266
    }
267
268
    /**
269
     * @param ElementInterface $element
270
     * @param string $regexp
271
     *
272
     * @throws \Exception If assertion failed
273
     */
274
    private function assertItIsMetadataCustomizationPage(ElementInterface $element, $regexp)
275
    {
276
        if (!$this->isItMetadataCustomizationPage($element, $regexp)) {
277
            throw new \Exception(sprintf('It is not metadata customziation page (regexp: %s)', $regexp));
278
        }
279
    }
280
281
    /**
282
     * @param ElementInterface $element
283
     * @param string $regexp
284
     *
285
     * @return bool
286
     */
287
    private function isItMetadataCustomizationPage(ElementInterface $element, $regexp)
288
    {
289
        $header = $element->find('css', '.page-header h1');
290
291
        if (null === $header) {
292
            return false;
293
        }
294
295
        if (false === strpos($header->getText(), 'Customizing metadata')) {
296
            return false;
297
        }
298
299
        if (false === (bool) preg_match($regexp, $header->getText())) {
300
            return false;
301
        }
302
303
        return true;
304
    }
305
306
    /**
307
     * @param ElementInterface $element
308
     * @param array $fields
309
     *
310
     * @throws \Exception If assertion failed
311
     */
312
    private function assertThereIsFormWithFields(ElementInterface $element, array $fields)
313
    {
314
        if (null === $this->getFormWithFields($element, $fields)) {
315
            throw new \Exception(sprintf('Could not found table with fields: %s', implode(', ', $fields)));
316
        }
317
    }
318
319
    /**
320
     * @param ElementInterface $element
321
     * @param string[] $fields
322
     *
323
     * @return ElementInterface|null
324
     */
325
    private function getFormWithFields(ElementInterface $element, array $fields)
326
    {
327
        /** @var NodeElement[] $forms */
328
        $forms = $element->findAll('css', 'form');
329
330
        foreach ($forms as $form) {
331
            $found = true;
332
            foreach ($fields as $field) {
333
                if (null === $form->findField($field)) {
334
                    $found = false;
335
                }
336
            }
337
338
            if ($found) {
339
                return $form;
340
            }
341
        }
342
343
        return null;
344
    }
345
346
    /**
347
     * @param string $value
348
     *
349
     * @return CardInterface
350
     */
351
    protected function createTwitterCardFromString($value)
352
    {
353
        switch (strtolower($value)) {
354
            case 'summary':
355
                return new SummaryCard();
356
357
            case 'summary with large image':
358
            case 'summary large image':
359
            case 'summarylargeimage':
360
                return new SummaryLargeImageCard();
361
362
            case 'player':
363
                return new PlayerCard();
364
365
            case 'app':
366
            case 'application':
367
                return new AppCard();
368
369
            default:
370
                throw new \InvalidArgumentException(sprintf('Unknown card type "%s"!', $value));
371
        }
372
    }
373
374
    /**
375
     * @param PageMetadataInterface $pageMetadata
376
     * @param string $key
377
     * @param string $value
378
     *
379
     * @return bool True if created new metadata object
380
     */
381
    protected function createNewMetadataObjectIfNeeded(PageMetadataInterface $pageMetadata, $key, $value)
382
    {
383
        if ('twitter.card' === strtolower($key)) {
384
            $pageMetadata->setTwitter($this->createTwitterCardFromString($value));
385
386
            return true;
387
        }
388
389
        return false;
390
    }
391
}
392