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