Passed
Push — master ( bc7a69...e18866 )
by Alexis
03:46
created

Test/WebTestCase.php (1 issue)

Severity

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
/*
4
 * This file is part of the Liip/FunctionalTestBundle
5
 *
6
 * (c) Lukas Kahwe Smith <[email protected]>
7
 *
8
 * This source file is subject to the MIT license that is bundled
9
 * with this source code in the file LICENSE.
10
 */
11
12
namespace Liip\FunctionalTestBundle\Test;
13
14
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase as BaseWebTestCase;
15
use Symfony\Bundle\FrameworkBundle\Console\Application;
16
use Symfony\Bundle\FrameworkBundle\Client;
17
use Symfony\Component\Console\Input\ArrayInput;
18
use Symfony\Component\Console\Output\OutputInterface;
19
use Symfony\Component\Console\Output\StreamOutput;
20
use Symfony\Component\DomCrawler\Crawler;
21
use Symfony\Component\BrowserKit\Cookie;
22
use Symfony\Component\HttpKernel\Kernel;
23
use Symfony\Component\HttpFoundation\Response;
24
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
25
use Symfony\Component\Security\Core\User\UserInterface;
26
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
27
use Symfony\Component\DependencyInjection\ContainerInterface;
28
use Symfony\Component\HttpFoundation\Session\Session;
29
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
30
use Symfony\Bridge\Doctrine\ManagerRegistry;
31
use Symfony\Bundle\DoctrineFixturesBundle\Common\DataFixtures\Loader;
32
use Doctrine\Common\Persistence\ObjectManager;
33
use Doctrine\Common\DataFixtures\DependentFixtureInterface;
34
use Doctrine\Common\DataFixtures\Executor\AbstractExecutor;
35
use Doctrine\Common\DataFixtures\ProxyReferenceRepository;
36
use Doctrine\DBAL\Driver\PDOSqlite\Driver as SqliteDriver;
37
use Doctrine\DBAL\Platforms\MySqlPlatform;
38
use Doctrine\ORM\EntityManager;
39
use Doctrine\ORM\Tools\SchemaTool;
40
use Nelmio\Alice\Fixtures;
41
use Liip\FunctionalTestBundle\Utils\HttpAssertions;
42
43
/**
44
 * @author Lea Haensenberger
45
 * @author Lukas Kahwe Smith <[email protected]>
46
 * @author Benjamin Eberlei <[email protected]>
47
 */
48
abstract class WebTestCase extends BaseWebTestCase
49
{
50
    protected $environment = 'test';
51
    protected $containers;
52
    protected $kernelDir;
53
    // 5 * 1024 * 1024 KB
54
    protected $maxMemory = 5242880;
55
56
    // RUN COMMAND
57
    protected $verbosityLevel;
58
    protected $decorated;
59
60
    /**
61
     * @var array
62
     */
63
    private $firewallLogins = array();
64
65
    /**
66
     * @var array
67
     */
68
    private $excludedDoctrineTables = array();
69
70
    /**
71
     * @var array
72
     */
73
    private static $cachedMetadatas = array();
74
75
    protected static function getKernelClass()
76
    {
77
        $dir = isset($_SERVER['KERNEL_DIR']) ? $_SERVER['KERNEL_DIR'] : static::getPhpUnitXmlDir();
78
79
        list($appname) = explode('\\', get_called_class());
80
81
        $class = $appname.'Kernel';
82
        $file = $dir.'/'.strtolower($appname).'/'.$class.'.php';
83
        if (!file_exists($file)) {
84
            return parent::getKernelClass();
85
        }
86
        require_once $file;
87
88
        return $class;
89
    }
90
91
    /**
92
     * Creates a mock object of a service identified by its id.
93
     *
94
     * @param string $id
95
     *
96
     * @return \PHPUnit_Framework_MockObject_MockBuilder
97
     */
98 1
    protected function getServiceMockBuilder($id)
99 1
    {
100
        $service = $this->getContainer()->get($id);
101
        $class = get_class($service);
102
103
        return $this->getMockBuilder($class)->disableOriginalConstructor();
104
    }
105
106
    /**
107
     * Builds up the environment to run the given command.
108
     *
109
     * @param string $name
110
     * @param array  $params
111
     * @param bool   $reuseKernel
112
     *
113
     * @return string
114
     */
115 12
    protected function runCommand($name, array $params = array(), $reuseKernel = false)
116
    {
117 12
        array_unshift($params, $name);
118
119 12
        if (!$reuseKernel) {
120 12
            if (null !== static::$kernel) {
121 9
                static::$kernel->shutdown();
122 9
            }
123
124 12
            $kernel = static::$kernel = $this->createKernel(array('environment' => $this->environment));
125 12
            $kernel->boot();
126 12
        } else {
127 2
            $kernel = $this->getContainer()->get('kernel');
128
        }
129
130 12
        $application = new Application($kernel);
131 12
        $application->setAutoExit(false);
132
133
        // @codeCoverageIgnoreStart
134
        if ('203' === substr(Kernel::VERSION_ID, 0, 3)) {
135
            $params = $this->configureVerbosityForSymfony203($params);
136
        }
137
        // @codeCoverageIgnoreEnd
138
139 12
        $input = new ArrayInput($params);
140 12
        $input->setInteractive(false);
141
142 12
        $fp = fopen('php://temp/maxmemory:'.$this->maxMemory, 'r+');
143 12
        $output = new StreamOutput($fp, $this->getVerbosityLevel(), $this->getDecorated());
144
145 11
        $application->run($input, $output);
146
147 11
        rewind($fp);
148
149 11
        return stream_get_contents($fp);
150
    }
151
152
    /**
153
     * Retrieves the output verbosity level.
154
     *
155
     * @see Symfony\Component\Console\Output\OutputInterface for available levels
156
     *
157
     * @return int
158
     *
159
     * @throws \OutOfBoundsException If the set value isn't accepted
160
     */
161 12
    protected function getVerbosityLevel()
162
    {
163
        // If `null`, is not yet set
164 12
        if (null === $this->verbosityLevel) {
165
            // Set the global verbosity level that is set as NORMAL by the TreeBuilder in Configuration
166 6
            $level = strtoupper($this->getContainer()->getParameter('liip_functional_test.command_verbosity'));
167 6
            $verbosity = '\Symfony\Component\Console\Output\StreamOutput::VERBOSITY_'.$level;
168
169 6
            $this->verbosityLevel = constant($verbosity);
170 6
        }
171
172
        // If string, it is set by the developer, so check that the value is an accepted one
173 12
        if (is_string($this->verbosityLevel)) {
174 6
            $level = strtoupper($this->verbosityLevel);
175 6
            $verbosity = '\Symfony\Component\Console\Output\StreamOutput::VERBOSITY_'.$level;
176
177 6
            if (!defined($verbosity)) {
178 1
                throw new \OutOfBoundsException(
179 1
                    sprintf('The set value "%s" for verbosityLevel is not valid. Accepted are: "quiet", "normal", "verbose", "very_verbose" and "debug".', $level)
180 1
                );
181
            }
182
183 5
            $this->verbosityLevel = constant($verbosity);
184 5
        }
185
186 11
        return $this->verbosityLevel;
187
    }
188
189
    /**
190
     * In Symfony 2.3.* the verbosity level has to be set through {Symfony\Component\Console\Input\ArrayInput} and not
191
     * in {Symfony\Component\Console\Output\OutputInterface}.
192
     *
193
     * This method builds $params to be passed to {Symfony\Component\Console\Input\ArrayInput}.
194
     *
195
     * @codeCoverageIgnore
196
     *
197
     * @param array $params
198
     *
199
     * @return array
200
     */
201
    private function configureVerbosityForSymfony203(array $params)
202
    {
203
        switch ($this->getVerbosityLevel()) {
204
            case OutputInterface::VERBOSITY_QUIET:
205
                $params['-q'] = '-q';
206
                break;
207
208
            case OutputInterface::VERBOSITY_VERBOSE:
209
                $params['-v'] = '';
210
                break;
211
212
            case OutputInterface::VERBOSITY_VERY_VERBOSE:
213
                $params['-vv'] = '';
214
                break;
215
216
            case OutputInterface::VERBOSITY_DEBUG:
217
                $params['-vvv'] = '';
218
                break;
219
        }
220
221
        return $params;
222
    }
223
224 6
    public function setVerbosityLevel($level)
225
    {
226 6
        $this->verbosityLevel = $level;
227 6
    }
228
229
    /**
230
     * Retrieves the flag indicating if the output should be decorated or not.
231
     *
232
     * @return bool
233
     */
234 11
    protected function getDecorated()
235
    {
236 11
        if (null === $this->decorated) {
237
            // Set the global decoration flag that is set to `true` by the TreeBuilder in Configuration
238 5
            $this->decorated = $this->getContainer()->getParameter('liip_functional_test.command_decoration');
239 5
        }
240
241
        // Check the local decorated flag
242 11
        if (false === is_bool($this->decorated)) {
243
            throw new \OutOfBoundsException(
244
                sprintf('`WebTestCase::decorated` has to be `bool`. "%s" given.', gettype($this->decorated))
245
            );
246
        }
247
248 11
        return $this->decorated;
249
    }
250
251 6
    public function isDecorated($decorated)
252
    {
253 6
        $this->decorated = $decorated;
254 6
    }
255
256
    /**
257
     * Get an instance of the dependency injection container.
258
     * (this creates a kernel *without* parameters).
259
     *
260
     * @return ContainerInterface
261
     */
262 50
    protected function getContainer()
263
    {
264 50
        if (!empty($this->kernelDir)) {
265
            $tmpKernelDir = isset($_SERVER['KERNEL_DIR']) ? $_SERVER['KERNEL_DIR'] : null;
266
            $_SERVER['KERNEL_DIR'] = getcwd().$this->kernelDir;
267
        }
268
269 50
        $cacheKey = $this->kernelDir.'|'.$this->environment;
270 50
        if (empty($this->containers[$cacheKey])) {
271
            $options = array(
272 49
                'environment' => $this->environment,
273 49
            );
274 49
            $kernel = $this->createKernel($options);
275 49
            $kernel->boot();
276
277 49
            $this->containers[$cacheKey] = $kernel->getContainer();
278 49
        }
279
280 50
        if (isset($tmpKernelDir)) {
281
            $_SERVER['KERNEL_DIR'] = $tmpKernelDir;
282
        }
283
284 50
        return $this->containers[$cacheKey];
285
    }
286
287
    /**
288
     * This function finds the time when the data blocks of a class definition
289
     * file were being written to, that is, the time when the content of the
290
     * file was changed.
291
     *
292
     * @param string $class The fully qualified class name of the fixture class to
293
     *                      check modification date on
294
     *
295
     * @return \DateTime|null
296
     */
297 3
    protected function getFixtureLastModified($class)
298
    {
299 3
        $lastModifiedDateTime = null;
300
301 3
        $reflClass = new \ReflectionClass($class);
302 3
        $classFileName = $reflClass->getFileName();
303
304 3
        if (file_exists($classFileName)) {
305 3
            $lastModifiedDateTime = new \DateTime();
306 3
            $lastModifiedDateTime->setTimestamp(filemtime($classFileName));
307 3
        }
308
309 3
        return $lastModifiedDateTime;
310
    }
311
312
    /**
313
     * Determine if the Fixtures that define a database backup have been
314
     * modified since the backup was made.
315
     *
316
     * @param array  $classNames The fixture classnames to check
317
     * @param string $backup     The fixture backup SQLite database file path
318
     *
319
     * @return bool TRUE if the backup was made since the modifications to the
320
     *              fixtures; FALSE otherwise
321
     */
322 7
    protected function isBackupUpToDate(array $classNames, $backup)
323
    {
324 7
        $backupLastModifiedDateTime = new \DateTime();
325 7
        $backupLastModifiedDateTime->setTimestamp(filemtime($backup));
326
327
        /** @var \Symfony\Bridge\Doctrine\DataFixtures\ContainerAwareLoader $loader */
328 7
        $loader = $this->getFixtureLoader($this->getContainer(), $classNames);
329
330
        // Use loader in order to fetch all the dependencies fixtures.
331 7
        foreach ($loader->getFixtures() as $className) {
332 3
            $fixtureLastModifiedDateTime = $this->getFixtureLastModified($className);
333 3
            if ($backupLastModifiedDateTime < $fixtureLastModifiedDateTime) {
334 1
                return false;
335
            }
336 7
        }
337
338 7
        return true;
339
    }
340
341
    /**
342
     * Set the database to the provided fixtures.
343
     *
344
     * Drops the current database and then loads fixtures using the specified
345
     * classes. The parameter is a list of fully qualified class names of
346
     * classes that implement Doctrine\Common\DataFixtures\FixtureInterface
347
     * so that they can be loaded by the DataFixtures Loader::addFixture
348
     *
349
     * When using SQLite this method will automatically make a copy of the
350
     * loaded schema and fixtures which will be restored automatically in
351
     * case the same fixture classes are to be loaded again. Caveat: changes
352
     * to references and/or identities may go undetected.
353
     *
354
     * Depends on the doctrine data-fixtures library being available in the
355
     * class path.
356
     *
357
     * @param array  $classNames   List of fully qualified class names of fixtures to load
358
     * @param string $omName       The name of object manager to use
359
     * @param string $registryName The service id of manager registry to use
360
     * @param int    $purgeMode    Sets the ORM purge mode
361
     *
362
     * @return null|AbstractExecutor
363
     */
364 36
    protected function loadFixtures(array $classNames, $omName = null, $registryName = 'doctrine', $purgeMode = null)
365
    {
366 36
        $container = $this->getContainer();
367
        /** @var ManagerRegistry $registry */
368 36
        $registry = $container->get($registryName);
369
        /** @var ObjectManager $om */
370 36
        $om = $registry->getManager($omName);
371 36
        $type = $registry->getName();
372
373 36
        $executorClass = 'PHPCR' === $type && class_exists('Doctrine\Bundle\PHPCRBundle\DataFixtures\PHPCRExecutor')
374 36
            ? 'Doctrine\Bundle\PHPCRBundle\DataFixtures\PHPCRExecutor'
375 36
            : 'Doctrine\\Common\\DataFixtures\\Executor\\'.$type.'Executor';
376 36
        $referenceRepository = new ProxyReferenceRepository($om);
377 36
        $cacheDriver = $om->getMetadataFactory()->getCacheDriver();
378
379 36
        if ($cacheDriver) {
380 36
            $cacheDriver->deleteAll();
381 36
        }
382
383 36
        if ('ORM' === $type) {
384 35
            $connection = $om->getConnection();
385 35
            if ($connection->getDriver() instanceof SqliteDriver) {
386 30
                $params = $connection->getParams();
387 30
                if (isset($params['master'])) {
388
                    $params = $params['master'];
389
                }
390
391 30
                $name = isset($params['path']) ? $params['path'] : (isset($params['dbname']) ? $params['dbname'] : false);
392 30
                if (!$name) {
393
                    throw new \InvalidArgumentException("Connection does not contain a 'path' or 'dbname' parameter and cannot be dropped.");
394
                }
395
396 30
                if (!isset(self::$cachedMetadatas[$omName])) {
397 10
                    self::$cachedMetadatas[$omName] = $om->getMetadataFactory()->getAllMetadata();
398 10
                    usort(self::$cachedMetadatas[$omName], function ($a, $b) {
399
                        return strcmp($a->name, $b->name);
400 10
                    });
401 10
                }
402 30
                $metadatas = self::$cachedMetadatas[$omName];
403
404 30
                if ($container->getParameter('liip_functional_test.cache_sqlite_db')) {
405 9
                    $backup = $container->getParameter('kernel.cache_dir').'/test_'.md5(serialize($metadatas).serialize($classNames)).'.db';
406 9
                    if (file_exists($backup) && file_exists($backup.'.ser') && $this->isBackupUpToDate($classNames, $backup)) {
407 7
                        $connection = $this->getContainer()->get('doctrine.orm.entity_manager')->getConnection();
408 7
                        if (null !== $connection) {
409 7
                            $connection->close();
410 7
                        }
411
412 7
                        $om->flush();
413 7
                        $om->clear();
414
415 7
                        $this->preFixtureBackupRestore($om, $referenceRepository, $backup);
416
417 7
                        copy($backup, $name);
418
419 7
                        $executor = new $executorClass($om);
420 7
                        $executor->setReferenceRepository($referenceRepository);
421 7
                        $executor->getReferenceRepository()->load($backup);
422
423 7
                        $this->postFixtureBackupRestore($backup);
424
425 7
                        return $executor;
426
                    }
427 3
                }
428
429
                // TODO: handle case when using persistent connections. Fail loudly?
430 24
                $schemaTool = new SchemaTool($om);
431 24
                $schemaTool->dropDatabase();
432 24
                if (!empty($metadatas)) {
433 24
                    $schemaTool->createSchema($metadatas);
434 24
                }
435 24
                $this->postFixtureSetup();
436
437 24
                $executor = new $executorClass($om);
438 24
                $executor->setReferenceRepository($referenceRepository);
439 24
            }
440 29
        }
441
442 30
        if (empty($executor)) {
443 6
            $purgerClass = 'Doctrine\\Common\\DataFixtures\\Purger\\'.$type.'Purger';
444 6
            if ('PHPCR' === $type) {
445 1
                $purger = new $purgerClass($om);
446 1
                $initManager = $container->has('doctrine_phpcr.initializer_manager')
447 1
                    ? $container->get('doctrine_phpcr.initializer_manager')
448 1
                    : null;
449
450 1
                $executor = new $executorClass($om, $purger, $initManager);
451 1
            } else {
452 5
                if ('ORM' === $type) {
453 5
                    $purger = new $purgerClass(null, $this->excludedDoctrineTables);
454 5
                } else {
455
                    $purger = new $purgerClass();
456
                }
457
458 5
                if (null !== $purgeMode) {
459 2
                    $purger->setPurgeMode($purgeMode);
460 2
                }
461
462 5
                $executor = new $executorClass($om, $purger);
463
            }
464
465 6
            $executor->setReferenceRepository($referenceRepository);
466 6
            $executor->purge();
467 6
        }
468
469 30
        $loader = $this->getFixtureLoader($container, $classNames);
470
471 30
        $executor->execute($loader->getFixtures(), true);
472
473 30
        if (isset($name) && isset($backup)) {
474 3
            $this->preReferenceSave($om, $executor, $backup);
475
476 3
            $executor->getReferenceRepository()->save($backup);
477 3
            copy($name, $backup);
478
479 3
            $this->postReferenceSave($om, $executor, $backup);
480 3
        }
481
482 30
        return $executor;
483
    }
484
485
    /**
486
     * Clean database.
487
     *
488
     * @param ManagerRegistry $registry
489
     * @param EntityManager   $om
490
     * @param null            $omName
491
     * @param string          $registryName
492
     * @param int             $purgeMode
493
     */
494 9
    private function cleanDatabase(ManagerRegistry $registry, EntityManager $om, $omName = null, $registryName = 'doctrine', $purgeMode = null)
495
    {
496 9
        $connection = $om->getConnection();
497
498 9
        $mysql = ($registry->getName() === 'ORM'
499 9
            && $connection->getDatabasePlatform() instanceof MySqlPlatform);
500
501 9
        if ($mysql) {
502 1
            $connection->query('SET FOREIGN_KEY_CHECKS=0');
503 1
        }
504
505 9
        $this->loadFixtures(array(), $omName, $registryName, $purgeMode);
506
507 9
        if ($mysql) {
508 1
            $connection->query('SET FOREIGN_KEY_CHECKS=1');
509 1
        }
510 9
    }
511
512
    /**
513
     * Locate fixture files.
514
     *
515
     * @param array $paths
516
     *
517
     * @return array $files
518
     *
519
     * @throws \InvalidArgumentException if a wrong path is given outside a bundle
520
     */
521 10
    private function locateResources($paths)
522
    {
523 10
        $files = array();
524
525 10
        $kernel = $this->getContainer()->get('kernel');
526
527 10
        foreach ($paths as $path) {
528 10
            if ($path[0] !== '@') {
529 3
                if (!file_exists($path)) {
530 1
                    throw new \InvalidArgumentException(sprintf('Unable to find file "%s".', $path));
531
                }
532 2
                $files[] = $path;
533 2
                continue;
534
            }
535
536 7
            $files[] = $kernel->locateResource($path);
537 8
        }
538
539 8
        return $files;
540
    }
541
542
    /**
543
     * @param array  $paths        Either symfony resource locators (@ BundleName/etc) or actual file paths
544
     * @param bool   $append
545
     * @param null   $omName
546
     * @param string $registryName
547
     * @param int    $purgeMode
548
     *
549
     * @return array
550
     *
551
     * @throws \BadMethodCallException
552
     */
553 10
    public function loadFixtureFiles(array $paths = array(), $append = false, $omName = null, $registryName = 'doctrine', $purgeMode = null)
554
    {
555 10
        if (!class_exists('Nelmio\Alice\Fixtures')) {
556
            // This class is available during tests, no exception will be thrown.
557
            // @codeCoverageIgnoreStart
558
            throw new \BadMethodCallException('nelmio/alice should be installed to use this method.');
559
            // @codeCoverageIgnoreEnd
560
        }
561
562
        /** @var ContainerInterface $container */
563 10
        $container = $this->getContainer();
564
565
        /** @var ManagerRegistry $registry */
566 10
        $registry = $container->get($registryName);
567
568
        /** @var EntityManager $om */
569 10
        $om = $registry->getManager($omName);
570
571 10
        if ($append === false) {
572 9
            $this->cleanDatabase($registry, $om, $omName, $registryName, $purgeMode);
573 9
        }
574
575 10
        $files = $this->locateResources($paths);
576
577
        // Check if the Hautelook AliceBundle is registered and if yes, use it instead of Nelmio Alice
578 8
        $hautelookLoaderServiceName = 'hautelook_alice.fixtures.loader';
579 8
        if ($container->has($hautelookLoaderServiceName)) {
580 3
            $loaderService = $container->get($hautelookLoaderServiceName);
581 3
            $persisterClass = class_exists('Nelmio\Alice\ORM\Doctrine') ?
582 3
                'Nelmio\Alice\ORM\Doctrine' :
583 3
                'Nelmio\Alice\Persister\Doctrine';
584
585 3
            return $loaderService->load(new $persisterClass($om), $files);
586
        }
587
588 5
        return Fixtures::load($files, $om);
589
    }
590
591
    /**
592
     * Callback function to be executed after Schema creation.
593
     * Use this to execute acl:init or other things necessary.
594
     */
595 24
    protected function postFixtureSetup()
596
    {
597 24
    }
598
599
    /**
600
     * Callback function to be executed after Schema restore.
601
     *
602
     * @return WebTestCase
603
     *
604
     * @deprecated since version 1.8, to be removed in 2.0. Use postFixtureBackupRestore method instead.
605
     */
606 7
    protected function postFixtureRestore()
607
    {
608 7
    }
609
610
    /**
611
     * Callback function to be executed before Schema restore.
612
     *
613
     * @param ObjectManager            $manager             The object manager
614
     * @param ProxyReferenceRepository $referenceRepository The reference repository
615
     *
616
     * @return WebTestCase
617
     *
618
     * @deprecated since version 1.8, to be removed in 2.0. Use preFixtureBackupRestore method instead.
619
     */
620 7
    protected function preFixtureRestore(ObjectManager $manager, ProxyReferenceRepository $referenceRepository)
621
    {
622 7
    }
623
624
    /**
625
     * Callback function to be executed after Schema restore.
626
     *
627
     * @param string $backupFilePath Path of file used to backup the references of the data fixtures
628
     *
629
     * @return WebTestCase
630
     */
631 7
    protected function postFixtureBackupRestore($backupFilePath)
632
    {
633 7
        $this->postFixtureRestore();
634
635 7
        return $this;
636
    }
637
638
    /**
639
     * Callback function to be executed before Schema restore.
640
     *
641
     * @param ObjectManager            $manager             The object manager
642
     * @param ProxyReferenceRepository $referenceRepository The reference repository
643
     * @param string                   $backupFilePath      Path of file used to backup the references of the data fixtures
644
     *
645
     * @return WebTestCase
646
     */
647 7
    protected function preFixtureBackupRestore(
648
        ObjectManager $manager,
649
        ProxyReferenceRepository $referenceRepository,
650
        $backupFilePath
651
    ) {
652 7
        $this->preFixtureRestore($manager, $referenceRepository);
653
654 7
        return $this;
655
    }
656
657
    /**
658
     * Callback function to be executed after save of references.
659
     *
660
     * @param ObjectManager    $manager        The object manager
661
     * @param AbstractExecutor $executor       Executor of the data fixtures
662
     * @param string           $backupFilePath Path of file used to backup the references of the data fixtures
663
     *
664
     * @return WebTestCase
665
     */
666 3
    protected function postReferenceSave(ObjectManager $manager, AbstractExecutor $executor, $backupFilePath)
667
    {
668 3
    }
669
670
    /**
671
     * Callback function to be executed before save of references.
672
     *
673
     * @param ObjectManager    $manager        The object manager
674
     * @param AbstractExecutor $executor       Executor of the data fixtures
675
     * @param string           $backupFilePath Path of file used to backup the references of the data fixtures
676
     *
677
     * @return WebTestCase
678
     */
679 3
    protected function preReferenceSave(ObjectManager $manager, AbstractExecutor $executor, $backupFilePath)
680
    {
681 3
    }
682
683
    /**
684
     * Retrieve Doctrine DataFixtures loader.
685
     *
686
     * @param ContainerInterface $container
687
     * @param array              $classNames
688
     *
689
     * @return Loader
690
     */
691 36
    protected function getFixtureLoader(ContainerInterface $container, array $classNames)
692
    {
693 36
        $loaderClass = class_exists('Symfony\Bridge\Doctrine\DataFixtures\ContainerAwareLoader')
694 36
            ? 'Symfony\Bridge\Doctrine\DataFixtures\ContainerAwareLoader'
695 36
            : (class_exists('Doctrine\Bundle\FixturesBundle\Common\DataFixtures\Loader')
696
                // This class is not available during tests.
697
                // @codeCoverageIgnoreStart
698
                ? 'Doctrine\Bundle\FixturesBundle\Common\DataFixtures\Loader'
699
                // @codeCoverageIgnoreEnd
700 36
                : 'Symfony\Bundle\DoctrineFixturesBundle\Common\DataFixtures\Loader');
701
702 36
        $loader = new $loaderClass($container);
703
704 36
        foreach ($classNames as $className) {
705 11
            $this->loadFixtureClass($loader, $className);
706 36
        }
707
708 36
        return $loader;
709
    }
710
711
    /**
712
     * Load a data fixture class.
713
     *
714
     * @param Loader $loader
715
     * @param string $className
716
     */
717 11
    protected function loadFixtureClass($loader, $className)
718
    {
719 11
        $fixture = new $className();
720
721 11
        if ($loader->hasFixture($fixture)) {
722 2
            unset($fixture);
723
724 2
            return;
725
        }
726
727 11
        $loader->addFixture($fixture);
728
729 11
        if ($fixture instanceof DependentFixtureInterface) {
730 2
            foreach ($fixture->getDependencies() as $dependency) {
731 2
                $this->loadFixtureClass($loader, $dependency);
732 2
            }
733 2
        }
734 11
    }
735
736
    /**
737
     * Creates an instance of a lightweight Http client.
738
     *
739
     * If $authentication is set to 'true' it will use the content of
740
     * 'liip_functional_test.authentication' to log in.
741
     *
742
     * $params can be used to pass headers to the client, note that they have
743
     * to follow the naming format used in $_SERVER.
744
     * Example: 'HTTP_X_REQUESTED_WITH' instead of 'X-Requested-With'
745
     *
746
     * @param bool|array $authentication
747
     * @param array      $params
748
     *
749
     * @return Client
750
     */
751 55
    protected function makeClient($authentication = false, array $params = array())
752
    {
753 55
        if ($authentication) {
754 2
            if ($authentication === true) {
755
                $authentication = array(
756 1
                    'username' => $this->getContainer()
757 1
                        ->getParameter('liip_functional_test.authentication.username'),
758 1
                    'password' => $this->getContainer()
759 1
                        ->getParameter('liip_functional_test.authentication.password'),
760 1
                );
761 1
            }
762
763 2
            $params = array_merge($params, array(
764 2
                'PHP_AUTH_USER' => $authentication['username'],
765 2
                'PHP_AUTH_PW' => $authentication['password'],
766 2
            ));
767 2
        }
768
769 55
        $client = static::createClient(array('environment' => $this->environment), $params);
770
771 55
        if ($this->firewallLogins) {
772
            // has to be set otherwise "hasPreviousSession" in Request returns false.
773 2
            $options = $client->getContainer()->getParameter('session.storage.options');
774
775 2
            if (!$options || !isset($options['name'])) {
776
                throw new \InvalidArgumentException('Missing session.storage.options#name');
777
            }
778
779 2
            $session = $client->getContainer()->get('session');
780
            // Since the namespace of the session changed in symfony 2.1, instanceof can be used to check the version.
781 2
            if ($session instanceof Session) {
782 2
                $session->setId(uniqid());
783 2
            }
784
785 2
            $client->getCookieJar()->set(new Cookie($options['name'], $session->getId()));
786
787
            /** @var $user UserInterface */
788 2
            foreach ($this->firewallLogins as $firewallName => $user) {
789 2
                $token = $this->createUserToken($user, $firewallName);
790
791
                // BC: security.token_storage is available on Symfony 2.6+
792
                // see http://symfony.com/blog/new-in-symfony-2-6-security-component-improvements
793 2
                if ($client->getContainer()->has('security.token_storage')) {
794 2
                    $tokenStorage = $client->getContainer()->get('security.token_storage');
795 2
                } else {
796
                    // This block will never be reached with Symfony 2.6+
797
                    // @codeCoverageIgnoreStart
798
                    $tokenStorage = $client->getContainer()->get('security.context');
799
                    // @codeCoverageIgnoreEnd
800
                }
801
802 2
                $tokenStorage->setToken($token);
803 2
                $session->set('_security_'.$firewallName, serialize($token));
804 2
            }
805
806 2
            $session->save();
807 2
        }
808
809 55
        return $client;
810
    }
811
812
    /**
813
     * Create User Token.
814
     *
815
     * Factory method for creating a User Token object for the firewall based on
816
     * the user object provided. By default it will be a Username/Password
817
     * Token based on the user's credentials, but may be overridden for custom
818
     * tokens in your applications.
819
     *
820
     * @param UserInterface $user         The user object to base the token off of
821
     * @param string        $firewallName name of the firewall provider to use
822
     *
823
     * @return TokenInterface The token to be used in the security context
824
     */
825 2
    protected function createUserToken(UserInterface $user, $firewallName)
826
    {
827 2
        return new UsernamePasswordToken(
828 2
            $user,
829 2
            null,
830 2
            $firewallName,
831 2
            $user->getRoles()
0 ignored issues
show
$user->getRoles() is of type array<integer,object<Sym...Core\Role\Role>|string>, but the function expects a array<integer,object<Sym...\RoleInterface>|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...
832 2
        );
833
    }
834
835
    /**
836
     * Extracts the location from the given route.
837
     *
838
     * @param string $route    The name of the route
839
     * @param array  $params   Set of parameters
840
     * @param int    $absolute
841
     *
842
     * @return string
843
     */
844 1
    protected function getUrl($route, $params = array(), $absolute = UrlGeneratorInterface::ABSOLUTE_PATH)
845
    {
846 1
        return $this->getContainer()->get('router')->generate($route, $params, $absolute);
847
    }
848
849
    /**
850
     * Checks the success state of a response.
851
     *
852
     * @param Response $response Response object
853
     * @param bool     $success  to define whether the response is expected to be successful
854
     * @param string   $type
855
     */
856 6
    public function isSuccessful(Response $response, $success = true, $type = 'text/html')
857
    {
858 6
        HttpAssertions::isSuccessful($response, $success, $type);
859 5
    }
860
861
    /**
862
     * Executes a request on the given url and returns the response contents.
863
     *
864
     * This method also asserts the request was successful.
865
     *
866
     * @param string $path           path of the requested page
867
     * @param string $method         The HTTP method to use, defaults to GET
868
     * @param bool   $authentication Whether to use authentication, defaults to false
869
     * @param bool   $success        to define whether the response is expected to be successful
870
     *
871
     * @return string
872
     */
873 1
    public function fetchContent($path, $method = 'GET', $authentication = false, $success = true)
874
    {
875 1
        $client = $this->makeClient($authentication);
876 1
        $client->request($method, $path);
877
878 1
        $content = $client->getResponse()->getContent();
879 1
        if (is_bool($success)) {
880 1
            $this->isSuccessful($client->getResponse(), $success);
881 1
        }
882
883 1
        return $content;
884
    }
885
886
    /**
887
     * Executes a request on the given url and returns a Crawler object.
888
     *
889
     * This method also asserts the request was successful.
890
     *
891
     * @param string $path           path of the requested page
892
     * @param string $method         The HTTP method to use, defaults to GET
893
     * @param bool   $authentication Whether to use authentication, defaults to false
894
     * @param bool   $success        Whether the response is expected to be successful
895
     *
896
     * @return Crawler
897
     */
898 1
    public function fetchCrawler($path, $method = 'GET', $authentication = false, $success = true)
899
    {
900 1
        $client = $this->makeClient($authentication);
901 1
        $crawler = $client->request($method, $path);
902
903 1
        $this->isSuccessful($client->getResponse(), $success);
904
905 1
        return $crawler;
906
    }
907
908
    /**
909
     * @param UserInterface $user
910
     * @param string        $firewallName
911
     *
912
     * @return WebTestCase
913
     */
914 2
    public function loginAs(UserInterface $user, $firewallName)
915
    {
916 2
        $this->firewallLogins[$firewallName] = $user;
917
918 2
        return $this;
919
    }
920
921
    /**
922
     * Asserts that the HTTP response code of the last request performed by
923
     * $client matches the expected code. If not, raises an error with more
924
     * information.
925
     *
926
     * @param $expectedStatusCode
927
     * @param Client $client
928
     */
929 12
    public function assertStatusCode($expectedStatusCode, Client $client)
930
    {
931 12
        HttpAssertions::assertStatusCode($expectedStatusCode, $client);
932 9
    }
933
934
    /**
935
     * Assert that the last validation errors within $container match the
936
     * expected keys.
937
     *
938
     * @param array              $expected  A flat array of field names
939
     * @param ContainerInterface $container
940
     */
941 3
    public function assertValidationErrors(array $expected, ContainerInterface $container)
942
    {
943 3
        HttpAssertions::assertValidationErrors($expected, $container);
944 1
    }
945
946
    /**
947
     * @param array $excludedDoctrineTables
948
     */
949 1
    public function setExcludedDoctrineTables($excludedDoctrineTables)
950
    {
951 1
        $this->excludedDoctrineTables = $excludedDoctrineTables;
952 1
    }
953
}
954