覆盖路由器并将参数添加到特定路由(在使用路径/ url之前)

Pat*_*ckB 6 routing symfony

我会使用一个简单的管理路由系统.

例如我现在有这条路线.

_welcome                    ANY      ANY    ANY  /
acmedemo_example_index      ANY      ANY    ANY  /acme/demos
acmedemo_example_edit       ANY      ANY    ANY  /acme/edit/{id}
acmedemo_example_delete     ANY      ANY    ANY  /acme/delete/{id}
acmeapi_backup_get          GET      ANY    ANY  /api/acme
acmeapi_backup_edit         POST     ANY    ANY  /api/acme
Run Code Online (Sandbox Code Playgroud)

现在我将当前用户ID添加到每个路由,因为如果用户向我或其他支持者/管理员发送链接,我们将看到用户看到的内容.你明白?

我现在就有这个.

_welcome                    ANY      ANY    ANY  /
acmedemo_example_index      ANY      ANY    ANY  /{user}/acme/demos
acmedemo_example_edit       ANY      ANY    ANY  /{user}/acme/edit/{id}
acmedemo_example_delete     ANY      ANY    ANY  /{user}/acme/delete/{id}
acmeapi_backup_get          GET      ANY    ANY  /api/acme
acmeapi_backup_edit         POST     ANY    ANY  /api/acme
Run Code Online (Sandbox Code Playgroud)

现在是"问题"......如果路由名称匹配,我想自动为每条路由添加"user"参数preg_match('/^acmedemo_/i').

例如(index.html.twig):

<a href="{{ path('acmedemo_example_index') }}">Show demos</a>
Run Code Online (Sandbox Code Playgroud)

要么

<a href="{{ path('acmedemo_example_edit', {id: entity.id}) }}">Edit demo</a>
Run Code Online (Sandbox Code Playgroud)

希望使用{{ path('acmedemo_example_edit', {id: entity.id, user: app.user.id}) }}!

而"user"参数需要"\ d +".

我想覆盖路由器上的"生成"功能,例如.然后我可以检查是否$router->getUrl()匹配^acmedemo_,然后我可以添加user参数:)

谢谢!

Pat*_*ckB 5

Soooo对我来说是新的一天:D

我重写了路由器和UrlGenerator.

@ Chausser:我很容易解决你的问题1:

acme_demo_example:
    resource: "@AcmeDemoBundle/Controller/"
    type:     annotation
    prefix:   /{user}
Run Code Online (Sandbox Code Playgroud)

现在我有这样的路线.

_welcome                    ANY      ANY    ANY  /
acmedemo_example_index      ANY      ANY    ANY  /{user}/acme/demos
acmedemo_example_edit       ANY      ANY    ANY  /{user}/acme/edit/{id}
acmedemo_example_delete     ANY      ANY    ANY  /{user}/acme/delete/{id}
acmeapi_examples_get        GET      ANY    ANY  /api/acme
acmeapi_examples_edit       POST     ANY    ANY  /api/acme
Run Code Online (Sandbox Code Playgroud)

问题1解决了!

问题2,因为我不想要额外的路线功能或其他东西.我想用<a href="{{ path('acmedemo_example_index') }}">Show demos</a><a href="{{ path('acmedemo_example_edit', {id: entity.id}) }}">Edit demo</a>.

但如果我愿意,我会得到错误.还可以这样做.

我对这项服务的问题是我没有容器>.<

services.yml

parameters:
    router.class: Acme\DemoBundle\Routing\Router
    router.options.generator_base_class: Acme\DemoBundle\Routing\Generator\UrlGenerator
Run Code Online (Sandbox Code Playgroud)

ACME\DemoBundle \路由\路由器

use Symfony\Bundle\FrameworkBundle\Routing\Router as BaseRouter;
class Router extends BaseRouter implements ContainerAwareInterface
{
    private $container;

    public function __construct(ContainerInterface $container, $resource, array $options = array(), RequestContext $context = null)
    {
        parent::__construct($container, $resource, $options, $context);
        $this->setContainer($container);
    }

    public function getGenerator()
    {
        $generator = parent::getGenerator();
        $generator->setContainer($this->container);
        return $generator;
    }

    public function setContainer(ContainerInterface $container = null)
    {
        $this->container = $container;
    }
}
Run Code Online (Sandbox Code Playgroud)

ACME\DemoBundle \路由\发电机\ UrlGenerator

use Symfony\Component\Routing\Generator\UrlGenerator as BaseUrlGenerator;
class UrlGenerator extends BaseUrlGenerator implements ContainerAwareInterface
{
    private $container;

    protected function doGenerate($variables, $defaults, $requirements, $tokens, $parameters, $name, $referenceType, $hostTokens)
    {
        /** Set the default user parameter for the routes which haven't a user parameter */
        if(preg_match('/^acmedemo_/i', $name) && in_array('user', $variables) && !array_key_exists('user', $parameters))
        {
            $parameters['user'] = $this->getUser()->getId();
        }

        return parent::doGenerate($variables, $defaults, $requirements, $tokens, $parameters, $name, $referenceType, $hostTokens);
    }

    public function setContainer(ContainerInterface $container = null)
    {
        $this->container = $container;
    }

    /**
     * @see \Symfony\Component\Security\Core\Authentication\Token\TokenInterface::getUser()
     */
    public function getUser()
    {
        if (!$this->container->has('security.context')) {
            throw new \LogicException('The SecurityBundle is not registered in your application.');
        }

        if (null === $token = $this->container->get('security.context')->getToken()) {
            return null;
        }

        if (!is_object($user = $token->getUser())) {
            return null;
        }

        return $user;
    }
}
Run Code Online (Sandbox Code Playgroud)

问题2解决了!

(我在Symfony*上写的代码*2.3*)

谢谢你的帮助.但这更好我认为=)


rol*_*ebi 5

实际上使用RequestContext::setParameter()方法有一种更简单的方法.此上下文可通过路由器通过Router::getContext()方法获得.

传入请求使用内核侦听器来初始化此上下文,或者在请求范围(例如命令)之外,直接通过调用路由器服务上的方法.

$router->getContext()->setParameter('user', $user->getId());

// where $router is the @router service.
Run Code Online (Sandbox Code Playgroud)

请求侦听器的示例:

namespace AppBundle\Listener;

use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\Routing\RequestContextAwareInterface;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;

/**
 * Add user param to router context on new request.
 */
class UserAwareRouterContextSubscriber implements EventSubscriberInterface
{
    /**
     * @var TokenStorageInterface
     */
    private $tokenStorage;

    /**
     * @var RequestContextAwareInterface
     */
    private $router;

    /**
     * @param TokenStorageInterface        $tokenStorage
     * @param RequestContextAwareInterface $router
     */
    public function __construct(TokenStorageInterface $tokenStorage, RequestContextAwareInterface $router)
    {
        $this->tokenStorage = $tokenStorage;
        $this->router = $router;
    }

    /**
     * {@inheritdoc}
     */
    public static function getSubscribedEvents()
    {
        return [KernelEvents::REQUEST => 'onRequest'];
    }

    /**
     * @param GetResponseEvent $event
     */
    public function onRequest(GetResponseEvent $event)
    {
        if (!$event->isMasterRequest()) {
            return;
        }

        if ($token = $this->tokenStorage->getToken()) {
            $user = $token->getUser();
            if ($user instanceof MyUserClass) { // use your own class here :)
                $this->router->getContext()->setParameter('user', $user->getId());
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

服务配置:

services:
    app.listener.user_aware_router_context:
        class: AppBundle\Listener\UserAwareRouterContextSubscriber
        arguments:
            - '@security.token_storage'
            - '@router'
        tags:
            - {name: kernel.event_subscriber}
Run Code Online (Sandbox Code Playgroud)