Completed
Push — master ( 902cca...dde4bb )
by Paweł
138:22 queued 138:06
created

DefaultContext::getSharedService()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
dl 0
loc 4
rs 10
c 1
b 0
f 0
cc 1
eloc 2
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\ResourceBundle\Behat;
13
14
use Behat\Behat\Context\Context;
15
use Behat\MinkExtension\Context\RawMinkContext;
16
use Behat\Mink\Element\NodeElement;
17
use Behat\Mink\Exception\ElementNotFoundException;
18
use Behat\Symfony2Extension\Context\KernelAwareContext;
19
use Doctrine\Common\Collections\ArrayCollection;
20
use Doctrine\Common\Persistence\ObjectManager;
21
use Faker\Factory as FakerFactory;
22
use Faker\Generator;
23
use Sylius\Component\Resource\Factory\FactoryInterface;
24
use Sylius\Component\Resource\Repository\RepositoryInterface;
25
use Symfony\Component\DependencyInjection\ContainerInterface;
26
use Symfony\Component\HttpKernel\KernelInterface;
27
use Symfony\Component\Intl\Intl;
28
use Symfony\Component\Routing\RouterInterface;
29
use Symfony\Component\Security\Core\SecurityContextInterface;
30
use Symfony\Component\Security\Core\User\UserInterface;
31
32
abstract class DefaultContext extends RawMinkContext implements Context, KernelAwareContext
33
{
34
    /**
35
     * @var string
36
     */
37
    protected $applicationName = 'sylius';
38
39
    /**
40
     * @var Generator
41
     */
42
    protected $faker;
43
44
    /**
45
     * @var array
46
     */
47
    protected $actions = array(
48
        'viewing'  => 'show',
49
        'creation' => 'create',
50
        'editing'  => 'update',
51
        'building' => 'build',
52
    );
53
54
    /**
55
     * @var KernelInterface
56
     */
57
    private $kernel;
58
59
    /**
60
     * @var KernelInterface
61
     */
62
    private static $sharedKernel;
63
64
    public function __construct($applicationName = null)
65
    {
66
        \Locale::setDefault('en');
67
68
        $this->faker = FakerFactory::create();
69
70
        if (null !== $applicationName) {
71
            $this->applicationName = $applicationName;
72
        }
73
    }
74
75
    /**
76
     * {@inheritdoc}
77
     */
78
    public function setKernel(KernelInterface $kernel)
79
    {
80
        $this->kernel = $kernel;
81
82
        if (null === self::$sharedKernel) {
83
            self::$sharedKernel = clone $kernel;
84
            self::$sharedKernel->boot();
85
        }
86
    }
87
88
    /**
89
     * @param string $type
90
     * @param string $name
91
     *
92
     * @return object
93
     */
94
    protected function findOneByName($type, $name)
95
    {
96
        return $this->findOneBy($type, array('name' => trim($name)));
97
    }
98
99
    /**
100
     * @param string $type
101
     * @param array  $criteria
102
     *
103
     * @return object
104
     *
105
     * @throws \InvalidArgumentException
106
     */
107
    protected function findOneBy($type, array $criteria)
108
    {
109
        $resource = $this
110
            ->getRepository($type)
111
            ->findOneBy($criteria)
112
        ;
113
114
        if (null === $resource) {
115
            throw new \InvalidArgumentException(
116
                sprintf('%s for criteria "%s" was not found.', str_replace('_', ' ', ucfirst($type)), serialize($criteria))
117
            );
118
        }
119
120
        return $resource;
121
    }
122
123
    /**
124
     * @param string $resourceName
125
     *
126
     * @return RepositoryInterface
127
     */
128
    protected function getRepository($resourceName)
129
    {
130
        return $this->getService($this->applicationName.'.repository.'.$resourceName);
131
    }
132
133
    /**
134
     * @param string $resourceName
135
     *
136
     * @return FactoryInterface
137
     */
138
    protected function getFactory($resourceName)
139
    {
140
        return $this->getService($this->applicationName.'.factory.'.$resourceName);
141
    }
142
143
    /**
144
     * @return ObjectManager
145
     */
146
    protected function getEntityManager()
147
    {
148
        return $this->getService('doctrine')->getManager();
149
    }
150
151
    /**
152
     * @return ContainerInterface
153
     */
154
    protected function getContainer()
155
    {
156
        return $this->kernel->getContainer();
157
    }
158
159
    /**
160
     * @param string $id
161
     *
162
     * @return object
163
     */
164
    protected function getService($id)
165
    {
166
        return $this->getContainer()->get($id);
167
    }
168
169
    /**
170
     * Configuration converter.
171
     *
172
     * @param string $configurationString
173
     *
174
     * @return array
175
     */
176
    protected function getConfiguration($configurationString)
177
    {
178
        $configuration = array();
179
        $list = explode(',', $configurationString);
180
181
        foreach ($list as $parameter) {
182
            list($key, $value) = explode(':', $parameter, 2);
183
            $key = strtolower(trim(str_replace(' ', '_', $key)));
184
185
            switch ($key) {
186
                case 'country':
187
                    $isoName = $this->getCountryCodeByEnglishCountryName(trim($value));
188
189
                    $configuration[$key] = $this->getRepository('country')->findOneBy(array('isoName' => $isoName))->getId();
190
                    break;
191
192
                case 'taxons':
193
                    $configuration[$key] = new ArrayCollection(array($this->getRepository('taxon')->findOneBy(array('name' => trim($value)))->getId()));
194
                    break;
195
196
                case 'variant':
197
                    $configuration[$key] = $this->getRepository('product')->findOneBy(array('name' => trim($value)))->getMasterVariant()->getId();
198
                    break;
199
200
                case 'amount':
201
                    $configuration[$key] = (int) $value;
202
                    break;
203
204
                default:
205
                    $configuration[$key] = trim($value);
206
                    break;
207
            }
208
        }
209
210
        return $configuration;
211
    }
212
213
    /**
214
     * Generate page url.
215
     * This method uses simple convention where page argument is prefixed
216
     * with the application name and used as route name passed to router generate method.
217
     *
218
     * @param object|string $page
219
     * @param array         $parameters
220
     *
221
     * @return string
222
     */
223
    protected function generatePageUrl($page, array $parameters = array())
224
    {
225
        if (is_object($page)) {
226
            return $this->generateUrl($page, $parameters);
0 ignored issues
show
Documentation introduced by
$page is of type object, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
227
        }
228
229
        $route  = str_replace(' ', '_', trim($page));
230
        $routes = $this->getRouter()->getRouteCollection();
231
232
        if (null === $routes->get($route)) {
233
            $route = $this->applicationName.'_'.$route;
234
        }
235
236
        if (null === $routes->get($route)) {
237
            $route = str_replace($this->applicationName.'_', $this->applicationName.'_backend_', $route);
238
        }
239
240
        $route = str_replace(array_keys($this->actions), array_values($this->actions), $route);
241
        $route = str_replace(' ', '_', $route);
242
243
        return $this->generateUrl($route, $parameters);
244
    }
245
246
    /**
247
     * Get current user instance.
248
     *
249
     * @return UserInterface|null
250
     *
251
     * @throws \Exception
252
     */
253
    protected function getUser()
254
    {
255
        $token = $this->getSecurityContext()->getToken();
256
257
        if (null === $token) {
258
            throw new \Exception('No token found in security context.');
259
        }
260
261
        return $token->getUser();
262
    }
263
264
    /**
265
     * @return SecurityContextInterface
266
     */
267
    protected function getSecurityContext()
268
    {
269
        return $this->getContainer()->get('security.context');
270
    }
271
272
    /**
273
     * @param string  $route
274
     * @param array   $parameters
275
     * @param Boolean $absolute
276
     *
277
     * @return string
278
     */
279
    protected function generateUrl($route, array $parameters = array(), $absolute = false)
280
    {
281
        return $this->locatePath($this->getRouter()->generate($route, $parameters, $absolute));
282
    }
283
284
    /**
285
     * Presses button with specified id|name|title|alt|value.
286
     *
287
     * @param string $button
288
     *
289
     * @throws ElementNotFoundException
290
     */
291
    protected function pressButton($button)
292
    {
293
        $this->getSession()->getPage()->pressButton($this->fixStepArgument($button));
294
    }
295
296
    /**
297
     * Clicks link with specified id|title|alt|text.
298
     *
299
     * @param string $link
300
     *
301
     * @throws ElementNotFoundException
302
     */
303
    protected function clickLink($link)
304
    {
305
        $this->getSession()->getPage()->clickLink($this->fixStepArgument($link));
306
    }
307
308
    /**
309
     * Fills in form field with specified id|name|label|value.
310
     *
311
     * @param string $field
312
     * @param string $value
313
     *
314
     * @throws ElementNotFoundException
315
     */
316
    protected function fillField($field, $value)
317
    {
318
        $this->getSession()->getPage()->fillField(
319
            $this->fixStepArgument($field),
320
            $this->fixStepArgument($value)
321
        );
322
    }
323
324
    /**
325
     * Selects option in select field with specified id|name|label|value.
326
     *
327
     * @param string $select
328
     * @param string $option
329
     *
330
     * @throws ElementNotFoundException
331
     */
332
    protected function selectOption($select, $option)
333
    {
334
        $this->getSession()->getPage()->selectFieldOption(
335
            $this->fixStepArgument($select),
336
            $this->fixStepArgument($option)
337
        );
338
    }
339
340
    /**
341
     * Returns fixed step argument (with \\" replaced back to ").
342
     *
343
     * @param string $argument
344
     *
345
     * @return string
346
     */
347
    protected function fixStepArgument($argument)
348
    {
349
        return str_replace('\\"', '"', $argument);
350
    }
351
352
    /**
353
     * @param NodeElement $table
354
     * @param string $columnName
355
     *
356
     * @return integer
357
     *
358
     * @throws \Exception If column was not found
359
     */
360
    protected function getColumnIndex(NodeElement $table, $columnName)
361
    {
362
        $rows = $table->findAll('css', 'tr');
363
364
        if (!isset($rows[0])) {
365
            throw new \Exception("There are no rows!");
366
        }
367
368
        /** @var NodeElement $firstRow */
369
        $firstRow = $rows[0];
370
        $columns = $firstRow->findAll('css', 'th,td');
371
        foreach ($columns as $index => $column) {
372
            /** @var NodeElement $column */
373
            if (0 === stripos($column->getText(), $columnName)) {
374
                return $index;
375
            }
376
        }
377
378
        throw new \Exception(sprintf('Column with name "%s" not found!', $columnName));
379
    }
380
381
    /**
382
     * @param NodeElement $table
383
     * @param array $fields
384
     *
385
     * @return NodeElement|null
386
     *
387
     * @throws \Exception If column was not found
388
     */
389
    protected function getRowWithFields(NodeElement $table, array $fields)
390
    {
391
        $foundRows = $this->getRowsWithFields($table, $fields, true);
392
393
        if (empty($foundRows)) {
394
            return null;
395
        }
396
397
        return current($foundRows);
398
    }
399
400
    /**
401
     * @param NodeElement $table
402
     * @param array $fields
403
     * @param boolean $onlyFirstOccurence
404
     *
405
     * @return NodeElement[]
406
     *
407
     * @throws \Exception If columns or rows were not found
408
     */
409
    protected function getRowsWithFields(NodeElement $table, array $fields, $onlyFirstOccurence = false)
410
    {
411
        $rows = $table->findAll('css', 'tr');
412
413
        if (!isset($rows[0])) {
414
            throw new \Exception("There are no rows!");
415
        }
416
417
        $fields = $this->replaceColumnNamesWithColumnIds($table, $fields);
418
419
        $foundRows = array();
420
421
        /** @var NodeElement[] $rows */
422
        $rows = $table->findAll('css', 'tr');
423
        foreach ($rows as $row) {
424
            $found = true;
425
426
            /** @var NodeElement[] $columns */
427
            $columns = $row->findAll('css', 'th,td');
428
            foreach ($fields as $index => $searchedValue) {
429
                if (!isset($columns[$index])) {
430
                    throw new \InvalidArgumentException(sprintf('There is no column with index %d', $index));
431
                }
432
433
                $containing = false;
434
                $searchedValue = trim($searchedValue);
435
                if (0 === strpos($searchedValue, '%') && (strlen($searchedValue) - 1) === strrpos($searchedValue, '%')) {
436
                    $searchedValue = substr($searchedValue, 1, strlen($searchedValue) - 2);
437
                    $containing = true;
438
                }
439
440
                $position = stripos(trim($columns[$index]->getText()), $searchedValue);
441
                if (($containing && false === $position) || (!$containing && 0 !== $position)) {
442
                    $found = false;
443
444
                    break;
445
                }
446
            }
447
448
            if ($found) {
449
                $foundRows[] = $row;
450
451
                if ($onlyFirstOccurence) {
452
                    break;
453
                }
454
            }
455
        }
456
457
        return $foundRows;
458
    }
459
460
    /**
461
     * @param NodeElement $table
462
     * @param string[] $fields
463
     *
464
     * @return string[]
465
     *
466
     * @throws \Exception
467
     */
468
    protected function replaceColumnNamesWithColumnIds(NodeElement $table, array $fields)
469
    {
470
        $replacedFields = array();
471
        foreach ($fields as $columnName => $expectedValue) {
472
            $columnIndex = $this->getColumnIndex($table, $columnName);
473
474
            $replacedFields[$columnIndex] = $expectedValue;
475
        }
476
477
        return $replacedFields;
478
    }
479
480
    /**
481
     * @param callable $callback
482
     * @param int $limit
483
     * @param int $delay In miliseconds
484
     *
485
     * @return mixed
486
     *
487
     * @throws \RuntimeException If timeout was reached
488
     */
489
    protected function waitFor(callable $callback, $limit = 30, $delay = 100)
490
    {
491
        for ($i = 0; $i < $limit; ++$i) {
492
            $payload = $callback();
493
494
            if (!empty($payload)) {
495
                return $payload;
496
            }
497
498
            usleep($delay * 1000);
499
        }
500
501
        throw new \RuntimeException(sprintf('Timeout reached (%f seconds)!', round($limit * $delay / 1000, 1)));
502
    }
503
504
    /**
505
     * @param string $name
506
     *
507
     * @return string
508
     *
509
     * @throws \InvalidArgumentException If name is not found in country code registry.
510
     */
511
    protected function getCountryCodeByEnglishCountryName($name)
512
    {
513
        $names = Intl::getRegionBundle()->getCountryNames('en');
514
        $isoName = array_search(trim($name), $names);
515
516
        if (null === $isoName) {
517
            throw new \InvalidArgumentException(sprintf(
518
                'Country "%s" not found! Available names: %s.', $name, join(', ', $names)
519
            ));
520
        }
521
522
        return $isoName;
523
    }
524
525
    /**
526
     * @param string $name
527
     *
528
     * @return string
529
     *
530
     * @throws \InvalidArgumentException If name is not found in locale code registry.
531
     */
532
    protected function getLocaleCodeByEnglishLocaleName($name)
533
    {
534
        $names = Intl::getLocaleBundle()->getLocaleNames('en');
535
        $code = array_search(trim($name), $names);
536
537
        if (null === $code) {
538
            throw new \InvalidArgumentException(sprintf(
539
                'Locale "%s" not found! Available names: %s.', $name, join(', ', $names)
540
            ));
541
        }
542
543
        return $code;
544
    }
545
546
    /**
547
     * @return RouterInterface
548
     */
549
    protected function getRouter()
550
    {
551
        return $this->getSharedService('router');
552
    }
553
554
    /**
555
     * @return KernelInterface
556
     */
557
    protected function getKernel()
558
    {
559
        return $this->kernel;
560
    }
561
562
    /**
563
     * @return KernelInterface
564
     */
565
    protected function getSharedKernel()
566
    {
567
        return self::$sharedKernel;
568
    }
569
570
    /**
571
     * @param string $id
572
     *
573
     * @return object
574
     */
575
    protected function getSharedService($id)
576
    {
577
        return self::$sharedKernel->getContainer()->get($id);
578
    }
579
}
580