我会使用简单的管理路由系统。
例如我现在有这条路线。
_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
现在我将当前用户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
现在问题" ...我想添加"用户"如果路径名称与preg_match('/^acmedemo_/i')
匹配,则自动为每条路线提供参数。
例如(index.html.twig):
<a href="{{ path('acmedemo_example_index') }}">Show demos</a>
或者
<a href="{{ path('acmedemo_example_edit', {id: entity.id}) }}">Edit demo</a>
我不想要使用{{ path('acmedemo_example_edit', {id: entity.id, user: app.user.id}) }}
!
&#34;用户&#34;参数需要&#34; \ d +&#34;。
我想覆盖&#34;生成&#34;例如,路由器上的功能。
然后,我可以检查$router->getUrl()
是否与^acmedemo_
匹配,然后我可以添加user
参数:)
谢谢!
答案 0 :(得分:5)
Soooo给我的新一天:D
我覆盖了路由器和UrlGenerator。
@ Chausser :我轻松修复了您的问题1:
acme_demo_example:
resource: "@AcmeDemoBundle/Controller/"
type: annotation
prefix: /{user}
现在我有这样的路线。
_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
问题1解决了!
现在问题2,因为我不想要额外的路线功能或其他东西。
我想使用<a href="{{ path('acmedemo_example_index') }}">Show demos</a>
和<a href="{{ path('acmedemo_example_edit', {id: entity.id}) }}">Edit demo</a>
。
但如果我愿意,我会得到错误。 还可以这样做。
我对此服务的问题是我没有容器&gt;。&lt;
services.yml
parameters:
router.class: Acme\DemoBundle\Routing\Router
router.options.generator_base_class: Acme\DemoBundle\Routing\Generator\UrlGenerator
的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;
}
}
的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;
}
}
问题2解决了!
(我在Symfony上写的代码 * 2.3 * )
感谢您的帮助。但我认为这更好 =)
答案 1 :(得分:5)
实际上使用RequestContext::setParameter()
方法有一种更简单的方法。此上下文可通过路由器通过Router::getContext()
方法获得。
在kernel listener上使用incoming requests初始化此上下文,或者在请求范围(例如命令)之外,直接通过调用路由器服务上的方法。
$router->getContext()->setParameter('user', $user->getId());
// where $router is the @router service.
请求侦听器的示例:
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());
}
}
}
}
服务配置:
services:
app.listener.user_aware_router_context:
class: AppBundle\Listener\UserAwareRouterContextSubscriber
arguments:
- '@security.token_storage'
- '@router'
tags:
- {name: kernel.event_subscriber}
答案 2 :(得分:1)
有了这个,你有两个主要问题:
问题1
您设置网址的方式需要有2条路线。 http://symfony.com/doc/current/book/routing.html#required-and-optional-placeholders
当然,您可以拥有多个可选占位符(例如/ blog / {slug} / {page}),但可选占位符后面的所有内容都必须是可选的。例如,/ {page} / blog是一个有效的路径,但总是需要页面(即简单/博客与此路线不匹配)。
含义即使你确实覆盖了/acme/demos
请求进入时路由的生成方式,如果期望acmedemo_example_index
,即使/{user}/acme/demos
,它也不会与{user}
匹配是可选的。
为此您有2个可选修复:
FIX 1
有2条路线,一条与用户匹配,另一条与out匹配。两者都指向同一个控制器动作:
acmedemo_example_index ANY ANY ANY /acme/demos
acmedemo_example_index_with_user ANY ANY ANY /{user}/acme/demos
FIX 2
将可选的{user}
参数移至网址的末尾:
acmedemo_example_index ANY ANY ANY /acme/demos/{user}
问题2
您需要一种方法来生成路线。为此,我将创建一个Twig函数,它基本上会执行path()
所做的事情,但会追加用户。
查看有关如何编写树枝扩展名的文档:http://symfony.com/doc/current/cookbook/templating/twig_extension.html
注册分机时,您需要传递一些额外的服务,以便生成路线,以便获得当前用户。
# src/Acme/DemoBundle/Resources/config/services.yml
services:
acme.twig.acme_extension:
class: Acme\DemoBundle\Twig\AcmeExtension
arguments: ["@security.context","@router"]
tags:
- { name: twig.extension }
然后在扩展中你需要使用一个构造函数:
// src/Acme/DemoBundle/Twig/AcmeExtension.php
namespace Acme\DemoBundle\Twig;
class AcmeExtension extends \Twig_Extension
{
protected $user;
protected $router;
public function __construct($security,$router)
{
$this->user = $security->getToken()->getUser();
$this->router = $router;
}
/* Declare your function */
public function acmePath($route,$params,$requirements)
{
if(strpos($route,'acmedemo_')===false){
return $this->router->generate($route,$params,$requirements);
}
/** IF YOU USE FIX 1 **/
array_merge($params,array('user'=>$this->user));
$newRoute = $route.'_with_user';
return $this->router->generate($newRoute ,$params,$requirements);
/** IF YOU USE FIX 2 **/
array_merge($params,array('user'=>$this->user));
return $this->router->generate($route,$params,$requirements);
}
}
然后在您的twig文件中使用acmePath()
而不是path
:
<a href="{{ acmePath('acmedemo_example_index') }}">Show demos</a>
而不是:
<a href="{{ path('acmedemo_example_index') }}">Show demos</a>