Completed
Pull Request — master (#293)
by Lukas Kahwe
09:43
created

WebTestCase::configureVerbosityForSymfony20301()   B

Complexity

Conditions 5
Paths 5

Size

Total Lines 22
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 30

Importance

Changes 0
Metric Value
dl 0
loc 22
ccs 0
cts 0
cp 0
rs 8.6737
c 0
b 0
f 0
cc 5
eloc 15
nc 5
nop 1
crap 30

1 Method

Rating   Name   Duplication   Size   Complexity  
A WebTestCase::isDecorated() 0 4 1
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 static $cachedMetadatas = array();
69
70
    protected static function getKernelClass()
0 ignored issues
show
Coding Style introduced by
getKernelClass uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
71
    {
72
        $dir = isset($_SERVER['KERNEL_DIR']) ? $_SERVER['KERNEL_DIR'] : static::getPhpUnitXmlDir();
73
74
        list($appname) = explode('\\', get_called_class());
75
76
        $class = $appname.'Kernel';
77
        $file = $dir.'/'.strtolower($appname).'/'.$class.'.php';
78
        if (!file_exists($file)) {
79
            return parent::getKernelClass();
80
        }
81
        require_once $file;
82
83
        return $class;
84
    }
85
86
    /**
87
     * Creates a mock object of a service identified by its id.
88
     *
89
     * @param string $id
90
     *
91
     * @return \PHPUnit_Framework_MockObject_MockBuilder
92
     */
93 2
    protected function getServiceMockBuilder($id)
94
    {
95 2
        $service = $this->getContainer()->get($id);
96
        $class = get_class($service);
97
98
        return $this->getMockBuilder($class)->disableOriginalConstructor();
99
    }
100
101
    /**
102
     * Builds up the environment to run the given command.
103
     *
104
     * @param string $name
105
     * @param array  $params
106
     * @param bool   $reuseKernel
107
     *
108
     * @return string
109
     */
110 12
    protected function runCommand($name, array $params = array(), $reuseKernel = false)
111
    {
112 12
        array_unshift($params, $name);
113
114 12
        if (!$reuseKernel) {
115 12
            if (null !== static::$kernel) {
116 9
                static::$kernel->shutdown();
117 9
            }
118
119 12
            $kernel = static::$kernel = $this->createKernel(array('environment' => $this->environment));
120 12
            $kernel->boot();
121 12
        } else {
122 2
            $kernel = $this->getContainer()->get('kernel');
123
        }
124
125 12
        $application = new Application($kernel);
126 12
        $application->setAutoExit(false);
127
128 12
        $input = new ArrayInput($params);
129 12
        $input->setInteractive(false);
130
131 12
        $fp = fopen('php://temp/maxmemory:'.$this->maxMemory, 'r+');
132 12
        $output = new StreamOutput($fp, $this->getVerbosityLevel(), $this->getDecorated());
133
134 11
        $application->run($input, $output);
135
136 11
        rewind($fp);
137
138 11
        return stream_get_contents($fp);
139
    }
140
141
    /**
142
     * Retrieves the output verbosity level.
143
     *
144
     * @see Symfony\Component\Console\Output\OutputInterface for available levels
145
     *
146
     * @return int
147
     *
148
     * @throws \OutOfBoundsException If the set value isn't accepted
149
     */
150 12
    protected function getVerbosityLevel()
151
    {
152
        // If `null`, is not yet set
153 12
        if (null === $this->verbosityLevel) {
154
            // Set the global verbosity level that is set as NORMAL by the TreeBuilder in Configuration
155 6
            $level = strtoupper($this->getContainer()->getParameter('liip_functional_test.command_verbosity'));
156 6
            $verbosity = '\Symfony\Component\Console\Output\StreamOutput::VERBOSITY_'.$level;
157
158 6
            $this->verbosityLevel = constant($verbosity);
159 6
        }
160
161
        // If string, it is set by the developer, so check that the value is an accepted one
162 12
        if (is_string($this->verbosityLevel)) {
163 6
            $level = strtoupper($this->verbosityLevel);
164 6
            $verbosity = '\Symfony\Component\Console\Output\StreamOutput::VERBOSITY_'.$level;
165
166 6
            if (!defined($verbosity)) {
167 1
                throw new \OutOfBoundsException(
168 1
                    sprintf('The set value "%s" for verbosityLevel is not valid. Accepted are: "quiet", "normal", "verbose", "very_verbose" and "debug".', $level)
169 1
                    );
170
            }
171
172 5
            $this->verbosityLevel = constant($verbosity);
173 5
        }
174
175 11
        return $this->verbosityLevel;
176
    }
177
178 6
    public function setVerbosityLevel($level)
179
    {
180 6
        $this->verbosityLevel = $level;
181 6
    }
182
183
    /**
184
     * Retrieves the flag indicating if the output should be decorated or not.
185
     *
186
     * @return bool
187
     */
188 11
    protected function getDecorated()
189
    {
190 11
        if (null === $this->decorated) {
191
            // Set the global decoration flag that is set to `true` by the TreeBuilder in Configuration
192 5
            $this->decorated = $this->getContainer()->getParameter('liip_functional_test.command_decoration');
193 5
        }
194
195
        // Check the local decorated flag
196 11
        if (false === is_bool($this->decorated)) {
197
            throw new \OutOfBoundsException(
198
                sprintf('`WebTestCase::decorated` has to be `bool`. "%s" given.', gettype($this->decorated))
199
            );
200
        }
201
202 11
        return $this->decorated;
203
    }
204
205 6
    public function isDecorated($decorated)
206
    {
207 6
        $this->decorated = $decorated;
208 6
    }
209
210
    /**
211
     * Get an instance of the dependency injection container.
212
     * (this creates a kernel *without* parameters).
213
     *
214
     * @return ContainerInterface
215
     */
216 45
    protected function getContainer()
0 ignored issues
show
Coding Style introduced by
getContainer uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
217
    {
218 45
        if (!empty($this->kernelDir)) {
219
            $tmpKernelDir = isset($_SERVER['KERNEL_DIR']) ? $_SERVER['KERNEL_DIR'] : null;
220
            $_SERVER['KERNEL_DIR'] = getcwd().$this->kernelDir;
221
        }
222
223 45
        $cacheKey = $this->kernelDir.'|'.$this->environment;
224 45
        if (empty($this->containers[$cacheKey])) {
225
            $options = array(
226 44
                'environment' => $this->environment,
227 44
            );
228 44
            $kernel = $this->createKernel($options);
229 44
            $kernel->boot();
230
231 44
            $this->containers[$cacheKey] = $kernel->getContainer();
232 44
        }
233
234 45
        if (isset($tmpKernelDir)) {
235
            $_SERVER['KERNEL_DIR'] = $tmpKernelDir;
236
        }
237
238 45
        return $this->containers[$cacheKey];
239
    }
240
241
    /**
242
     * This function finds the time when the data blocks of a class definition
243
     * file were being written to, that is, the time when the content of the
244
     * file was changed.
245
     *
246
     * @param string $class The fully qualified class name of the fixture class to
247
     *                      check modification date on
248
     *
249
     * @return \DateTime|null
250
     */
251 3
    protected function getFixtureLastModified($class)
252
    {
253 3
        $lastModifiedDateTime = null;
254
255 3
        $reflClass = new \ReflectionClass($class);
256 3
        $classFileName = $reflClass->getFileName();
257
258 3
        if (file_exists($classFileName)) {
259 3
            $lastModifiedDateTime = new \DateTime();
260 3
            $lastModifiedDateTime->setTimestamp(filemtime($classFileName));
261 3
        }
262
263 3
        return $lastModifiedDateTime;
264
    }
265
266
    /**
267
     * Determine if the Fixtures that define a database backup have been
268
     * modified since the backup was made.
269
     *
270
     * @param array  $classNames The fixture classnames to check
271
     * @param string $backup     The fixture backup SQLite database file path
272
     *
273
     * @return bool TRUE if the backup was made since the modifications to the
274
     *              fixtures; FALSE otherwise
275
     */
276 7
    protected function isBackupUpToDate(array $classNames, $backup)
277
    {
278 7
        $backupLastModifiedDateTime = new \DateTime();
279 7
        $backupLastModifiedDateTime->setTimestamp(filemtime($backup));
280
281
        /** @var \Symfony\Bridge\Doctrine\DataFixtures\ContainerAwareLoader $loader */
282 7
        $loader = $this->getFixtureLoader($this->getContainer(), $classNames);
283
284
        // Use loader in order to fetch all the dependencies fixtures.
285 7
        foreach ($loader->getFixtures() as $className) {
286 3
            $fixtureLastModifiedDateTime = $this->getFixtureLastModified($className);
287 3
            if ($backupLastModifiedDateTime < $fixtureLastModifiedDateTime) {
288 1
                return false;
289
            }
290 7
        }
291
292 7
        return true;
293
    }
294
295
    /**
296
     * Set the database to the provided fixtures.
297
     *
298
     * Drops the current database and then loads fixtures using the specified
299
     * classes. The parameter is a list of fully qualified class names of
300
     * classes that implement Doctrine\Common\DataFixtures\FixtureInterface
301
     * so that they can be loaded by the DataFixtures Loader::addFixture
302
     *
303
     * When using SQLite this method will automatically make a copy of the
304
     * loaded schema and fixtures which will be restored automatically in
305
     * case the same fixture classes are to be loaded again. Caveat: changes
306
     * to references and/or identities may go undetected.
307
     *
308
     * Depends on the doctrine data-fixtures library being available in the
309
     * class path.
310
     *
311
     * @param array  $classNames   List of fully qualified class names of fixtures to load
312
     * @param string $omName       The name of object manager to use
313
     * @param string $registryName The service id of manager registry to use
314
     * @param int    $purgeMode    Sets the ORM purge mode
315
     *
316
     * @return null|AbstractExecutor
317
     */
318 32
    protected function loadFixtures(array $classNames, $omName = null, $registryName = 'doctrine', $purgeMode = null)
319
    {
320 32
        $container = $this->getContainer();
321
        /** @var ManagerRegistry $registry */
322 32
        $registry = $container->get($registryName);
323
        /** @var ObjectManager $om */
324 32
        $om = $registry->getManager($omName);
325 32
        $type = $registry->getName();
326
327 32
        $executorClass = 'PHPCR' === $type && class_exists('Doctrine\Bundle\PHPCRBundle\DataFixtures\PHPCRExecutor')
328 32
            ? 'Doctrine\Bundle\PHPCRBundle\DataFixtures\PHPCRExecutor'
329 32
            : 'Doctrine\\Common\\DataFixtures\\Executor\\'.$type.'Executor';
330 32
        $referenceRepository = new ProxyReferenceRepository($om);
331 32
        $cacheDriver = $om->getMetadataFactory()->getCacheDriver();
332
333 32
        if ($cacheDriver) {
334 32
            $cacheDriver->deleteAll();
335 32
        }
336
337 32
        if ('ORM' === $type) {
338 31
            $connection = $om->getConnection();
339 31
            if ($connection->getDriver() instanceof SqliteDriver) {
340 27
                $params = $connection->getParams();
341 27
                if (isset($params['master'])) {
342
                    $params = $params['master'];
343
                }
344
345 27
                $name = isset($params['path']) ? $params['path'] : (isset($params['dbname']) ? $params['dbname'] : false);
346 27
                if (!$name) {
347
                    throw new \InvalidArgumentException("Connection does not contain a 'path' or 'dbname' parameter and cannot be dropped.");
348
                }
349
350 27
                if (!isset(self::$cachedMetadatas[$omName])) {
351 10
                    self::$cachedMetadatas[$omName] = $om->getMetadataFactory()->getAllMetadata();
352 10
                    usort(self::$cachedMetadatas[$omName], function ($a, $b) {
353
                        return strcmp($a->name, $b->name);
354 10
                    });
355 10
                }
356 27
                $metadatas = self::$cachedMetadatas[$omName];
357
358 27
                if ($container->getParameter('liip_functional_test.cache_sqlite_db')) {
359 9
                    $backup = $container->getParameter('kernel.cache_dir').'/test_'.md5(serialize($metadatas).serialize($classNames)).'.db';
360 9
                    if (file_exists($backup) && file_exists($backup.'.ser') && $this->isBackupUpToDate($classNames, $backup)) {
361 7
                        $om->flush();
362 7
                        $om->clear();
363
364 7
                        $this->preFixtureRestore($om, $referenceRepository);
365
366 7
                        copy($backup, $name);
367
368 7
                        $executor = new $executorClass($om);
369 7
                        $executor->setReferenceRepository($referenceRepository);
370 7
                        $executor->getReferenceRepository()->load($backup);
371
372 7
                        $this->postFixtureRestore();
373
374 7
                        return $executor;
375
                    }
376 3
                }
377
378
                // TODO: handle case when using persistent connections. Fail loudly?
379 21
                $schemaTool = new SchemaTool($om);
0 ignored issues
show
Compatibility introduced by
$om of type object<Doctrine\Common\Persistence\ObjectManager> is not a sub-type of object<Doctrine\ORM\EntityManagerInterface>. It seems like you assume a child interface of the interface Doctrine\Common\Persistence\ObjectManager to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
380 21
                $schemaTool->dropDatabase();
381 21
                if (!empty($metadatas)) {
382 21
                    $schemaTool->createSchema($metadatas);
383 21
                }
384 21
                $this->postFixtureSetup();
385
386 21
                $executor = new $executorClass($om);
387 21
                $executor->setReferenceRepository($referenceRepository);
388 21
            }
389 25
        }
390
391 26
        if (empty($executor)) {
392 5
            $purgerClass = 'Doctrine\\Common\\DataFixtures\\Purger\\'.$type.'Purger';
393 5
            if ('PHPCR' === $type) {
394 1
                $purger = new $purgerClass($om);
395 1
                $initManager = $container->has('doctrine_phpcr.initializer_manager')
396 1
                    ? $container->get('doctrine_phpcr.initializer_manager')
397 1
                    : null;
398
399 1
                $executor = new $executorClass($om, $purger, $initManager);
400 1
            } else {
401 4
                $purger = new $purgerClass();
402 4
                if (null !== $purgeMode) {
403 1
                    $purger->setPurgeMode($purgeMode);
404 1
                }
405
406 4
                $executor = new $executorClass($om, $purger);
407
            }
408
409 5
            $executor->setReferenceRepository($referenceRepository);
410 5
            $executor->purge();
411 5
        }
412
413 26
        $loader = $this->getFixtureLoader($container, $classNames);
414
415 26
        $executor->execute($loader->getFixtures(), true);
416
417 26
        if (isset($name) && isset($backup)) {
418 3
            $this->preReferenceSave($om, $executor, $backup);
419
420 3
            $executor->getReferenceRepository()->save($backup);
421 3
            copy($name, $backup);
422
423 3
            $this->postReferenceSave($om, $executor, $backup);
424 3
        }
425
426 26
        return $executor;
427
    }
428
429
    /**
430
     * Clean database.
431
     *
432
     * @param ManagerRegistry $registry
433
     * @param EntityManager   $om
434
     * @param null            $omName
435
     */
436 6
    private function cleanDatabase(ManagerRegistry $registry, EntityManager $om, $omName = null)
437
    {
438 6
        $connection = $om->getConnection();
439
440 6
        $mysql = ($registry->getName() === 'ORM'
441 6
            && $connection->getDatabasePlatform() instanceof MySqlPlatform);
442
443 6
        if ($mysql) {
444 1
            $connection->query('SET FOREIGN_KEY_CHECKS=0');
445 1
        }
446
447 6
        $this->loadFixtures(array(), $omName);
448
449 6
        if ($mysql) {
450 1
            $connection->query('SET FOREIGN_KEY_CHECKS=1');
451 1
        }
452 6
    }
453
454
    /**
455
     * Locate fixture files.
456
     *
457
     * @param array $paths
458
     *
459
     * @return array $files
460
     */
461 6
    private function locateResources($paths)
462
    {
463 6
        $files = array();
464
465 6
        $kernel = $this->getContainer()->get('kernel');
466
467 6
        foreach ($paths as $path) {
468 6
            if ($path[0] !== '@' && file_exists($path) === true) {
469 1
                $files[] = $path;
470 1
                continue;
471
            }
472
473 5
            $files[] = $kernel->locateResource($path);
474 6
        }
475
476 6
        return $files;
477
    }
478
479
    /**
480
     * @param array  $paths        Either symfony resource locators (@ BundleName/etc) or actual file paths
481
     * @param bool   $append
482
     * @param null   $omName
483
     * @param string $registryName
484
     *
485
     * @return array
486
     *
487
     * @throws \BadMethodCallException
488
     */
489 6
    public function loadFixtureFiles(array $paths = array(), $append = false, $omName = null, $registryName = 'doctrine')
490
    {
491 6
        if (!class_exists('Nelmio\Alice\Fixtures')) {
492
            // This class is available during tests, no exception will be thrown.
493
            // @codeCoverageIgnoreStart
494
            throw new \BadMethodCallException('nelmio/alice should be installed to use this method.');
495
            // @codeCoverageIgnoreEnd
496
        }
497
498
        /** @var ContainerInterface $container */
499 6
        $container = $this->getContainer();
500
501
        /** @var ManagerRegistry $registry */
502 6
        $registry = $container->get($registryName);
503
504
        /** @var EntityManager $om */
505 6
        $om = $registry->getManager($omName);
506
507 6
        if ($append === false) {
508 6
            $this->cleanDatabase($registry, $om, $omName);
509 6
        }
510
511 6
        $files = $this->locateResources($paths);
512
513
        // Check if the Hautelook AliceBundle is registered and if yes, use it instead of Nelmio Alice
514 6
        $hautelookLoaderServiceName = 'hautelook_alice.fixtures.loader';
515 6
        if ($container->has($hautelookLoaderServiceName)) {
516 3
            $loaderService = $container->get($hautelookLoaderServiceName);
517 3
            $persisterClass = class_exists('Nelmio\Alice\ORM\Doctrine') ?
518 3
                'Nelmio\Alice\ORM\Doctrine' :
519 3
                'Nelmio\Alice\Persister\Doctrine';
520
521 3
            return $loaderService->load(new $persisterClass($om), $files);
522
        }
523
524 3
        return Fixtures::load($files, $om);
525
    }
526
527
    /**
528
     * Callback function to be executed after Schema creation.
529
     * Use this to execute acl:init or other things necessary.
530
     */
531 21
    protected function postFixtureSetup()
532
    {
533 21
    }
534
535
    /**
536
     * Callback function to be executed after Schema restore.
537
     *
538
     * @return WebTestCase
539
     */
540 7
    protected function postFixtureRestore()
541
    {
542 7
    }
543
544
    /**
545
     * Callback function to be executed before Schema restore.
546
     *
547
     * @param ObjectManager            $manager             The object manager
548
     * @param ProxyReferenceRepository $referenceRepository The reference repository
549
     *
550
     * @return WebTestCase
551
     */
552 7
    protected function preFixtureRestore(ObjectManager $manager, ProxyReferenceRepository $referenceRepository)
0 ignored issues
show
Unused Code introduced by
The parameter $manager is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $referenceRepository is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
553
    {
554 7
    }
555
556
    /**
557
     * Callback function to be executed after save of references.
558
     *
559
     * @param ObjectManager    $manager        The object manager
560
     * @param AbstractExecutor $executor       Executor of the data fixtures
561
     * @param string           $backupFilePath Path of file used to backup the references of the data fixtures
562
     *
563
     * @return WebTestCase
564
     */
565 3
    protected function postReferenceSave(ObjectManager $manager, AbstractExecutor $executor, $backupFilePath)
0 ignored issues
show
Unused Code introduced by
The parameter $manager is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $executor is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $backupFilePath is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
566
    {
567 3
    }
568
569
    /**
570
     * Callback function to be executed before save of references.
571
     *
572
     * @param ObjectManager    $manager        The object manager
573
     * @param AbstractExecutor $executor       Executor of the data fixtures
574
     * @param string           $backupFilePath Path of file used to backup the references of the data fixtures
575
     *
576
     * @return WebTestCase
577
     */
578 3
    protected function preReferenceSave(ObjectManager $manager, AbstractExecutor $executor, $backupFilePath)
0 ignored issues
show
Unused Code introduced by
The parameter $manager is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $executor is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $backupFilePath is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
579
    {
580 3
    }
581
582
    /**
583
     * Retrieve Doctrine DataFixtures loader.
584
     *
585
     * @param ContainerInterface $container
586
     * @param array              $classNames
587
     *
588
     * @return Loader
589
     */
590 32
    protected function getFixtureLoader(ContainerInterface $container, array $classNames)
591
    {
592 32
        $loaderClass = class_exists('Symfony\Bridge\Doctrine\DataFixtures\ContainerAwareLoader')
593 32
            ? 'Symfony\Bridge\Doctrine\DataFixtures\ContainerAwareLoader'
594 32
            : (class_exists('Doctrine\Bundle\FixturesBundle\Common\DataFixtures\Loader')
595
                // This class is not available during tests.
596
                // @codeCoverageIgnoreStart
597
                ? 'Doctrine\Bundle\FixturesBundle\Common\DataFixtures\Loader'
598
                // @codeCoverageIgnoreEnd
599 32
                : 'Symfony\Bundle\DoctrineFixturesBundle\Common\DataFixtures\Loader');
600
601 32
        $loader = new $loaderClass($container);
602
603 32
        foreach ($classNames as $className) {
604 10
            $this->loadFixtureClass($loader, $className);
605 32
        }
606
607 32
        return $loader;
608
    }
609
610
    /**
611
     * Load a data fixture class.
612
     *
613
     * @param Loader $loader
614
     * @param string $className
615
     */
616 10
    protected function loadFixtureClass($loader, $className)
617
    {
618 10
        $fixture = new $className();
619
620 10
        if ($loader->hasFixture($fixture)) {
621 2
            unset($fixture);
622
623 2
            return;
624
        }
625
626 10
        $loader->addFixture($fixture);
627
628 10
        if ($fixture instanceof DependentFixtureInterface) {
629 2
            foreach ($fixture->getDependencies() as $dependency) {
630 2
                $this->loadFixtureClass($loader, $dependency);
631 2
            }
632 2
        }
633 10
    }
634
635
    /**
636
     * Creates an instance of a lightweight Http client.
637
     *
638
     * If $authentication is set to 'true' it will use the content of
639
     * 'liip_functional_test.authentication' to log in.
640
     *
641
     * $params can be used to pass headers to the client, note that they have
642
     * to follow the naming format used in $_SERVER.
643
     * Example: 'HTTP_X_REQUESTED_WITH' instead of 'X-Requested-With'
644
     *
645
     * @param bool|array $authentication
646
     * @param array      $params
647
     *
648
     * @return Client
649
     */
650 49
    protected function makeClient($authentication = false, array $params = array())
651
    {
652 49
        if ($authentication) {
653 2
            if ($authentication === true) {
654
                $authentication = array(
655 1
                    'username' => $this->getContainer()
656 1
                        ->getParameter('liip_functional_test.authentication.username'),
657 1
                    'password' => $this->getContainer()
658 1
                        ->getParameter('liip_functional_test.authentication.password'),
659 1
                );
660 1
            }
661
662 2
            $params = array_merge($params, array(
663 2
                'PHP_AUTH_USER' => $authentication['username'],
664 2
                'PHP_AUTH_PW' => $authentication['password'],
665 2
            ));
666 2
        }
667
668 49
        $client = static::createClient(array('environment' => $this->environment), $params);
669
670 49
        if ($this->firewallLogins) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->firewallLogins of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
671
            // has to be set otherwise "hasPreviousSession" in Request returns false.
672 2
            $options = $client->getContainer()->getParameter('session.storage.options');
673
674 2
            if (!$options || !isset($options['name'])) {
675
                throw new \InvalidArgumentException('Missing session.storage.options#name');
676
            }
677
678 2
            $session = $client->getContainer()->get('session');
679
            // Since the namespace of the session changed in symfony 2.1, instanceof can be used to check the version.
680 2
            if ($session instanceof Session) {
681 2
                $session->setId(uniqid());
682 2
            }
683
684 2
            $client->getCookieJar()->set(new Cookie($options['name'], $session->getId()));
685
686
            /** @var $user UserInterface */
687 2
            foreach ($this->firewallLogins as $firewallName => $user) {
688 2
                $token = $this->createUserToken($user, $firewallName);
689
690
                // BC: security.token_storage is available on Symfony 2.6+
691
                // see http://symfony.com/blog/new-in-symfony-2-6-security-component-improvements
692 2
                if ($client->getContainer()->has('security.token_storage')) {
693 2
                    $tokenStorage = $client->getContainer()->get('security.token_storage');
694 2
                } else {
695
                    // This block will never be reached with Symfony 2.6+
696
                    // @codeCoverageIgnoreStart
697
                    $tokenStorage = $client->getContainer()->get('security.context');
698
                    // @codeCoverageIgnoreEnd
699
                }
700
701 2
                $tokenStorage->setToken($token);
702 2
                $session->set('_security_'.$firewallName, serialize($token));
703 2
            }
704
705 2
            $session->save();
706 2
        }
707
708 49
        return $client;
709
    }
710
711
    /**
712
     * Create User Token.
713
     *
714
     * Factory method for creating a User Token object for the firewall based on
715
     * the user object provided. By default it will be a Username/Password
716
     * Token based on the user's credentials, but may be overridden for custom
717
     * tokens in your applications.
718
     *
719
     * @param UserInterface $user         The user object to base the token off of
720
     * @param string        $firewallName name of the firewall provider to use
721
     *
722
     * @return TokenInterface The token to be used in the security context
723
     */
724 2
    protected function createUserToken(UserInterface $user, $firewallName)
725
    {
726 2
        return new UsernamePasswordToken(
727 2
            $user,
728 2
            null,
729 2
            $firewallName,
730 2
            $user->getRoles()
731 2
        );
732
    }
733
734
    /**
735
     * Extracts the location from the given route.
736
     *
737
     * @param string $route    The name of the route
738
     * @param array  $params   Set of parameters
739
     * @param int    $absolute
740
     *
741
     * @return string
742
     */
743 1
    protected function getUrl($route, $params = array(), $absolute = UrlGeneratorInterface::ABSOLUTE_PATH)
744
    {
745 1
        return $this->getContainer()->get('router')->generate($route, $params, $absolute);
746
    }
747
748
    /**
749
     * Checks the success state of a response.
750
     *
751
     * @param Response $response Response object
752
     * @param bool     $success  to define whether the response is expected to be successful
753
     * @param string   $type
754
     */
755 6
    public function isSuccessful(Response $response, $success = true, $type = 'text/html')
756
    {
757 6
        HttpAssertions::isSuccessful($response, $success, $type);
758 5
    }
759
760
    /**
761
     * Executes a request on the given url and returns the response contents.
762
     *
763
     * This method also asserts the request was successful.
764
     *
765
     * @param string $path           path of the requested page
766
     * @param string $method         The HTTP method to use, defaults to GET
767
     * @param bool   $authentication Whether to use authentication, defaults to false
768
     * @param bool   $success        to define whether the response is expected to be successful
769
     *
770
     * @return string
771
     */
772 1
    public function fetchContent($path, $method = 'GET', $authentication = false, $success = true)
773
    {
774 1
        $client = $this->makeClient($authentication);
775 1
        $client->request($method, $path);
776
777 1
        $content = $client->getResponse()->getContent();
778 1
        if (is_bool($success)) {
779 1
            $this->isSuccessful($client->getResponse(), $success);
0 ignored issues
show
Documentation introduced by
$client->getResponse() is of type object|null, but the function expects a object<Symfony\Component\HttpFoundation\Response>.

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...
780 1
        }
781
782 1
        return $content;
783
    }
784
785
    /**
786
     * Executes a request on the given url and returns a Crawler object.
787
     *
788
     * This method also asserts the request was successful.
789
     *
790
     * @param string $path           path of the requested page
791
     * @param string $method         The HTTP method to use, defaults to GET
792
     * @param bool   $authentication Whether to use authentication, defaults to false
793
     * @param bool   $success        Whether the response is expected to be successful
794
     *
795
     * @return Crawler
796
     */
797 1
    public function fetchCrawler($path, $method = 'GET', $authentication = false, $success = true)
798
    {
799 1
        $client = $this->makeClient($authentication);
800 1
        $crawler = $client->request($method, $path);
801
802 1
        $this->isSuccessful($client->getResponse(), $success);
0 ignored issues
show
Documentation introduced by
$client->getResponse() is of type object|null, but the function expects a object<Symfony\Component\HttpFoundation\Response>.

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...
803
804 1
        return $crawler;
805
    }
806
807
    /**
808
     * @param UserInterface $user
809
     * @param string        $firewallName
810
     *
811
     * @return WebTestCase
812
     */
813 2
    public function loginAs(UserInterface $user, $firewallName)
814
    {
815 2
        $this->firewallLogins[$firewallName] = $user;
816
817 2
        return $this;
818
    }
819
820
    /**
821
     * Asserts that the HTTP response code of the last request performed by
822
     * $client matches the expected code. If not, raises an error with more
823
     * information.
824
     *
825
     * @param $expectedStatusCode
826
     * @param Client $client
827
     */
828 11
    public function assertStatusCode($expectedStatusCode, Client $client)
829
    {
830 11
        HttpAssertions::assertStatusCode($expectedStatusCode, $client);
831 8
    }
832
833
    /**
834
     * Assert that the last validation errors within $container match the
835
     * expected keys.
836
     *
837
     * @param array              $expected  A flat array of field names
838
     * @param ContainerInterface $container
839
     */
840 2
    public function assertValidationErrors(array $expected, ContainerInterface $container)
841
    {
842 2
        HttpAssertions::assertValidationErrors($expected, $container);
843 1
    }
844
}
845