Completed
Push — master ( 90ccc1...22512f )
by Kamil
35:43
created

MetadataContext::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

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