Passed
Pull Request — master (#397)
by
unknown
06:29
created

WebTestCase::locateResources()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 21
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 4

Importance

Changes 0
Metric Value
dl 0
loc 21
ccs 12
cts 12
cp 1
rs 9.0534
c 0
b 0
f 0
cc 4
eloc 11
nc 4
nop 1
crap 4
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 Doctrine\Common\DataFixtures\Executor\AbstractExecutor;
15
use Doctrine\Common\DataFixtures\ProxyReferenceRepository;
16
use Doctrine\Common\Persistence\ObjectManager;
17
use Liip\FunctionalTestBundle\Utils\HttpAssertions;
18
use Symfony\Bundle\FrameworkBundle\Client;
19
use Symfony\Bundle\FrameworkBundle\Console\Application;
20
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase as BaseWebTestCase;
21
use Symfony\Component\BrowserKit\Cookie;
22
use Symfony\Component\Console\Input\ArrayInput;
23
use Symfony\Component\Console\Output\StreamOutput;
24
use Symfony\Component\DependencyInjection\ContainerInterface;
25
use Symfony\Component\DomCrawler\Crawler;
26
use Symfony\Component\HttpFoundation\Response;
27
use Symfony\Component\HttpFoundation\Session\Session;
28
use Symfony\Component\HttpKernel\KernelInterface;
29
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
30
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
31
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
32
use Symfony\Component\Security\Core\User\UserInterface;
33
34
/**
35
 * @author Lea Haensenberger
36
 * @author Lukas Kahwe Smith <[email protected]>
37
 * @author Benjamin Eberlei <[email protected]>
38
 */
39
abstract class WebTestCase extends BaseWebTestCase
40
{
41
    protected $environment = 'test';
42
43
    protected $containers;
44
45
    protected $kernelDir;
46
47
    // 5 * 1024 * 1024 KB
48
    protected $maxMemory = 5242880;
49
50
    // RUN COMMAND
51
    protected $verbosityLevel;
52
53
    protected $decorated;
54
55
    /**
56
     * @var array
57
     */
58
    private $firewallLogins = [];
59
60
    /**
61
     * @var array
62
     */
63
    private $excludedDoctrineTables = [];
64
65 1
    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...
66
    {
67
        $dir = isset($_SERVER['KERNEL_DIR']) ? $_SERVER['KERNEL_DIR'] : static::getPhpUnitXmlDir();
0 ignored issues
show
Deprecated Code introduced by
The method Symfony\Bundle\Framework...ase::getPhpUnitXmlDir() has been deprecated with message: since 3.4 and will be removed in 4.0.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
68
69
        list($appname) = explode('\\', get_called_class());
70
71 1
        $class = $appname.'Kernel';
72
        $file = $dir.'/'.strtolower($appname).'/'.$class.'.php';
73 1
        if (!file_exists($file)) {
74
            return parent::getKernelClass();
75
        }
76
        require_once $file;
77
78
        return $class;
79
    }
80
81
    /**
82
     * Creates a mock object of a service identified by its id.
83
     *
84
     * @param string $id
85
     *
86
     * @return \PHPUnit_Framework_MockObject_MockBuilder
87
     */
88
    protected function getServiceMockBuilder($id)
89
    {
90
        $service = $this->getContainer()->get($id);
91
        $class = get_class($service);
92
93
        return $this->getMockBuilder($class)->disableOriginalConstructor();
94
    }
95
96
    /**
97
     * Builds up the environment to run the given command.
98
     *
99
     * @param string $name
100
     * @param array  $params
101
     * @param bool   $reuseKernel
102
     *
103
     * @return string
104
     */
105 12
    protected function runCommand($name, array $params = [], $reuseKernel = false)
106
    {
107 12
        array_unshift($params, $name);
108
109 12
        if (!$reuseKernel) {
110 12
            if (null !== static::$kernel) {
111 9
                static::$kernel->shutdown();
112 9
            }
113
114 12
            $kernel = static::$kernel = $this->createKernel(['environment' => $this->environment]);
115 12
            $kernel->boot();
116 12
        } else {
117 2
            $kernel = $this->getContainer()->get('kernel');
118
        }
119
120 12
        $application = $this->createApplication($kernel);
121
122 12
        $input = new ArrayInput($params);
123 12
        $input->setInteractive(false);
124
125 12
        $fp = fopen('php://temp/maxmemory:'.$this->maxMemory, 'r+');
126 12
        $verbosityLevel = $this->getVerbosityLevel();
127
128 11
        $this->setVerbosityLevelEnv($verbosityLevel);
129 11
        $output = new StreamOutput($fp, $verbosityLevel, $this->getDecorated());
130
131 11
        $application->run($input, $output);
132
133 11
        rewind($fp);
134
135 11
        return stream_get_contents($fp);
136
    }
137
138
    /**
139
     * @param KernelInterface $kernel
140
     *
141
     * @return Application
142
     */
143 12
    protected function createApplication(KernelInterface $kernel)
144
    {
145 12
        $application = new Application($kernel);
146 12
        $application->setAutoExit(false);
147
148 12
        return $application;
149
    }
150
151
    /**
152
     * Retrieves the output verbosity level.
153
     *
154
     * @see \Symfony\Component\Console\Output\OutputInterface for available levels
155
     *
156
     * @throws \OutOfBoundsException If the set value isn't accepted
157
     *
158
     * @return int
159
     */
160 12
    protected function getVerbosityLevel()
161 3
    {
162
        // If `null`, is not yet set
163 12
        if (null === $this->verbosityLevel) {
164
            // Set the global verbosity level that is set as NORMAL by the TreeBuilder in Configuration
165 6
            $level = strtoupper($this->getContainer()->getParameter('liip_functional_test.command_verbosity'));
166 6
            $verbosity = '\Symfony\Component\Console\Output\StreamOutput::VERBOSITY_'.$level;
167
168 6
            $this->verbosityLevel = constant($verbosity);
169 6
        }
170
171
        // If string, it is set by the developer, so check that the value is an accepted one
172 12
        if (is_string($this->verbosityLevel)) {
173 6
            $level = strtoupper($this->verbosityLevel);
174 6
            $verbosity = '\Symfony\Component\Console\Output\StreamOutput::VERBOSITY_'.$level;
175
176 6
            if (!defined($verbosity)) {
177 1
                throw new \OutOfBoundsException(
178 1
                    sprintf('The set value "%s" for verbosityLevel is not valid. Accepted are: "quiet", "normal", "verbose", "very_verbose" and "debug".', $level)
179 1
                );
180
            }
181
182 5
            $this->verbosityLevel = constant($verbosity);
183 5
        }
184
185 11
        return $this->verbosityLevel;
186
    }
187
188 6
    public function setVerbosityLevel($level)
189
    {
190 6
        $this->verbosityLevel = $level;
191 6
    }
192
193
    /**
194
     * Set verbosity for Symfony 3.4+.
195
     *
196
     * @see https://github.com/symfony/symfony/pull/24425
197
     *
198
     * @param $level
199
     */
200 11
    private function setVerbosityLevelEnv($level)
201
    {
202 11
        putenv('SHELL_VERBOSITY='.$level);
203 11
    }
204
205
    /**
206
     * Retrieves the flag indicating if the output should be decorated or not.
207
     *
208
     * @return bool
209
     */
210 11
    protected function getDecorated()
211
    {
212 11
        if (null === $this->decorated) {
213
            // Set the global decoration flag that is set to `true` by the TreeBuilder in Configuration
214 5
            $this->decorated = $this->getContainer()->getParameter('liip_functional_test.command_decoration');
215 5
        }
216
217
        // Check the local decorated flag
218 11
        if (false === is_bool($this->decorated)) {
219
            throw new \OutOfBoundsException(
220
                sprintf('`WebTestCase::decorated` has to be `bool`. "%s" given.', gettype($this->decorated))
221
            );
222
        }
223
224 11
        return $this->decorated;
225
    }
226
227 6
    public function isDecorated($decorated)
228
    {
229 6
        $this->decorated = $decorated;
230 6
    }
231
232
    /**
233
     * Get an instance of the dependency injection container.
234
     * (this creates a kernel *without* parameters).
235
     *
236
     * @return ContainerInterface
237
     */
238 49
    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...
239
    {
240 49
        if (!empty($this->kernelDir)) {
241
            $tmpKernelDir = isset($_SERVER['KERNEL_DIR']) ? $_SERVER['KERNEL_DIR'] : null;
242
            $_SERVER['KERNEL_DIR'] = getcwd().$this->kernelDir;
243
        }
244
245 49
        $cacheKey = $this->kernelDir.'|'.$this->environment;
246 49
        if (empty($this->containers[$cacheKey])) {
247
            $options = [
248 48
                'environment' => $this->environment,
249 48
            ];
250 48
            $kernel = $this->createKernel($options);
251 48
            $kernel->boot();
252
253 48
            $this->containers[$cacheKey] = $kernel->getContainer();
254 48
        }
255
256 49
        if (isset($tmpKernelDir)) {
257
            $_SERVER['KERNEL_DIR'] = $tmpKernelDir;
258
        }
259
260 49
        return $this->containers[$cacheKey];
261
    }
262
263
    /**
264
     * Set the database to the provided fixtures.
265
     *
266
     * Drops the current database and then loads fixtures using the specified
267
     * classes. The parameter is a list of fully qualified class names of
268
     * classes that implement Doctrine\Common\DataFixtures\FixtureInterface
269
     * so that they can be loaded by the DataFixtures Loader::addFixture
270
     *
271
     * When using SQLite this method will automatically make a copy of the
272
     * loaded schema and fixtures which will be restored automatically in
273
     * case the same fixture classes are to be loaded again. Caveat: changes
274
     * to references and/or identities may go undetected.
275
     *
276
     * Depends on the doctrine data-fixtures library being available in the
277
     * class path.
278
     *
279
     * @param array  $classNames   List of fully qualified class names of fixtures to load
280
     * @param string $omName       The name of object manager to use
281
     * @param string $registryName The service id of manager registry to use
282
     * @param int    $purgeMode    Sets the ORM purge mode
283
     *
284
     * @return null|AbstractExecutor
285
     */
286 26 View Code Duplication
    protected function loadFixtures(array $classNames, $omName = null, $registryName = 'doctrine', $purgeMode = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
287
    {
288 26
        $container = $this->getContainer();
289
290 26
        $dbToolCollection = $container->get('liip_functional_test.services.database_tool_collection');
291 26
        $dbTool = $dbToolCollection->get($omName, $registryName, $purgeMode, $this);
292 26
        $dbTool->setExcludedDoctrineTables($this->excludedDoctrineTables);
293
294 26
        return $dbTool->loadFixtures($classNames);
295
    }
296
297
    /**
298
     * @param array  $paths        Either symfony resource locators (@ BundleName/etc) or actual file paths
299
     * @param bool   $append
300
     * @param null   $omName
301
     * @param string $registryName
302
     * @param int    $purgeMode
303
     *
304
     * @throws \BadMethodCallException
305
     *
306
     * @return array
307
     */
308 10 View Code Duplication
    public function loadFixtureFiles(array $paths = [], $append = false, $omName = null, $registryName = 'doctrine', $purgeMode = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
309
    {
310
        /** @var ContainerInterface $container */
311 10
        $container = $this->getContainer();
312
313 10
        $dbToolCollection = $container->get('liip_functional_test.services.database_tool_collection');
314 10
        $dbTool = $dbToolCollection->get($omName, $registryName, $purgeMode, $this);
315 10
        $dbTool->setExcludedDoctrineTables($this->excludedDoctrineTables);
316
317 10
        return $dbTool->loadAliceFixture($paths, $append);
318
    }
319
320
    /**
321
     * Callback function to be executed after Schema creation.
322
     * Use this to execute acl:init or other things necessary.
323
     */
324 23
    public function postFixtureSetup()
325
    {
326 23
    }
327
328
    /**
329
     * Callback function to be executed after Schema restore.
330
     *
331
     * @return WebTestCase
332
     *
333
     * @deprecated since version 1.8, to be removed in 2.0. Use postFixtureBackupRestore method instead.
334
     */
335 6
    public function postFixtureRestore()
336
    {
337 6
    }
338
339
    /**
340
     * Callback function to be executed before Schema restore.
341
     *
342
     * @param ObjectManager            $manager             The object manager
343
     * @param ProxyReferenceRepository $referenceRepository The reference repository
344
     *
345
     * @return WebTestCase
346
     *
347
     * @deprecated since version 1.8, to be removed in 2.0. Use preFixtureBackupRestore method instead.
348
     */
349 6
    public 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...
350
    {
351 6
    }
352
353
    /**
354
     * Callback function to be executed after Schema restore.
355
     *
356
     * @param string $backupFilePath Path of file used to backup the references of the data fixtures
357
     *
358
     * @return WebTestCase
359
     */
360 6
    public function postFixtureBackupRestore($backupFilePath)
0 ignored issues
show
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...
361
    {
362 6
        $this->postFixtureRestore();
0 ignored issues
show
Deprecated Code introduced by
The method Liip\FunctionalTestBundl...e::postFixtureRestore() has been deprecated with message: since version 1.8, to be removed in 2.0. Use postFixtureBackupRestore method instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
363
364 6
        return $this;
365
    }
366
367
    /**
368
     * Callback function to be executed before Schema restore.
369
     *
370
     * @param ObjectManager            $manager             The object manager
371
     * @param ProxyReferenceRepository $referenceRepository The reference repository
372
     * @param string                   $backupFilePath      Path of file used to backup the references of the data fixtures
373
     *
374
     * @return WebTestCase
375
     */
376 6
    public function preFixtureBackupRestore(
377
        ObjectManager $manager,
378
        ProxyReferenceRepository $referenceRepository,
379
        $backupFilePath
0 ignored issues
show
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...
380
    ) {
381 6
        $this->preFixtureRestore($manager, $referenceRepository);
0 ignored issues
show
Deprecated Code introduced by
The method Liip\FunctionalTestBundl...se::preFixtureRestore() has been deprecated with message: since version 1.8, to be removed in 2.0. Use preFixtureBackupRestore method instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
382
383 6
        return $this;
384
    }
385
386
    /**
387
     * Callback function to be executed after save of references.
388
     *
389
     * @param ObjectManager    $manager        The object manager
390
     * @param AbstractExecutor $executor       Executor of the data fixtures
391
     * @param string           $backupFilePath Path of file used to backup the references of the data fixtures
392
     *
393
     * @return WebTestCase
394
     */
395 2
    public 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...
396
    {
397 2
    }
398
399
    /**
400
     * Callback function to be executed before save of references.
401
     *
402
     * @param ObjectManager    $manager        The object manager
403
     * @param AbstractExecutor $executor       Executor of the data fixtures
404
     * @param string           $backupFilePath Path of file used to backup the references of the data fixtures
405
     *
406
     * @return WebTestCase
407
     */
408 2
    public 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...
409
    {
410 2
    }
411
412
    /**
413
     * Creates an instance of a lightweight Http client.
414
     *
415
     * If $authentication is set to 'true' it will use the content of
416
     * 'liip_functional_test.authentication' to log in.
417
     *
418
     * $params can be used to pass headers to the client, note that they have
419
     * to follow the naming format used in $_SERVER.
420
     * Example: 'HTTP_X_REQUESTED_WITH' instead of 'X-Requested-With'
421
     *
422
     * @param bool|array $authentication
423
     * @param array      $params
424
     *
425
     * @return Client
426
     */
427 58
    protected function makeClient($authentication = false, array $params = [])
428
    {
429 58
        if ($authentication) {
430 2
            if (true === $authentication) {
431
                $authentication = [
432 1
                    'username' => $this->getContainer()
433 1
                        ->getParameter('liip_functional_test.authentication.username'),
434 1
                    'password' => $this->getContainer()
435 1
                        ->getParameter('liip_functional_test.authentication.password'),
436 1
                ];
437 1
            }
438
439 2
            $params = array_merge($params, [
440 2
                'PHP_AUTH_USER' => $authentication['username'],
441 2
                'PHP_AUTH_PW' => $authentication['password'],
442 2
            ]);
443 2
        }
444
445 58
        $client = static::createClient(['environment' => $this->environment], $params);
446
447 58
        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...
448
            // has to be set otherwise "hasPreviousSession" in Request returns false.
449 2
            $options = $client->getContainer()->getParameter('session.storage.options');
450
451 2
            if (!$options || !isset($options['name'])) {
452
                throw new \InvalidArgumentException('Missing session.storage.options#name');
453
            }
454
455 2
            $session = $client->getContainer()->get('session');
456
            // Since the namespace of the session changed in symfony 2.1, instanceof can be used to check the version.
457 2
            if ($session instanceof Session) {
458 2
                $session->setId(uniqid());
459 2
            }
460
461 2
            $client->getCookieJar()->set(new Cookie($options['name'], $session->getId()));
462
463
            /** @var $user UserInterface */
464 2
            foreach ($this->firewallLogins as $firewallName => $user) {
465 2
                $token = $this->createUserToken($user, $firewallName);
466
467
                // BC: security.token_storage is available on Symfony 2.6+
468
                // see http://symfony.com/blog/new-in-symfony-2-6-security-component-improvements
469 2
                if ($client->getContainer()->has('security.token_storage')) {
470 2
                    $tokenStorage = $client->getContainer()->get('security.token_storage');
471 2
                } else {
472
                    // This block will never be reached with Symfony 2.6+
473
                    // @codeCoverageIgnoreStart
474
                    $tokenStorage = $client->getContainer()->get('security.context');
475
                    // @codeCoverageIgnoreEnd
476
                }
477
478 2
                $tokenStorage->setToken($token);
479 2
                $session->set('_security_'.$firewallName, serialize($token));
480 2
            }
481
482 2
            $session->save();
483 2
        }
484
485 58
        return $client;
486
    }
487
488
    /**
489
     * Create User Token.
490
     *
491
     * Factory method for creating a User Token object for the firewall based on
492
     * the user object provided. By default it will be a Username/Password
493
     * Token based on the user's credentials, but may be overridden for custom
494
     * tokens in your applications.
495
     *
496
     * @param UserInterface $user         The user object to base the token off of
497
     * @param string        $firewallName name of the firewall provider to use
498
     *
499
     * @return TokenInterface The token to be used in the security context
500
     */
501 2
    protected function createUserToken(UserInterface $user, $firewallName)
502
    {
503 2
        return new UsernamePasswordToken(
504 2
            $user,
505 2
            null,
506 2
            $firewallName,
507 2
            $user->getRoles()
0 ignored issues
show
Documentation introduced by
$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...
508 2
        );
509
    }
510
511
    /**
512
     * Extracts the location from the given route.
513
     *
514
     * @param string $route    The name of the route
515
     * @param array  $params   Set of parameters
516
     * @param int    $absolute
517
     *
518
     * @return string
519
     */
520 1
    protected function getUrl($route, $params = [], $absolute = UrlGeneratorInterface::ABSOLUTE_PATH)
521
    {
522 1
        return $this->getContainer()->get('router')->generate($route, $params, $absolute);
523
    }
524
525
    /**
526
     * Checks the success state of a response.
527
     *
528
     * @param Response $response Response object
529
     * @param bool     $success  to define whether the response is expected to be successful
530
     * @param string   $type
531
     */
532 6
    public function isSuccessful(Response $response, $success = true, $type = 'text/html')
533
    {
534 6
        HttpAssertions::isSuccessful($response, $success, $type);
535 5
    }
536
537
    /**
538
     * Executes a request on the given url and returns the response contents.
539
     *
540
     * This method also asserts the request was successful.
541
     *
542
     * @param string $path           path of the requested page
543
     * @param string $method         The HTTP method to use, defaults to GET
544
     * @param bool   $authentication Whether to use authentication, defaults to false
545
     * @param bool   $success        to define whether the response is expected to be successful
546
     *
547
     * @return string
548
     */
549 1
    public function fetchContent($path, $method = 'GET', $authentication = false, $success = true)
550
    {
551 1
        $client = $this->makeClient($authentication);
552 1
        $client->request($method, $path);
553
554 1
        $content = $client->getResponse()->getContent();
555 1
        if (is_bool($success)) {
556 1
            $this->isSuccessful($client->getResponse(), $success);
0 ignored issues
show
Bug introduced by
It seems like $client->getResponse() can be null; however, isSuccessful() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
557 1
        }
558
559 1
        return $content;
560
    }
561
562
    /**
563
     * Executes a request on the given url and returns a Crawler object.
564
     *
565
     * This method also asserts the request was successful.
566
     *
567
     * @param string $path           path of the requested page
568
     * @param string $method         The HTTP method to use, defaults to GET
569
     * @param bool   $authentication Whether to use authentication, defaults to false
570
     * @param bool   $success        Whether the response is expected to be successful
571
     *
572
     * @return Crawler
573
     */
574 1
    public function fetchCrawler($path, $method = 'GET', $authentication = false, $success = true)
575
    {
576 1
        $client = $this->makeClient($authentication);
577 1
        $crawler = $client->request($method, $path);
578
579 1
        $this->isSuccessful($client->getResponse(), $success);
0 ignored issues
show
Bug introduced by
It seems like $client->getResponse() can be null; however, isSuccessful() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
580
581 1
        return $crawler;
582
    }
583
584
    /**
585
     * @param UserInterface $user
586
     * @param string        $firewallName
587
     *
588
     * @return WebTestCase
589
     */
590 2
    public function loginAs(UserInterface $user, $firewallName)
591
    {
592 2
        $this->firewallLogins[$firewallName] = $user;
593
594 2
        return $this;
595
    }
596
597
    /**
598
     * Asserts that the HTTP response code of the last request performed by
599
     * $client matches the expected code. If not, raises an error with more
600
     * information.
601
     *
602
     * @param $expectedStatusCode
603
     * @param Client $client
604
     */
605 12
    public function assertStatusCode($expectedStatusCode, Client $client)
606
    {
607 12
        HttpAssertions::assertStatusCode($expectedStatusCode, $client);
608 9
    }
609
610
    /**
611
     * Assert that the last validation errors within $container match the
612
     * expected keys.
613
     *
614
     * @param array              $expected  A flat array of field names
615
     * @param ContainerInterface $container
616
     */
617 3
    public function assertValidationErrors(array $expected, ContainerInterface $container)
618
    {
619 3
        HttpAssertions::assertValidationErrors($expected, $container);
620 1
    }
621
622 1
    public function setExcludedDoctrineTables(array $excludedDoctrineTables)
623
    {
624 1
        $this->excludedDoctrineTables = $excludedDoctrineTables;
625 1
    }
626
}
627