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