[FrameworkBundle][Routing] added Configurators to handle template and redirect controllers
This commit is contained in:
parent
9bfa25869a
commit
de74794acf
@ -4,6 +4,7 @@ CHANGELOG
|
|||||||
5.1.0
|
5.1.0
|
||||||
-----
|
-----
|
||||||
|
|
||||||
|
* Added `Routing\Loader` and `Routing\Loader\Configurator` namespaces to ease defining routes with default controllers
|
||||||
* Added the `framework.router.context` configuration node to configure the `RequestContext`
|
* Added the `framework.router.context` configuration node to configure the `RequestContext`
|
||||||
* Made `MicroKernelTrait::configureContainer()` compatible with `ContainerConfigurator`
|
* Made `MicroKernelTrait::configureContainer()` compatible with `ContainerConfigurator`
|
||||||
* Added a new `mailer.message_bus` option to configure or disable the message bus to use to send mails.
|
* Added a new `mailer.message_bus` option to configure or disable the message bus to use to send mails.
|
||||||
|
@ -11,14 +11,14 @@
|
|||||||
|
|
||||||
namespace Symfony\Bundle\FrameworkBundle\Kernel;
|
namespace Symfony\Bundle\FrameworkBundle\Kernel;
|
||||||
|
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Routing\Loader\Configurator\RoutingConfigurator;
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Routing\Loader\PhpFileLoader as RoutingPhpFileLoader;
|
||||||
use Symfony\Component\Config\Loader\LoaderInterface;
|
use Symfony\Component\Config\Loader\LoaderInterface;
|
||||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||||
use Symfony\Component\DependencyInjection\Loader\Configurator\AbstractConfigurator;
|
use Symfony\Component\DependencyInjection\Loader\Configurator\AbstractConfigurator;
|
||||||
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
|
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
|
||||||
use Symfony\Component\DependencyInjection\Loader\PhpFileLoader as ContainerPhpFileLoader;
|
use Symfony\Component\DependencyInjection\Loader\PhpFileLoader as ContainerPhpFileLoader;
|
||||||
use Symfony\Component\DependencyInjection\Reference;
|
use Symfony\Component\DependencyInjection\Reference;
|
||||||
use Symfony\Component\Routing\Loader\Configurator\RoutingConfigurator;
|
|
||||||
use Symfony\Component\Routing\Loader\PhpFileLoader as RoutingPhpFileLoader;
|
|
||||||
use Symfony\Component\Routing\RouteCollection;
|
use Symfony\Component\Routing\RouteCollection;
|
||||||
use Symfony\Component\Routing\RouteCollectionBuilder;
|
use Symfony\Component\Routing\RouteCollectionBuilder;
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
<argument type="service" id="file_locator" />
|
<argument type="service" id="file_locator" />
|
||||||
</service>
|
</service>
|
||||||
|
|
||||||
<service id="routing.loader.php" class="Symfony\Component\Routing\Loader\PhpFileLoader">
|
<service id="routing.loader.php" class="Symfony\Bundle\FrameworkBundle\Routing\Loader\PhpFileLoader">
|
||||||
<tag name="routing.loader" />
|
<tag name="routing.loader" />
|
||||||
<argument type="service" id="file_locator" />
|
<argument type="service" id="file_locator" />
|
||||||
</service>
|
</service>
|
||||||
|
@ -0,0 +1,33 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Bundle\FrameworkBundle\Routing\Loader\Configurator;
|
||||||
|
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Routing\Loader\Configurator\Traits\AddTrait;
|
||||||
|
use Symfony\Component\Routing\Loader\Configurator\RouteConfigurator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Nicolas Grekas <p@tchwork.com>
|
||||||
|
*/
|
||||||
|
class GoneRouteConfigurator extends RouteConfigurator
|
||||||
|
{
|
||||||
|
use AddTrait;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param bool $permanent Whether the redirection is permanent
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
final public function permanent(bool $permanent = true)
|
||||||
|
{
|
||||||
|
return $this->defaults(['permanent' => $permanent]);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,63 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Bundle\FrameworkBundle\Routing\Loader\Configurator;
|
||||||
|
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Routing\Loader\Configurator\Traits\AddTrait;
|
||||||
|
use Symfony\Component\Routing\Loader\Configurator\RouteConfigurator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Jules Pietri <jules@heahprod.com>
|
||||||
|
*/
|
||||||
|
class RedirectRouteConfigurator extends RouteConfigurator
|
||||||
|
{
|
||||||
|
use AddTrait;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param bool $permanent Whether the redirection is permanent
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
final public function permanent(bool $permanent = true)
|
||||||
|
{
|
||||||
|
return $this->defaults(['permanent' => $permanent]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param bool|array $ignoreAttributes Whether to ignore attributes or an array of attributes to ignore
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
final public function ignoreAttributes($ignoreAttributes = true)
|
||||||
|
{
|
||||||
|
return $this->defaults(['ignoreAttributes' => $ignoreAttributes]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param bool $keepRequestMethod Whether redirect action should keep HTTP request method
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
final public function keepRequestMethod(bool $keepRequestMethod = true)
|
||||||
|
{
|
||||||
|
return $this->defaults(['keepRequestMethod' => $keepRequestMethod]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param bool $keepQueryParams Whether redirect action should keep query parameters
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
final public function keepQueryParams(bool $keepQueryParams = true)
|
||||||
|
{
|
||||||
|
return $this->defaults(['keepQueryParams' => $keepQueryParams]);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,73 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Bundle\FrameworkBundle\Routing\Loader\Configurator;
|
||||||
|
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Controller\RedirectController;
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Controller\TemplateController;
|
||||||
|
use Symfony\Component\Routing\Loader\Configurator\RouteConfigurator as BaseRouteConfigurator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Jules Pietri <jules@heahprod.com>
|
||||||
|
*/
|
||||||
|
class RouteConfigurator extends BaseRouteConfigurator
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @param string $template The template name
|
||||||
|
* @param array $context The template variables
|
||||||
|
*/
|
||||||
|
final public function template(string $template, array $context = []): TemplateRouteConfigurator
|
||||||
|
{
|
||||||
|
return (new TemplateRouteConfigurator($this->collection, $this->route, $this->name, $this->parentConfigurator, $this->prefixes))
|
||||||
|
->defaults([
|
||||||
|
'_controller' => TemplateController::class,
|
||||||
|
'template' => $template,
|
||||||
|
'context' => $context,
|
||||||
|
])
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $route The route name to redirect to
|
||||||
|
*/
|
||||||
|
final public function redirectToRoute(string $route): RedirectRouteConfigurator
|
||||||
|
{
|
||||||
|
return (new RedirectRouteConfigurator($this->collection, $this->route, $this->name, $this->parentConfigurator, $this->prefixes))
|
||||||
|
->defaults([
|
||||||
|
'_controller' => RedirectController::class.'::redirectAction',
|
||||||
|
'route' => $route,
|
||||||
|
])
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $url The relative path or URL to redirect to
|
||||||
|
*/
|
||||||
|
final public function redirectToUrl(string $url): UrlRedirectRouteConfigurator
|
||||||
|
{
|
||||||
|
return (new UrlRedirectRouteConfigurator($this->collection, $this->route, $this->name, $this->parentConfigurator, $this->prefixes))
|
||||||
|
->defaults([
|
||||||
|
'_controller' => RedirectController::class.'::urlRedirectAction',
|
||||||
|
'path' => $url,
|
||||||
|
])
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
final public function gone(): GoneRouteConfigurator
|
||||||
|
{
|
||||||
|
return (new GoneRouteConfigurator($this->collection, $this->route, $this->name, $this->parentConfigurator, $this->prefixes))
|
||||||
|
->defaults([
|
||||||
|
'_controller' => RedirectController::class.'::redirectAction',
|
||||||
|
'route' => '',
|
||||||
|
])
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Bundle\FrameworkBundle\Routing\Loader\Configurator;
|
||||||
|
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Routing\Loader\Configurator\Traits\AddTrait;
|
||||||
|
use Symfony\Component\Routing\Loader\Configurator\RoutingConfigurator as BaseRoutingConfigurator;
|
||||||
|
|
||||||
|
class RoutingConfigurator extends BaseRoutingConfigurator
|
||||||
|
{
|
||||||
|
use AddTrait;
|
||||||
|
}
|
@ -0,0 +1,53 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Bundle\FrameworkBundle\Routing\Loader\Configurator;
|
||||||
|
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Routing\Loader\Configurator\Traits\AddTrait;
|
||||||
|
use Symfony\Component\Routing\Loader\Configurator\RouteConfigurator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Jules Pietri <jules@heahprod.com>
|
||||||
|
*/
|
||||||
|
class TemplateRouteConfigurator extends RouteConfigurator
|
||||||
|
{
|
||||||
|
use AddTrait;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int|null $maxAge Max age for client caching
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
final public function maxAge(?int $maxAge)
|
||||||
|
{
|
||||||
|
return $this->defaults(['maxAge' => $maxAge]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int|null $sharedMaxAge Max age for shared (proxy) caching
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
final public function sharedMaxAge(?int $sharedMaxAge)
|
||||||
|
{
|
||||||
|
return $this->defaults(['sharedAge' => $sharedMaxAge]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param bool|null $private Whether or not caching should apply for client caches only
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
final public function private(?bool $private = true)
|
||||||
|
{
|
||||||
|
return $this->defaults(['private' => $private]);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,46 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Bundle\FrameworkBundle\Routing\Loader\Configurator\Traits;
|
||||||
|
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Routing\Loader\Configurator\RouteConfigurator;
|
||||||
|
use Symfony\Component\Routing\Loader\Configurator\CollectionConfigurator;
|
||||||
|
use Symfony\Component\Routing\Loader\Configurator\RouteConfigurator as BaseRouteConfigurator;
|
||||||
|
|
||||||
|
trait AddTrait
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Adds a route.
|
||||||
|
*
|
||||||
|
* @param string|array $path the path, or the localized paths of the route
|
||||||
|
*
|
||||||
|
* @return RouteConfigurator
|
||||||
|
*/
|
||||||
|
public function add(string $name, $path): BaseRouteConfigurator
|
||||||
|
{
|
||||||
|
$parentConfigurator = $this instanceof CollectionConfigurator ? $this : ($this instanceof RouteConfigurator ? $this->parentConfigurator : null);
|
||||||
|
$route = $this->createLocalizedRoute($this->collection, $name, $path, $this->name, $this->prefixes);
|
||||||
|
|
||||||
|
return new RouteConfigurator($this->collection, $route, $this->name, $parentConfigurator, $this->prefixes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a route.
|
||||||
|
*
|
||||||
|
* @param string|array $path the path, or the localized paths of the route
|
||||||
|
*
|
||||||
|
* @return RouteConfigurator
|
||||||
|
*/
|
||||||
|
final public function __invoke(string $name, $path): BaseRouteConfigurator
|
||||||
|
{
|
||||||
|
return $this->add($name, $path);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,62 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Bundle\FrameworkBundle\Routing\Loader\Configurator;
|
||||||
|
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Routing\Loader\Configurator\Traits\AddTrait;
|
||||||
|
use Symfony\Component\Routing\Loader\Configurator\RouteConfigurator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Jules Pietri <jules@heahprod.com>
|
||||||
|
*/
|
||||||
|
class UrlRedirectRouteConfigurator extends RouteConfigurator
|
||||||
|
{
|
||||||
|
use AddTrait;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param bool $permanent Whether the redirection is permanent
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
final public function permanent(bool $permanent = true)
|
||||||
|
{
|
||||||
|
return $this->defaults(['permanent' => $permanent]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string|null $scheme The URL scheme (null to keep the current one)
|
||||||
|
* @param int|null $port The HTTP or HTTPS port (null to keep the current one for the same scheme or the default configured port)
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
final public function scheme(?string $scheme, int $port = null)
|
||||||
|
{
|
||||||
|
$this->defaults(['scheme' => $scheme]);
|
||||||
|
|
||||||
|
if ('http' === $scheme) {
|
||||||
|
$this->defaults(['httpPort' => $port]);
|
||||||
|
} elseif ('https' === $scheme) {
|
||||||
|
$this->defaults(['httpsPort' => $port]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param bool $keepRequestMethod Whether redirect action should keep HTTP request method
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
final public function keepRequestMethod(bool $keepRequestMethod = true)
|
||||||
|
{
|
||||||
|
return $this->defaults(['keepRequestMethod' => $keepRequestMethod]);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Bundle\FrameworkBundle\Routing\Loader;
|
||||||
|
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Routing\Loader\Configurator\RoutingConfigurator;
|
||||||
|
use Symfony\Component\Routing\Loader\PhpFileLoader as BasePhpFileLoader;
|
||||||
|
use Symfony\Component\Routing\RouteCollection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Jules Pietri <jules@heahprod.com>
|
||||||
|
*/
|
||||||
|
class PhpFileLoader extends BasePhpFileLoader
|
||||||
|
{
|
||||||
|
protected function callConfigurator(callable $result, string $path, string $file): RouteCollection
|
||||||
|
{
|
||||||
|
$collection = new RouteCollection();
|
||||||
|
|
||||||
|
$result(new RoutingConfigurator($collection, $this, $path, $file));
|
||||||
|
|
||||||
|
return $collection;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,45 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Symfony\Bundle\FrameworkBundle\Routing\Loader\Configurator;
|
||||||
|
|
||||||
|
return function (RoutingConfigurator $routes) {
|
||||||
|
$routes->add('classic_route', '/classic');
|
||||||
|
|
||||||
|
$routes->add('template_route', '/static')
|
||||||
|
->template('static.html.twig', ['foo' => 'bar'])
|
||||||
|
->maxAge(300)
|
||||||
|
->sharedMaxAge(100)
|
||||||
|
->private()
|
||||||
|
->methods(['GET'])
|
||||||
|
->utf8()
|
||||||
|
->condition('abc')
|
||||||
|
;
|
||||||
|
$routes->add('redirect_route', '/redirect')
|
||||||
|
->redirectToRoute('target_route')
|
||||||
|
->permanent()
|
||||||
|
->ignoreAttributes(['attr', 'ibutes'])
|
||||||
|
->keepRequestMethod()
|
||||||
|
->keepQueryParams()
|
||||||
|
->schemes(['http'])
|
||||||
|
->host('legacy')
|
||||||
|
->utf8()
|
||||||
|
;
|
||||||
|
$routes->add('url_redirect_route', '/redirect-url')
|
||||||
|
->redirectToUrl('/url-target')
|
||||||
|
->permanent()
|
||||||
|
->scheme('http', 1)
|
||||||
|
->keepRequestMethod()
|
||||||
|
->host('legacy')
|
||||||
|
->utf8()
|
||||||
|
;
|
||||||
|
$routes->add('not_a_route', '/not-a-path')
|
||||||
|
->gone()
|
||||||
|
->host('legacy')
|
||||||
|
->utf8()
|
||||||
|
;
|
||||||
|
$routes->add('gone_route', '/gone-path')
|
||||||
|
->gone()
|
||||||
|
->permanent()
|
||||||
|
->utf8()
|
||||||
|
;
|
||||||
|
};
|
@ -0,0 +1,116 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Bundle\FrameworkBundle\Tests\Routing\Loader;
|
||||||
|
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Controller\RedirectController;
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Controller\TemplateController;
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Tests\TestCase;
|
||||||
|
use Symfony\Component\Config\FileLocator;
|
||||||
|
use Symfony\Component\Config\FileLocatorInterface;
|
||||||
|
use Symfony\Component\Config\Loader\LoaderInterface;
|
||||||
|
use Symfony\Component\Config\Resource\FileResource;
|
||||||
|
use Symfony\Component\Routing\Route;
|
||||||
|
use Symfony\Component\Routing\RouteCollection;
|
||||||
|
|
||||||
|
abstract class AbstractLoaderTest extends TestCase
|
||||||
|
{
|
||||||
|
/** @var LoaderInterface */
|
||||||
|
protected $loader;
|
||||||
|
|
||||||
|
abstract protected function getLoader(): LoaderInterface;
|
||||||
|
|
||||||
|
abstract protected function getType(): string;
|
||||||
|
|
||||||
|
protected function setUp(): void
|
||||||
|
{
|
||||||
|
$this->loader = $this->getLoader();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function tearDown(): void
|
||||||
|
{
|
||||||
|
$this->loader = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getLocator(): FileLocatorInterface
|
||||||
|
{
|
||||||
|
return new FileLocator([__DIR__.'/../../Fixtures/Resources/config/routing']);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testRoutesAreLoaded()
|
||||||
|
{
|
||||||
|
$routeCollection = $this->loader->load('routes.'.$this->getType());
|
||||||
|
|
||||||
|
$expectedCollection = new RouteCollection();
|
||||||
|
|
||||||
|
$expectedCollection->add('classic_route', (new Route('/classic')));
|
||||||
|
|
||||||
|
$expectedCollection->add('template_route', (new Route('/static'))
|
||||||
|
->setDefaults([
|
||||||
|
'_controller' => TemplateController::class,
|
||||||
|
'context' => ['foo' => 'bar'],
|
||||||
|
'template' => 'static.html.twig',
|
||||||
|
'maxAge' => 300,
|
||||||
|
'sharedAge' => 100,
|
||||||
|
'private' => true,
|
||||||
|
])
|
||||||
|
->setMethods(['GET'])
|
||||||
|
->setOptions(['utf8' => true])
|
||||||
|
->setCondition('abc')
|
||||||
|
);
|
||||||
|
$expectedCollection->add('redirect_route', (new Route('/redirect'))
|
||||||
|
->setDefaults([
|
||||||
|
'_controller' => RedirectController::class.'::redirectAction',
|
||||||
|
'route' => 'target_route',
|
||||||
|
'permanent' => true,
|
||||||
|
'ignoreAttributes' => ['attr', 'ibutes'],
|
||||||
|
'keepRequestMethod' => true,
|
||||||
|
'keepQueryParams' => true,
|
||||||
|
])
|
||||||
|
->setSchemes(['http'])
|
||||||
|
->setHost('legacy')
|
||||||
|
->setOptions(['utf8' => true])
|
||||||
|
);
|
||||||
|
$expectedCollection->add('url_redirect_route', (new Route('/redirect-url'))
|
||||||
|
->setDefaults([
|
||||||
|
'_controller' => RedirectController::class.'::urlRedirectAction',
|
||||||
|
'path' => '/url-target',
|
||||||
|
'permanent' => true,
|
||||||
|
'scheme' => 'http',
|
||||||
|
'httpPort' => 1,
|
||||||
|
'keepRequestMethod' => true,
|
||||||
|
])
|
||||||
|
->setHost('legacy')
|
||||||
|
->setOptions(['utf8' => true])
|
||||||
|
);
|
||||||
|
$expectedCollection->add('not_a_route', (new Route('/not-a-path'))
|
||||||
|
->setDefaults([
|
||||||
|
'_controller' => RedirectController::class.'::redirectAction',
|
||||||
|
'route' => '',
|
||||||
|
])
|
||||||
|
->setHost('legacy')
|
||||||
|
->setOptions(['utf8' => true])
|
||||||
|
);
|
||||||
|
$expectedCollection->add('gone_route', (new Route('/gone-path'))
|
||||||
|
->setDefaults([
|
||||||
|
'_controller' => RedirectController::class.'::redirectAction',
|
||||||
|
'route' => '',
|
||||||
|
'permanent' => true,
|
||||||
|
])
|
||||||
|
->setOptions(['utf8' => true])
|
||||||
|
);
|
||||||
|
$expectedCollection->addResource(new FileResource(realpath(
|
||||||
|
__DIR__.'/../../Fixtures/Resources/config/routing/routes.'.$this->getType()
|
||||||
|
)));
|
||||||
|
|
||||||
|
$this->assertEquals($expectedCollection, $routeCollection);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Bundle\FrameworkBundle\Tests\Routing\Loader;
|
||||||
|
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Routing\Loader\PhpFileLoader;
|
||||||
|
use Symfony\Component\Config\Loader\LoaderInterface;
|
||||||
|
|
||||||
|
class PhpFileLoaderTest extends AbstractLoaderTest
|
||||||
|
{
|
||||||
|
protected function getLoader(): LoaderInterface
|
||||||
|
{
|
||||||
|
return new PhpFileLoader($this->getLocator());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getType(): string
|
||||||
|
{
|
||||||
|
return 'php';
|
||||||
|
}
|
||||||
|
}
|
@ -80,6 +80,7 @@
|
|||||||
"symfony/messenger": "<4.4",
|
"symfony/messenger": "<4.4",
|
||||||
"symfony/mime": "<4.4",
|
"symfony/mime": "<4.4",
|
||||||
"symfony/property-info": "<4.4",
|
"symfony/property-info": "<4.4",
|
||||||
|
"symfony/routing": "<5.1",
|
||||||
"symfony/serializer": "<4.4",
|
"symfony/serializer": "<4.4",
|
||||||
"symfony/stopwatch": "<4.4",
|
"symfony/stopwatch": "<4.4",
|
||||||
"symfony/translation": "<5.0",
|
"symfony/translation": "<5.0",
|
||||||
|
@ -4,6 +4,7 @@ CHANGELOG
|
|||||||
5.1.0
|
5.1.0
|
||||||
-----
|
-----
|
||||||
|
|
||||||
|
* added the protected method `PhpFileLoader::callConfigurator()` as extension point to ease custom routing configuration
|
||||||
* deprecated `RouteCollectionBuilder` in favor of `RoutingConfigurator`.
|
* deprecated `RouteCollectionBuilder` in favor of `RoutingConfigurator`.
|
||||||
* added "priority" option to annotated routes
|
* added "priority" option to annotated routes
|
||||||
* added argument `$priority` to `RouteCollection::add()`
|
* added argument `$priority` to `RouteCollection::add()`
|
||||||
|
@ -11,7 +11,6 @@
|
|||||||
|
|
||||||
namespace Symfony\Component\Routing\Loader\Configurator;
|
namespace Symfony\Component\Routing\Loader\Configurator;
|
||||||
|
|
||||||
use Symfony\Component\Routing\Route;
|
|
||||||
use Symfony\Component\Routing\RouteCollection;
|
use Symfony\Component\Routing\RouteCollection;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -19,6 +18,7 @@ use Symfony\Component\Routing\RouteCollection;
|
|||||||
*/
|
*/
|
||||||
class ImportConfigurator
|
class ImportConfigurator
|
||||||
{
|
{
|
||||||
|
use Traits\PrefixTrait;
|
||||||
use Traits\RouteTrait;
|
use Traits\RouteTrait;
|
||||||
|
|
||||||
private $parent;
|
private $parent;
|
||||||
@ -43,38 +43,7 @@ class ImportConfigurator
|
|||||||
*/
|
*/
|
||||||
final public function prefix($prefix, bool $trailingSlashOnRoot = true): self
|
final public function prefix($prefix, bool $trailingSlashOnRoot = true): self
|
||||||
{
|
{
|
||||||
if (!\is_array($prefix)) {
|
$this->addPrefix($this->route, $prefix, $trailingSlashOnRoot);
|
||||||
$this->route->addPrefix($prefix);
|
|
||||||
if (!$trailingSlashOnRoot) {
|
|
||||||
$rootPath = (new Route(trim(trim($prefix), '/').'/'))->getPath();
|
|
||||||
foreach ($this->route->all() as $route) {
|
|
||||||
if ($route->getPath() === $rootPath) {
|
|
||||||
$route->setPath(rtrim($rootPath, '/'));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
foreach ($prefix as $locale => $localePrefix) {
|
|
||||||
$prefix[$locale] = trim(trim($localePrefix), '/');
|
|
||||||
}
|
|
||||||
foreach ($this->route->all() as $name => $route) {
|
|
||||||
if (null === $locale = $route->getDefault('_locale')) {
|
|
||||||
$this->route->remove($name);
|
|
||||||
foreach ($prefix as $locale => $localePrefix) {
|
|
||||||
$localizedRoute = clone $route;
|
|
||||||
$localizedRoute->setDefault('_locale', $locale);
|
|
||||||
$localizedRoute->setDefault('_canonical_route', $name);
|
|
||||||
$localizedRoute->setPath($localePrefix.(!$trailingSlashOnRoot && '/' === $route->getPath() ? '' : $route->getPath()));
|
|
||||||
$this->route->add($name.'.'.$locale, $localizedRoute);
|
|
||||||
}
|
|
||||||
} elseif (!isset($prefix[$locale])) {
|
|
||||||
throw new \InvalidArgumentException(sprintf('Route "%s" with locale "%s" is missing a corresponding prefix in its parent collection.', $name, $locale));
|
|
||||||
} else {
|
|
||||||
$route->setPath($prefix[$locale].(!$trailingSlashOnRoot && '/' === $route->getPath() ? '' : $route->getPath()));
|
|
||||||
$this->route->add($name, $route);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@ class RouteConfigurator
|
|||||||
use Traits\AddTrait;
|
use Traits\AddTrait;
|
||||||
use Traits\RouteTrait;
|
use Traits\RouteTrait;
|
||||||
|
|
||||||
private $parentConfigurator;
|
protected $parentConfigurator;
|
||||||
|
|
||||||
public function __construct(RouteCollection $collection, $route, string $name = '', CollectionConfigurator $parentConfigurator = null, array $prefixes = null)
|
public function __construct(RouteCollection $collection, $route, string $name = '', CollectionConfigurator $parentConfigurator = null, array $prefixes = null)
|
||||||
{
|
{
|
||||||
|
@ -13,64 +13,33 @@ namespace Symfony\Component\Routing\Loader\Configurator\Traits;
|
|||||||
|
|
||||||
use Symfony\Component\Routing\Loader\Configurator\CollectionConfigurator;
|
use Symfony\Component\Routing\Loader\Configurator\CollectionConfigurator;
|
||||||
use Symfony\Component\Routing\Loader\Configurator\RouteConfigurator;
|
use Symfony\Component\Routing\Loader\Configurator\RouteConfigurator;
|
||||||
use Symfony\Component\Routing\Route;
|
|
||||||
use Symfony\Component\Routing\RouteCollection;
|
use Symfony\Component\Routing\RouteCollection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Nicolas Grekas <p@tchwork.com>
|
||||||
|
*/
|
||||||
trait AddTrait
|
trait AddTrait
|
||||||
{
|
{
|
||||||
|
use LocalizedRouteTrait;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var RouteCollection
|
* @var RouteCollection
|
||||||
*/
|
*/
|
||||||
private $collection;
|
protected $collection;
|
||||||
|
protected $name = '';
|
||||||
private $name = '';
|
protected $prefixes;
|
||||||
|
|
||||||
private $prefixes;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a route.
|
* Adds a route.
|
||||||
*
|
*
|
||||||
* @param string|array $path the path, or the localized paths of the route
|
* @param string|array $path the path, or the localized paths of the route
|
||||||
*/
|
*/
|
||||||
final public function add(string $name, $path): RouteConfigurator
|
public function add(string $name, $path): RouteConfigurator
|
||||||
{
|
{
|
||||||
$paths = [];
|
|
||||||
$parentConfigurator = $this instanceof CollectionConfigurator ? $this : ($this instanceof RouteConfigurator ? $this->parentConfigurator : null);
|
$parentConfigurator = $this instanceof CollectionConfigurator ? $this : ($this instanceof RouteConfigurator ? $this->parentConfigurator : null);
|
||||||
|
$route = $this->createLocalizedRoute($this->collection, $name, $path, $this->name, $this->prefixes);
|
||||||
|
|
||||||
if (\is_array($path)) {
|
return new RouteConfigurator($this->collection, $route, $this->name, $parentConfigurator, $this->prefixes);
|
||||||
if (null === $this->prefixes) {
|
|
||||||
$paths = $path;
|
|
||||||
} elseif ($missing = array_diff_key($this->prefixes, $path)) {
|
|
||||||
throw new \LogicException(sprintf('Route "%s" is missing routes for locale(s) "%s".', $name, implode('", "', array_keys($missing))));
|
|
||||||
} else {
|
|
||||||
foreach ($path as $locale => $localePath) {
|
|
||||||
if (!isset($this->prefixes[$locale])) {
|
|
||||||
throw new \LogicException(sprintf('Route "%s" with locale "%s" is missing a corresponding prefix in its parent collection.', $name, $locale));
|
|
||||||
}
|
|
||||||
|
|
||||||
$paths[$locale] = $this->prefixes[$locale].$localePath;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} elseif (null !== $this->prefixes) {
|
|
||||||
foreach ($this->prefixes as $locale => $prefix) {
|
|
||||||
$paths[$locale] = $prefix.$path;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$this->collection->add($this->name.$name, $route = $this->createRoute($path));
|
|
||||||
|
|
||||||
return new RouteConfigurator($this->collection, $route, $this->name, $parentConfigurator, $this->prefixes);
|
|
||||||
}
|
|
||||||
|
|
||||||
$routes = new RouteCollection();
|
|
||||||
|
|
||||||
foreach ($paths as $locale => $path) {
|
|
||||||
$routes->add($name.'.'.$locale, $route = $this->createRoute($path));
|
|
||||||
$this->collection->add($this->name.$name.'.'.$locale, $route);
|
|
||||||
$route->setDefault('_locale', $locale);
|
|
||||||
$route->setDefault('_canonical_route', $this->name.$name);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new RouteConfigurator($this->collection, $routes, $this->name, $parentConfigurator, $this->prefixes);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -78,13 +47,8 @@ trait AddTrait
|
|||||||
*
|
*
|
||||||
* @param string|array $path the path, or the localized paths of the route
|
* @param string|array $path the path, or the localized paths of the route
|
||||||
*/
|
*/
|
||||||
final public function __invoke(string $name, $path): RouteConfigurator
|
public function __invoke(string $name, $path): RouteConfigurator
|
||||||
{
|
{
|
||||||
return $this->add($name, $path);
|
return $this->add($name, $path);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function createRoute(string $path): Route
|
|
||||||
{
|
|
||||||
return new Route($path);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,74 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\Routing\Loader\Configurator\Traits;
|
||||||
|
|
||||||
|
use Symfony\Component\Routing\Route;
|
||||||
|
use Symfony\Component\Routing\RouteCollection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Nicolas Grekas <p@tchwork.com>
|
||||||
|
* @author Jules Pietri <jules@heahprod.com>
|
||||||
|
*/
|
||||||
|
trait LocalizedRouteTrait
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Creates one or many routes.
|
||||||
|
*
|
||||||
|
* @param string|array $path the path, or the localized paths of the route
|
||||||
|
*
|
||||||
|
* @return Route|RouteCollection
|
||||||
|
*/
|
||||||
|
final protected function createLocalizedRoute(RouteCollection $collection, string $name, $path, string $namePrefix = '', array $prefixes = null)
|
||||||
|
{
|
||||||
|
$paths = [];
|
||||||
|
|
||||||
|
if (\is_array($path)) {
|
||||||
|
if (null === $prefixes) {
|
||||||
|
$paths = $path;
|
||||||
|
} elseif ($missing = array_diff_key($prefixes, $path)) {
|
||||||
|
throw new \LogicException(sprintf('Route "%s" is missing routes for locale(s) "%s".', $name, implode('", "', array_keys($missing))));
|
||||||
|
} else {
|
||||||
|
foreach ($path as $locale => $localePath) {
|
||||||
|
if (!isset($prefixes[$locale])) {
|
||||||
|
throw new \LogicException(sprintf('Route "%s" with locale "%s" is missing a corresponding prefix in its parent collection.', $name, $locale));
|
||||||
|
}
|
||||||
|
|
||||||
|
$paths[$locale] = $prefixes[$locale].$localePath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} elseif (null !== $prefixes) {
|
||||||
|
foreach ($prefixes as $locale => $prefix) {
|
||||||
|
$paths[$locale] = $prefix.$path;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$collection->add($namePrefix.$name, $route = $this->createRoute($path));
|
||||||
|
|
||||||
|
return $route;
|
||||||
|
}
|
||||||
|
|
||||||
|
$routes = new RouteCollection();
|
||||||
|
|
||||||
|
foreach ($paths as $locale => $path) {
|
||||||
|
$routes->add($name.'.'.$locale, $route = $this->createRoute($path));
|
||||||
|
$collection->add($namePrefix.$name.'.'.$locale, $route);
|
||||||
|
$route->setDefault('_locale', $locale);
|
||||||
|
$route->setDefault('_canonical_route', $namePrefix.$name);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $routes;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function createRoute(string $path): Route
|
||||||
|
{
|
||||||
|
return new Route($path);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,59 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\Routing\Loader\Configurator\Traits;
|
||||||
|
|
||||||
|
use Symfony\Component\Routing\Route;
|
||||||
|
use Symfony\Component\Routing\RouteCollection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Nicolas Grekas <p@tchwork.com>
|
||||||
|
*/
|
||||||
|
trait PrefixTrait
|
||||||
|
{
|
||||||
|
final protected function addPrefix(RouteCollection $routes, $prefix, bool $trailingSlashOnRoot)
|
||||||
|
{
|
||||||
|
if (\is_array($prefix)) {
|
||||||
|
foreach ($prefix as $locale => $localePrefix) {
|
||||||
|
$prefix[$locale] = trim(trim($localePrefix), '/');
|
||||||
|
}
|
||||||
|
foreach ($routes->all() as $name => $route) {
|
||||||
|
if (null === $locale = $route->getDefault('_locale')) {
|
||||||
|
$routes->remove($name);
|
||||||
|
foreach ($prefix as $locale => $localePrefix) {
|
||||||
|
$localizedRoute = clone $route;
|
||||||
|
$localizedRoute->setDefault('_locale', $locale);
|
||||||
|
$localizedRoute->setDefault('_canonical_route', $name);
|
||||||
|
$localizedRoute->setPath($localePrefix.(!$trailingSlashOnRoot && '/' === $route->getPath() ? '' : $route->getPath()));
|
||||||
|
$routes->add($name.'.'.$locale, $localizedRoute);
|
||||||
|
}
|
||||||
|
} elseif (!isset($prefix[$locale])) {
|
||||||
|
throw new \InvalidArgumentException(sprintf('Route "%s" with locale "%s" is missing a corresponding prefix in its parent collection.', $name, $locale));
|
||||||
|
} else {
|
||||||
|
$route->setPath($prefix[$locale].(!$trailingSlashOnRoot && '/' === $route->getPath() ? '' : $route->getPath()));
|
||||||
|
$routes->add($name, $route);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$routes->addPrefix($prefix);
|
||||||
|
if (!$trailingSlashOnRoot) {
|
||||||
|
$rootPath = (new Route(trim(trim($prefix), '/').'/'))->getPath();
|
||||||
|
foreach ($routes->all() as $route) {
|
||||||
|
if ($route->getPath() === $rootPath) {
|
||||||
|
$route->setPath(rtrim($rootPath, '/'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -19,7 +19,7 @@ trait RouteTrait
|
|||||||
/**
|
/**
|
||||||
* @var RouteCollection|Route
|
* @var RouteCollection|Route
|
||||||
*/
|
*/
|
||||||
private $route;
|
protected $route;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds defaults.
|
* Adds defaults.
|
||||||
|
@ -22,6 +22,8 @@ use Symfony\Component\Routing\RouteCollection;
|
|||||||
* The file must return a RouteCollection instance.
|
* The file must return a RouteCollection instance.
|
||||||
*
|
*
|
||||||
* @author Fabien Potencier <fabien@symfony.com>
|
* @author Fabien Potencier <fabien@symfony.com>
|
||||||
|
* @author Nicolas grekas <p@tchwork.com>
|
||||||
|
* @author Jules Pietri <jules@heahprod.com>
|
||||||
*/
|
*/
|
||||||
class PhpFileLoader extends FileLoader
|
class PhpFileLoader extends FileLoader
|
||||||
{
|
{
|
||||||
@ -47,8 +49,7 @@ class PhpFileLoader extends FileLoader
|
|||||||
$result = $load($path);
|
$result = $load($path);
|
||||||
|
|
||||||
if (\is_object($result) && \is_callable($result)) {
|
if (\is_object($result) && \is_callable($result)) {
|
||||||
$collection = new RouteCollection();
|
$collection = $this->callConfigurator($result, $path, $file);
|
||||||
$result(new RoutingConfigurator($collection, $this, $path, $file));
|
|
||||||
} else {
|
} else {
|
||||||
$collection = $result;
|
$collection = $result;
|
||||||
}
|
}
|
||||||
@ -65,6 +66,15 @@ class PhpFileLoader extends FileLoader
|
|||||||
{
|
{
|
||||||
return \is_string($resource) && 'php' === pathinfo($resource, PATHINFO_EXTENSION) && (!$type || 'php' === $type);
|
return \is_string($resource) && 'php' === pathinfo($resource, PATHINFO_EXTENSION) && (!$type || 'php' === $type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function callConfigurator(callable $result, string $path, string $file): RouteCollection
|
||||||
|
{
|
||||||
|
$collection = new RouteCollection();
|
||||||
|
|
||||||
|
$result(new RoutingConfigurator($collection, $this, $path, $file));
|
||||||
|
|
||||||
|
return $collection;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -14,7 +14,8 @@ namespace Symfony\Component\Routing\Loader;
|
|||||||
use Symfony\Component\Config\Loader\FileLoader;
|
use Symfony\Component\Config\Loader\FileLoader;
|
||||||
use Symfony\Component\Config\Resource\FileResource;
|
use Symfony\Component\Config\Resource\FileResource;
|
||||||
use Symfony\Component\Config\Util\XmlUtils;
|
use Symfony\Component\Config\Util\XmlUtils;
|
||||||
use Symfony\Component\Routing\Route;
|
use Symfony\Component\Routing\Loader\Configurator\Traits\LocalizedRouteTrait;
|
||||||
|
use Symfony\Component\Routing\Loader\Configurator\Traits\PrefixTrait;
|
||||||
use Symfony\Component\Routing\RouteCollection;
|
use Symfony\Component\Routing\RouteCollection;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -25,6 +26,9 @@ use Symfony\Component\Routing\RouteCollection;
|
|||||||
*/
|
*/
|
||||||
class XmlFileLoader extends FileLoader
|
class XmlFileLoader extends FileLoader
|
||||||
{
|
{
|
||||||
|
use LocalizedRouteTrait;
|
||||||
|
use PrefixTrait;
|
||||||
|
|
||||||
const NAMESPACE_URI = 'http://symfony.com/schema/routing';
|
const NAMESPACE_URI = 'http://symfony.com/schema/routing';
|
||||||
const SCHEME_PATH = '/schema/routing/routing-1.0.xsd';
|
const SCHEME_PATH = '/schema/routing/routing-1.0.xsd';
|
||||||
|
|
||||||
@ -98,41 +102,40 @@ class XmlFileLoader extends FileLoader
|
|||||||
/**
|
/**
|
||||||
* Parses a route and adds it to the RouteCollection.
|
* Parses a route and adds it to the RouteCollection.
|
||||||
*
|
*
|
||||||
* @param \DOMElement $node Element to parse that represents a Route
|
* @param \DOMElement $node Element to parse that represents a Route
|
||||||
* @param string $path Full path of the XML file being processed
|
* @param string $filepath Full path of the XML file being processed
|
||||||
*
|
*
|
||||||
* @throws \InvalidArgumentException When the XML is invalid
|
* @throws \InvalidArgumentException When the XML is invalid
|
||||||
*/
|
*/
|
||||||
protected function parseRoute(RouteCollection $collection, \DOMElement $node, string $path)
|
protected function parseRoute(RouteCollection $collection, \DOMElement $node, string $filepath)
|
||||||
{
|
{
|
||||||
if ('' === $id = $node->getAttribute('id')) {
|
if ('' === $id = $node->getAttribute('id')) {
|
||||||
throw new \InvalidArgumentException(sprintf('The <route> element in file "%s" must have an "id" attribute.', $path));
|
throw new \InvalidArgumentException(sprintf('The <route> element in file "%s" must have an "id" attribute.', $filepath));
|
||||||
}
|
}
|
||||||
|
|
||||||
$schemes = preg_split('/[\s,\|]++/', $node->getAttribute('schemes'), -1, PREG_SPLIT_NO_EMPTY);
|
$schemes = preg_split('/[\s,\|]++/', $node->getAttribute('schemes'), -1, PREG_SPLIT_NO_EMPTY);
|
||||||
$methods = preg_split('/[\s,\|]++/', $node->getAttribute('methods'), -1, PREG_SPLIT_NO_EMPTY);
|
$methods = preg_split('/[\s,\|]++/', $node->getAttribute('methods'), -1, PREG_SPLIT_NO_EMPTY);
|
||||||
|
|
||||||
list($defaults, $requirements, $options, $condition, $paths) = $this->parseConfigs($node, $path);
|
list($defaults, $requirements, $options, $condition, $paths) = $this->parseConfigs($node, $filepath);
|
||||||
|
|
||||||
if (!$paths && '' === $node->getAttribute('path')) {
|
$path = $node->getAttribute('path');
|
||||||
throw new \InvalidArgumentException(sprintf('The <route> element in file "%s" must have a "path" attribute or <path> child nodes.', $path));
|
|
||||||
|
if (!$paths && '' === $path) {
|
||||||
|
throw new \InvalidArgumentException(sprintf('The <route> element in file "%s" must have a "path" attribute or <path> child nodes.', $filepath));
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($paths && '' !== $node->getAttribute('path')) {
|
if ($paths && '' !== $path) {
|
||||||
throw new \InvalidArgumentException(sprintf('The <route> element in file "%s" must not have both a "path" attribute and <path> child nodes.', $path));
|
throw new \InvalidArgumentException(sprintf('The <route> element in file "%s" must not have both a "path" attribute and <path> child nodes.', $filepath));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$paths) {
|
$route = $this->createLocalizedRoute($collection, $id, $paths ?: $path);
|
||||||
$route = new Route($node->getAttribute('path'), $defaults, $requirements, $options, $node->getAttribute('host'), $schemes, $methods, $condition);
|
$route->addDefaults($defaults);
|
||||||
$collection->add($id, $route);
|
$route->addRequirements($requirements);
|
||||||
} else {
|
$route->addOptions($options);
|
||||||
foreach ($paths as $locale => $p) {
|
$route->setHost($node->getAttribute('host'));
|
||||||
$defaults['_locale'] = $locale;
|
$route->setSchemes($schemes);
|
||||||
$defaults['_canonical_route'] = $id;
|
$route->setMethods($methods);
|
||||||
$route = new Route($p, $defaults, $requirements, $options, $node->getAttribute('host'), $schemes, $methods, $condition);
|
$route->setCondition($condition);
|
||||||
$collection->add($id.'.'.$locale, $route);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -156,6 +159,7 @@ class XmlFileLoader extends FileLoader
|
|||||||
$schemes = $node->hasAttribute('schemes') ? preg_split('/[\s,\|]++/', $node->getAttribute('schemes'), -1, PREG_SPLIT_NO_EMPTY) : null;
|
$schemes = $node->hasAttribute('schemes') ? preg_split('/[\s,\|]++/', $node->getAttribute('schemes'), -1, PREG_SPLIT_NO_EMPTY) : null;
|
||||||
$methods = $node->hasAttribute('methods') ? preg_split('/[\s,\|]++/', $node->getAttribute('methods'), -1, PREG_SPLIT_NO_EMPTY) : null;
|
$methods = $node->hasAttribute('methods') ? preg_split('/[\s,\|]++/', $node->getAttribute('methods'), -1, PREG_SPLIT_NO_EMPTY) : null;
|
||||||
$trailingSlashOnRoot = $node->hasAttribute('trailing-slash-on-root') ? XmlUtils::phpize($node->getAttribute('trailing-slash-on-root')) : true;
|
$trailingSlashOnRoot = $node->hasAttribute('trailing-slash-on-root') ? XmlUtils::phpize($node->getAttribute('trailing-slash-on-root')) : true;
|
||||||
|
$namePrefix = $node->getAttribute('name-prefix') ?: null;
|
||||||
|
|
||||||
list($defaults, $requirements, $options, $condition, /* $paths */, $prefixes) = $this->parseConfigs($node, $path);
|
list($defaults, $requirements, $options, $condition, /* $paths */, $prefixes) = $this->parseConfigs($node, $path);
|
||||||
|
|
||||||
@ -187,39 +191,7 @@ class XmlFileLoader extends FileLoader
|
|||||||
}
|
}
|
||||||
|
|
||||||
foreach ($imported as $subCollection) {
|
foreach ($imported as $subCollection) {
|
||||||
/* @var $subCollection RouteCollection */
|
$this->addPrefix($subCollection, $prefixes ?: $prefix, $trailingSlashOnRoot);
|
||||||
if ('' !== $prefix || !$prefixes) {
|
|
||||||
$subCollection->addPrefix($prefix);
|
|
||||||
if (!$trailingSlashOnRoot) {
|
|
||||||
$rootPath = (new Route(trim(trim($prefix), '/').'/'))->getPath();
|
|
||||||
foreach ($subCollection->all() as $route) {
|
|
||||||
if ($route->getPath() === $rootPath) {
|
|
||||||
$route->setPath(rtrim($rootPath, '/'));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
foreach ($prefixes as $locale => $localePrefix) {
|
|
||||||
$prefixes[$locale] = trim(trim($localePrefix), '/');
|
|
||||||
}
|
|
||||||
foreach ($subCollection->all() as $name => $route) {
|
|
||||||
if (null === $locale = $route->getDefault('_locale')) {
|
|
||||||
$subCollection->remove($name);
|
|
||||||
foreach ($prefixes as $locale => $localePrefix) {
|
|
||||||
$localizedRoute = clone $route;
|
|
||||||
$localizedRoute->setPath($localePrefix.(!$trailingSlashOnRoot && '/' === $route->getPath() ? '' : $route->getPath()));
|
|
||||||
$localizedRoute->setDefault('_locale', $locale);
|
|
||||||
$localizedRoute->setDefault('_canonical_route', $name);
|
|
||||||
$subCollection->add($name.'.'.$locale, $localizedRoute);
|
|
||||||
}
|
|
||||||
} elseif (!isset($prefixes[$locale])) {
|
|
||||||
throw new \InvalidArgumentException(sprintf('Route "%s" with locale "%s" is missing a corresponding prefix when imported in "%s".', $name, $locale, $path));
|
|
||||||
} else {
|
|
||||||
$route->setPath($prefixes[$locale].(!$trailingSlashOnRoot && '/' === $route->getPath() ? '' : $route->getPath()));
|
|
||||||
$subCollection->add($name, $route);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (null !== $host) {
|
if (null !== $host) {
|
||||||
$subCollection->setHost($host);
|
$subCollection->setHost($host);
|
||||||
@ -233,14 +205,13 @@ class XmlFileLoader extends FileLoader
|
|||||||
if (null !== $methods) {
|
if (null !== $methods) {
|
||||||
$subCollection->setMethods($methods);
|
$subCollection->setMethods($methods);
|
||||||
}
|
}
|
||||||
|
if (null !== $namePrefix) {
|
||||||
|
$subCollection->addNamePrefix($namePrefix);
|
||||||
|
}
|
||||||
$subCollection->addDefaults($defaults);
|
$subCollection->addDefaults($defaults);
|
||||||
$subCollection->addRequirements($requirements);
|
$subCollection->addRequirements($requirements);
|
||||||
$subCollection->addOptions($options);
|
$subCollection->addOptions($options);
|
||||||
|
|
||||||
if ($namePrefix = $node->getAttribute('name-prefix')) {
|
|
||||||
$subCollection->addNamePrefix($namePrefix);
|
|
||||||
}
|
|
||||||
|
|
||||||
$collection->addCollection($subCollection);
|
$collection->addCollection($subCollection);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,8 @@ namespace Symfony\Component\Routing\Loader;
|
|||||||
|
|
||||||
use Symfony\Component\Config\Loader\FileLoader;
|
use Symfony\Component\Config\Loader\FileLoader;
|
||||||
use Symfony\Component\Config\Resource\FileResource;
|
use Symfony\Component\Config\Resource\FileResource;
|
||||||
use Symfony\Component\Routing\Route;
|
use Symfony\Component\Routing\Loader\Configurator\Traits\LocalizedRouteTrait;
|
||||||
|
use Symfony\Component\Routing\Loader\Configurator\Traits\PrefixTrait;
|
||||||
use Symfony\Component\Routing\RouteCollection;
|
use Symfony\Component\Routing\RouteCollection;
|
||||||
use Symfony\Component\Yaml\Exception\ParseException;
|
use Symfony\Component\Yaml\Exception\ParseException;
|
||||||
use Symfony\Component\Yaml\Parser as YamlParser;
|
use Symfony\Component\Yaml\Parser as YamlParser;
|
||||||
@ -27,6 +28,9 @@ use Symfony\Component\Yaml\Yaml;
|
|||||||
*/
|
*/
|
||||||
class YamlFileLoader extends FileLoader
|
class YamlFileLoader extends FileLoader
|
||||||
{
|
{
|
||||||
|
use LocalizedRouteTrait;
|
||||||
|
use PrefixTrait;
|
||||||
|
|
||||||
private static $availableKeys = [
|
private static $availableKeys = [
|
||||||
'resource', 'type', 'prefix', 'path', 'host', 'schemes', 'methods', 'defaults', 'requirements', 'options', 'condition', 'controller', 'name_prefix', 'trailing_slash_on_root', 'locale', 'format', 'utf8', 'exclude',
|
'resource', 'type', 'prefix', 'path', 'host', 'schemes', 'methods', 'defaults', 'requirements', 'options', 'condition', 'controller', 'name_prefix', 'trailing_slash_on_root', 'locale', 'format', 'utf8', 'exclude',
|
||||||
];
|
];
|
||||||
@ -110,10 +114,6 @@ class YamlFileLoader extends FileLoader
|
|||||||
$defaults = isset($config['defaults']) ? $config['defaults'] : [];
|
$defaults = isset($config['defaults']) ? $config['defaults'] : [];
|
||||||
$requirements = isset($config['requirements']) ? $config['requirements'] : [];
|
$requirements = isset($config['requirements']) ? $config['requirements'] : [];
|
||||||
$options = isset($config['options']) ? $config['options'] : [];
|
$options = isset($config['options']) ? $config['options'] : [];
|
||||||
$host = isset($config['host']) ? $config['host'] : '';
|
|
||||||
$schemes = isset($config['schemes']) ? $config['schemes'] : [];
|
|
||||||
$methods = isset($config['methods']) ? $config['methods'] : [];
|
|
||||||
$condition = isset($config['condition']) ? $config['condition'] : null;
|
|
||||||
|
|
||||||
foreach ($requirements as $placeholder => $requirement) {
|
foreach ($requirements as $placeholder => $requirement) {
|
||||||
if (\is_int($placeholder)) {
|
if (\is_int($placeholder)) {
|
||||||
@ -134,20 +134,14 @@ class YamlFileLoader extends FileLoader
|
|||||||
$options['utf8'] = $config['utf8'];
|
$options['utf8'] = $config['utf8'];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (\is_array($config['path'])) {
|
$route = $this->createLocalizedRoute($collection, $name, $config['path']);
|
||||||
$route = new Route('', $defaults, $requirements, $options, $host, $schemes, $methods, $condition);
|
$route->addDefaults($defaults);
|
||||||
|
$route->addRequirements($requirements);
|
||||||
foreach ($config['path'] as $locale => $path) {
|
$route->addOptions($options);
|
||||||
$localizedRoute = clone $route;
|
$route->setHost($config['host'] ?? '');
|
||||||
$localizedRoute->setDefault('_locale', $locale);
|
$route->setSchemes($config['schemes'] ?? []);
|
||||||
$localizedRoute->setDefault('_canonical_route', $name);
|
$route->setMethods($config['methods'] ?? []);
|
||||||
$localizedRoute->setPath($path);
|
$route->setCondition($config['condition'] ?? null);
|
||||||
$collection->add($name.'.'.$locale, $localizedRoute);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$route = new Route($config['path'], $defaults, $requirements, $options, $host, $schemes, $methods, $condition);
|
|
||||||
$collection->add($name, $route);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -169,6 +163,7 @@ class YamlFileLoader extends FileLoader
|
|||||||
$schemes = isset($config['schemes']) ? $config['schemes'] : null;
|
$schemes = isset($config['schemes']) ? $config['schemes'] : null;
|
||||||
$methods = isset($config['methods']) ? $config['methods'] : null;
|
$methods = isset($config['methods']) ? $config['methods'] : null;
|
||||||
$trailingSlashOnRoot = $config['trailing_slash_on_root'] ?? true;
|
$trailingSlashOnRoot = $config['trailing_slash_on_root'] ?? true;
|
||||||
|
$namePrefix = $config['name_prefix'] ?? '';
|
||||||
$exclude = $config['exclude'] ?? null;
|
$exclude = $config['exclude'] ?? null;
|
||||||
|
|
||||||
if (isset($config['controller'])) {
|
if (isset($config['controller'])) {
|
||||||
@ -186,6 +181,7 @@ class YamlFileLoader extends FileLoader
|
|||||||
|
|
||||||
$this->setCurrentDir(\dirname($path));
|
$this->setCurrentDir(\dirname($path));
|
||||||
|
|
||||||
|
/** @var RouteCollection[] $imported */
|
||||||
$imported = $this->import($config['resource'], $type, false, $file, $exclude) ?: [];
|
$imported = $this->import($config['resource'], $type, false, $file, $exclude) ?: [];
|
||||||
|
|
||||||
if (!\is_array($imported)) {
|
if (!\is_array($imported)) {
|
||||||
@ -193,39 +189,7 @@ class YamlFileLoader extends FileLoader
|
|||||||
}
|
}
|
||||||
|
|
||||||
foreach ($imported as $subCollection) {
|
foreach ($imported as $subCollection) {
|
||||||
/* @var $subCollection RouteCollection */
|
$this->addPrefix($subCollection, $prefix, $trailingSlashOnRoot);
|
||||||
if (!\is_array($prefix)) {
|
|
||||||
$subCollection->addPrefix($prefix);
|
|
||||||
if (!$trailingSlashOnRoot) {
|
|
||||||
$rootPath = (new Route(trim(trim($prefix), '/').'/'))->getPath();
|
|
||||||
foreach ($subCollection->all() as $route) {
|
|
||||||
if ($route->getPath() === $rootPath) {
|
|
||||||
$route->setPath(rtrim($rootPath, '/'));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
foreach ($prefix as $locale => $localePrefix) {
|
|
||||||
$prefix[$locale] = trim(trim($localePrefix), '/');
|
|
||||||
}
|
|
||||||
foreach ($subCollection->all() as $name => $route) {
|
|
||||||
if (null === $locale = $route->getDefault('_locale')) {
|
|
||||||
$subCollection->remove($name);
|
|
||||||
foreach ($prefix as $locale => $localePrefix) {
|
|
||||||
$localizedRoute = clone $route;
|
|
||||||
$localizedRoute->setDefault('_locale', $locale);
|
|
||||||
$localizedRoute->setDefault('_canonical_route', $name);
|
|
||||||
$localizedRoute->setPath($localePrefix.(!$trailingSlashOnRoot && '/' === $route->getPath() ? '' : $route->getPath()));
|
|
||||||
$subCollection->add($name.'.'.$locale, $localizedRoute);
|
|
||||||
}
|
|
||||||
} elseif (!isset($prefix[$locale])) {
|
|
||||||
throw new \InvalidArgumentException(sprintf('Route "%s" with locale "%s" is missing a corresponding prefix when imported in "%s".', $name, $locale, $file));
|
|
||||||
} else {
|
|
||||||
$route->setPath($prefix[$locale].(!$trailingSlashOnRoot && '/' === $route->getPath() ? '' : $route->getPath()));
|
|
||||||
$subCollection->add($name, $route);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (null !== $host) {
|
if (null !== $host) {
|
||||||
$subCollection->setHost($host);
|
$subCollection->setHost($host);
|
||||||
@ -239,14 +203,13 @@ class YamlFileLoader extends FileLoader
|
|||||||
if (null !== $methods) {
|
if (null !== $methods) {
|
||||||
$subCollection->setMethods($methods);
|
$subCollection->setMethods($methods);
|
||||||
}
|
}
|
||||||
|
if (null !== $namePrefix) {
|
||||||
|
$subCollection->addNamePrefix($namePrefix);
|
||||||
|
}
|
||||||
$subCollection->addDefaults($defaults);
|
$subCollection->addDefaults($defaults);
|
||||||
$subCollection->addRequirements($requirements);
|
$subCollection->addRequirements($requirements);
|
||||||
$subCollection->addOptions($options);
|
$subCollection->addOptions($options);
|
||||||
|
|
||||||
if (isset($config['name_prefix'])) {
|
|
||||||
$subCollection->addNamePrefix($config['name_prefix']);
|
|
||||||
}
|
|
||||||
|
|
||||||
$collection->addCollection($subCollection);
|
$collection->addCollection($subCollection);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user