Skip to content

Commit

Permalink
Update dependencies
Browse files Browse the repository at this point in the history
  • Loading branch information
Matthias Devlamynck committed Feb 28, 2024
1 parent 0bd7ada commit 98dac69
Show file tree
Hide file tree
Showing 20 changed files with 2,383 additions and 2,611 deletions.
235 changes: 151 additions & 84 deletions Kernel/DefaultTestKernel.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,17 @@
use Doctrine\Bundle\DoctrineBundle\DoctrineBundle;
use RichCongress\WebTestBundle\RichCongressWebTestBundle;
use Symfony\Bundle\FrameworkBundle\FrameworkBundle;
use Symfony\Component\Config\Exception\LoaderLoadException;
use Symfony\Component\Config\Loader\LoaderInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Loader\Configurator\AbstractConfigurator;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
use Symfony\Component\DependencyInjection\Loader\PhpFileLoader as ContainerPhpFileLoader;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Bundle\BundleInterface;
use Symfony\Component\HttpKernel\Kernel;
use Symfony\Component\Routing\Loader\Configurator\RoutingConfigurator;
use Symfony\Component\Routing\Loader\PhpFileLoader as RoutingPhpFileLoader;
use Symfony\Component\Routing\RouteCollection;
use Symfony\Component\Routing\RouteCollectionBuilder;

/**
* Class DefaultTestKernel
Expand All @@ -34,16 +37,56 @@ class DefaultTestKernel extends Kernel
RichCongressWebTestBundle::class,
];

/**
* @return array|iterable|\Traversable|BundleInterface[]
*/
public function getConfigurationDir(): ?string
{
return null;
}

public function getBundlesPath(): ?string
{
$configDir = $this->getConfigurationDir();

return $configDir ? $configDir . '/bundles.php' : null;
}

public function getCacheDir(): string
{
if (isset($_SERVER['APP_CACHE_DIR'])) {
return $_SERVER['APP_CACHE_DIR'].'/'.$this->environment;
}

return parent::getCacheDir();
}

public function getBuildDir(): string
{
if (isset($_SERVER['APP_BUILD_DIR'])) {
return $_SERVER['APP_BUILD_DIR'].'/'.$this->environment;
}

return parent::getBuildDir();
}

public function getLogDir(): string
{
return $_SERVER['APP_LOG_DIR'] ?? parent::getLogDir();
}

public function registerBundles(): iterable
{
foreach (static::$defaultBundles as $class) {
yield new $class();
}

foreach ($this->getCustomBundles() as $class => $envs) {
$bundlePath = $this->getBundlesPath();

if ($bundlePath === null) {
return;
}

$contents = require $bundlePath;

foreach ($contents as $class => $envs) {
$appropriateEnv = $envs[$this->environment] ?? $envs['all'] ?? false;
$isAlreadyLoaded = in_array($class, static::$defaultBundles, true);

Expand All @@ -53,105 +96,129 @@ public function registerBundles(): iterable
}
}

protected function getCustomBundles(): array
public function registerContainerConfiguration(LoaderInterface $loader)
{
$configDir = $this->getConfigurationDir();
$loader->load(function (ContainerBuilder $container) use ($loader) {
$container->setParameter('container.dumper.inline_class_loader', true);

$container->loadFromExtension('framework', [
'router' => [
'resource' => 'kernel::loadRoutes',
'type' => 'service',
],
]);

$container->prependExtensionConfig('doctrine', [
'dbal' => [
'connections' => [
'default' => [
'use_savepoints' => true
]
]
],
]);

$kernelClass = str_contains(static::class, "@anonymous\0") ? parent::class : static::class;

if (!$container->hasDefinition('kernel')) {
$container->register('kernel', $kernelClass)
->addTag('controller.service_arguments')
->setAutoconfigured(true)
->setSynthetic(true)
->setPublic(true)
;
}

if ($configDir === null || !file_exists($configDir . '/bundles.php')) {
return [];
}
$kernelDefinition = $container->getDefinition('kernel');
$kernelDefinition->addTag('routing.route_loader');

return require $configDir . '/bundles.php';
}
if ($this instanceof EventSubscriberInterface) {
$kernelDefinition->addTag('kernel.event_subscriber');
}

/**
* @return string|null
*/
public function getConfigurationDir(): ?string
{
return null;
$container->addObjectResource($this);
if (($bundlePath = $this->getBundlesPath()) !== null) {
$container->fileExists($bundlePath);
}

$configureContainer = new \ReflectionMethod($this, 'configureContainer');
$configuratorClass = $configureContainer->getNumberOfParameters() > 0 && ($type = $configureContainer->getParameters()[0]->getType()) instanceof \ReflectionNamedType && !$type->isBuiltin() ? $type->getName() : null;

if ($configuratorClass && !is_a(ContainerConfigurator::class, $configuratorClass, true)) {
$configureContainer->getClosure($this)($container, $loader);

return;
}

$file = (new \ReflectionObject($this))->getFileName();
/* @var ContainerPhpFileLoader $kernelLoader */
$kernelLoader = $loader->getResolver()->resolve($file);
$kernelLoader->setCurrentDir(\dirname($file));
$instanceof = &\Closure::bind(fn &() => $this->instanceof, $kernelLoader, $kernelLoader)();

$valuePreProcessor = AbstractConfigurator::$valuePreProcessor;
AbstractConfigurator::$valuePreProcessor = fn ($value) => $this === $value ? new Reference('kernel') : $value;

try {
$configureContainer->getClosure($this)(new ContainerConfigurator($container, $kernelLoader, $instanceof, $file, $file, $this->getEnvironment()), $loader, $container);
} finally {
$instanceof = [];
$kernelLoader->registerAliasesForSinglyImplementedInterfaces();
AbstractConfigurator::$valuePreProcessor = $valuePreProcessor;
}

$container->setAlias($kernelClass, 'kernel')->setPublic(true);
});
}

/**
* @param LoaderInterface $loader Resource loader.
*
* @return void
*
* @throws \Exception
*/
public function registerContainerConfiguration(LoaderInterface $loader): void
public function loadRoutes(LoaderInterface $loader): RouteCollection
{
$confDir = $this->getConfigurationDir();
$loader->load(
function (ContainerBuilder $containerBuilder) use ($loader) {
$this->configureContainer($containerBuilder, $loader);
$file = (new \ReflectionObject($this))->getFileName();
/* @var RoutingPhpFileLoader $kernelLoader */
$kernelLoader = $loader->getResolver()->resolve($file, 'php');
$kernelLoader->setCurrentDir(\dirname($file));
$collection = new RouteCollection();

$configureRoutes = new \ReflectionMethod($this, 'configureRoutes');
$configureRoutes->getClosure($this)(new RoutingConfigurator($collection, $kernelLoader, $file, $file, $this->getEnvironment()));

foreach ($collection as $route) {
$controller = $route->getDefault('_controller');

if (\is_array($controller) && [0, 1] === array_keys($controller) && $this === $controller[0]) {
$route->setDefault('_controller', ['kernel', $controller[1]]);
} elseif ($controller instanceof \Closure && $this === ($r = new \ReflectionFunction($controller))->getClosureThis() && !str_contains($r->name, '{closure}')) {
$route->setDefault('_controller', ['kernel', $r->name]);
}
);

if ($confDir === null) {
return;
}

$loader->load($confDir . '/{packages}/*' . self::CONFIG_EXTS, 'glob');
$loader->load($confDir . '/{packages}/' . $this->environment . '/**/*' . self::CONFIG_EXTS, 'glob');
$loader->load($confDir . '/{services}' . self::CONFIG_EXTS, 'glob');
$loader->load($confDir . '/{services}_' . $this->environment . self::CONFIG_EXTS, 'glob');
return $collection;
}

/**
* @param ContainerBuilder $container
* @param LoaderInterface $loader
*
* @return void
*/
public function configureContainer(ContainerBuilder $container, LoaderInterface $loader): void
{
$container->setParameter('container.dumper.inline_class_loader', true);

// Configure router
$container->loadFromExtension('framework', [
'router' => [
'resource' => 'kernel::loadRoutes',
'type' => 'service',
],
]);

if (!$container->hasDefinition('kernel')) {
$container->register('kernel', static::class)
->setSynthetic(true)
->setPublic(true);
}

$kernelDefinition = $container->getDefinition('kernel');
$kernelDefinition->addTag('routing.route_loader');
$configDir = $this->getConfigurationDir();

if ($this instanceof EventSubscriberInterface) {
$kernelDefinition->addTag('kernel.event_subscriber');
if ($configDir === null) {
return;
}

$container->addObjectResource($this);
$loader->load($configDir . '/{packages}/*' . self::CONFIG_EXTS, 'glob');
$loader->load($configDir . '/{packages}/' . $this->environment . '/**/*' . self::CONFIG_EXTS, 'glob');
$loader->load($configDir . '/{services}' . self::CONFIG_EXTS, 'glob');
$loader->load($configDir . '/{services}_' . $this->environment . self::CONFIG_EXTS, 'glob');
}

/**
* @param LoaderInterface $loader
*
* @return RouteCollection
*
* @throws LoaderLoadException
*/
public function loadRoutes(LoaderInterface $loader): RouteCollection
public function configureRoutes(RoutingConfigurator $routes): void
{
$routes = new RouteCollectionBuilder($loader);
$confDir = $this->getConfigurationDir();
$configDir = $this->getConfigurationDir();

if ($confDir === null) {
return $routes->build();
if ($configDir === null) {
return;
}

$routes->import($confDir . '/{routes}/' . $this->environment . '/**/*' . self::CONFIG_EXTS, '/', 'glob');
$routes->import($confDir . '/{routes}/*' . self::CONFIG_EXTS, '/', 'glob');
$routes->import($confDir . '/{routes}' . self::CONFIG_EXTS, '/', 'glob');

return $routes->build();
$routes->import($configDir . '/{routes}/' . $this->environment . '/**/*' . self::CONFIG_EXTS);
$routes->import($configDir . '/{routes}/*' . self::CONFIG_EXTS);
$routes->import($configDir . '/{routes}' . self::CONFIG_EXTS);
}
}
4 changes: 2 additions & 2 deletions TestCase/ControllerTestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

namespace RichCongress\WebTestBundle\TestCase;

use RichCongress\TestFramework\TestConfiguration\Annotation\TestConfig;
use RichCongress\TestFramework\TestConfiguration\Attribute\TestConfig;
use RichCongress\WebTestBundle\TestCase\TestTrait\ControllerTestUtilitiesTrait;
use RichCongress\WebTestBundle\TestCase\TestTrait\WebTestAssertionsTrait;

Expand All @@ -12,8 +12,8 @@
* @package RichCongress\WebTestBundle\TestCase
* @author Nicolas Guilloux <[email protected]>
* @copyright 2014 - 2020 RichCongress (https://www.richcongress.com)
* @TestConfig("kernel")
*/
#[TestConfig('kernel')]
abstract class ControllerTestCase extends TestCase
{
use WebTestAssertionsTrait;
Expand Down
26 changes: 25 additions & 1 deletion TestCase/TestTrait/ControllerTestUtilitiesTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,12 @@
use RichCongress\WebTestBundle\Exception\CsrfTokenManagerMissingException;
use RichCongress\WebTestBundle\WebTest\Client;
use Symfony\Bundle\FrameworkBundle\KernelBrowser;
use Symfony\Component\BrowserKit\Cookie;
use Symfony\Component\Form\FormTypeInterface;
use Symfony\Component\HttpFoundation\Exception\SessionNotFoundException;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Session\SessionFactoryInterface;
use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;

/**
Expand All @@ -17,6 +22,8 @@
*/
trait ControllerTestUtilitiesTrait
{
use WithSessionTrait;

/**
* Get the CSRF token from the Type and the Client
*/
Expand All @@ -40,8 +47,25 @@ protected function getCsrfToken(string $intention): string
if ($class !== null) {
$intention = $class->getBlockPrefix() ?? $intention;
}

$requestStack = $this->getService(RequestStack::class);
return $this->withSession(
$this->getClient(),
$requestStack,
$this->getService('session.factory'),
function ($session) use ($requestStack, $csrfTokenManager, $intention) {
$request = new Request();
$request->setSession($session);
$requestStack->push($request);

$csrfToken = (string) $csrfTokenManager->getToken($intention);

$session->save();
$requestStack->pop();

return (string) $csrfTokenManager->getToken($intention);
return $csrfToken;
}
);
}

/**
Expand Down
35 changes: 35 additions & 0 deletions TestCase/TestTrait/WithSessionTrait.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php

namespace RichCongress\WebTestBundle\TestCase\TestTrait;

use RichCongress\WebTestBundle\WebTest\Client;
use Symfony\Component\BrowserKit\Cookie;
use Symfony\Component\HttpFoundation\Exception\SessionNotFoundException;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Session\SessionFactoryInterface;

trait WithSessionTrait
{
private function withSession(Client $client, RequestStack $requestStack, SessionFactoryInterface $sessionFactory, callable $callback): mixed
{
$cookies = $client->getBrowser()->getCookieJar();

try {
$session = $requestStack->getSession();
} catch (SessionNotFoundException $e) {
$session = $sessionFactory->createSession();
}

$cookie = $cookies->get($session->getName());
if ($cookie !== null) {
$session->setId($cookie->getValue());
}

$result = $callback($session);

$cookie = new Cookie($session->getName(), $session->getId());
$cookies->set($cookie);

return $result;
}
}
Loading

0 comments on commit 98dac69

Please sign in to comment.