Symfony:如何在包含Twig控制器中设置Cookie和Session变量?

时间:2016-12-12 08:42:30

标签: session cookies controller twig symfony

这是我的第一篇文章,如果有任何问题,请告诉我:)。

我正在使用Symfony构建一个网站,但我目前遇到了一个问题: 我无法在包含Twig控制器{{ render(controller("AcmeCoreBundle:Auth:index")) }}中设置(或肯定我遗漏了一些)cookie和会话变量(此控制器必须允许来自每个网站页面的“连接”)

我使用实体WhoIsIt和表单类型WhoIsIt

创建了表单
<?php

namespace Acme\CoreBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Cookie;
use Acme\CoreBundle\Form\WhoIsItType;
use Acme\CoreBundle\Entity\WhoIsIt;

class AuthController extends Controller
{
    public function indexAction(Request $request)
    {

        $who = new WhoIsIt;
        $session = $this->get('session');
        $response = new Response();
        $form = $this->get('form.factory')->create(WhoIsItType::class, $who);

        if ($request->isMethod('POST')) {
          $form->handleRequest($request);
          if ($form->isValid()) {
              $whoisit = $form->getData();
              //I set Cookie and Session variables

              $response->headers->setCookie(new Cookie('personality', $whoisit->getPersonality(), time() + 3600 * 24 * 3));
              $session->set('personality', $whoisit->getPersonality());
              $response->setContent($this->render('AcmeCoreBundle:Form:Auth.html.twig', array(
                        'form' => $form->createView())));
              return $response;
          }
    }

    $cookies = $request->cookies;
    $who->setPersonality($this->setDefault('personality', 'personality.supporter', $cookies, $session));
    $form = $this->get('form.factory')->create(WhoIsItType::class, $who);
    $response->setContent($this->render('AcmeCoreBundle:Form:Auth.html.twig', array(
        'form' => $form->createView())));
    return $response;
}

private function setDefault($element, $default, $cookies, $session)
{
//This fonction help me to define the default value of the form
    if ($session->has($element))
    {
        return $session->get($element);
    }
    elseif ($cookies->has($element))
    {
        return $cookies->get($element);
    }
    return $default;
}
}

当我在Symfony Profiler中查找响应时,我得到一个POST参数:

who_is_it   [ personality => personality.supporter, validate => ], _token => 9ACFB8AO53e7M5QMoqyptVhNqOj933SoMYRfKZsNRJ4 ]

并且不要获取名为personality

的Cookie或Session变量

我想知道是否可以在SubRequest中设置cookie / session? 如果可能,我应该在代码中更改什么?

我希望你理解我的问题:)如果你没有,或者需要更多精确度,请通过评论告诉我。

感谢您的帮助。

2 个答案:

答案 0 :(得分:0)

这是我访问我的网站时创建会话的方式:
我需要检查网站网址以找到合适的实体。希望它会对你有所帮助。

1:注册服务

<强> 的appbundle \资源\配置\ services.yml

app.session_handler:
    class: SalonBundle\Services\SessionHandler
    arguments:
        - "@doctrine"
        - "@router"
    tags:
        - { name: kernel.event_listener, event: kernel.request, method: setSession }

首先,我将指出我使用参数@router,但除非您需要将响应重定向到另一个网址,否则不需要。

2:创建服务

<强> 的appbundle \事件监听\ SessionHandler.php

<?php

namespace AppBundle\Services;

use Doctrine\Bundle\DoctrineBundle\Registry;
use Symfony\Bundle\FrameworkBundle\Routing\Router;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\PropertyAccess\PropertyAccess;

class SessionHandler {

    private $doctrine;
    private $router;

    public function __construct(Registry $doctrine, Router $router) {
        //Make sure to type $doctrine and $router in the constructor.
        //Else some methods can't be found directly, and Symfony have to do the job for you
        //I guess it would make a big project a bit slower without the types
        $this->doctrine=$doctrine;
        $this->router=$router;
    }

    public function setSession(GetResponseEvent $responseEvent) {
        //This function parameter call on GetResponseEvent class
        //for the same reason as above.
        $accessor=PropertyAccess::createPropertyAccessor();
        //accessor will be used to get a parameter from an entity stored in session.
        $session=$responseEvent->getRequest()->getSession();
        //Fetching the existing session
        $site=$session->get('site');
        //Fetching object in session, return null if doesn't exists
        $url=$responseEvent->getRequest()->getSchemeAndHttpHost();
        //Fetching my site current base URL
        if(!$site) {
            //If site isn't in session
            $site=$this->doctrine->getRepository('AppBundle:Site')->findOneBy(array('url'=>$url));
            //Fetch object based on site URL
            if($site) {
                //If found, send it to session to make sure we don't keep searching for it on each page loading
                $session->clear();
                $session->set('site', $site);
            } else {
                //Else send to dashboard and go create it
                if($responseEvent->getRequest()->get('_route') != 'dashboard_site') {
                    $responseEvent->setResponse(new RedirectResponse($this->router->generate('dashboard_site')));
                }
            }
        } else {
            //If site is in session
            if($accessor->getValue($site, 'url') != $url) {
                //Use of accessor to fetch url param from site object and check if object url is same as website url
                $site=$this->doctrine->getRepository('AppBundle:Site')->findOneBy(array('url'=>$url));
                if($site) {
                    $session->clear();
                    $session->set('site', $site);
                } else {
                    if($responseEvent->getRequest()->get('_route') != 'dashboard_site') {
                        $responseEvent->setResponse(new RedirectResponse($this->router->generate('dashboard_homepage')));
                    }
                }
            }
        }
    }
}

我还建议阅读此question,它与当前问题配对。

答案 1 :(得分:0)

好吧,我找到了解决问题的方法。

对于我的第一个问题,我需要将原始请求作为参数:

{{ render(controller("AcmeCoreBundle:Auth:index", {'cookies': app.request.cookies})) }}

做一些其他的黑客攻击(js重定向等......)

但是,现在我使用另一个控制器来捕获&#39; POST&#39;,为此,当我创建表单时,我需要指定一个选项:

$form = $this->get('form.factory')->create(WhoIsItType::class, $who, array(
                        'action' => $this->generateUrl('acme_core_auth'))
                        );

然后我创建了正确的动作:

public function authAction (Request $request)
    {
        $who = new WhoIsIt;
        $session = $this->get('session');
        $form = $this->get('form.factory')->create(WhoIsItType::class, $who);
        if ($request->isMethod('POST')) {
            $form->handleRequest($request);
            if ($form->isValid()) {
                $whoisit = $form->getData();                    
                $response = new RedirectResponse($request->headers->get('referer')); //Here I create a redirection to the current webpage
                $response->headers->setCookie(new Cookie('personality', $whoisit->getPersonality(), time() + 3600 * 48)); I set a new cookie in the response header
                $session->set('personality', $whoisit->getPersonality()); // I update session var
                return $response;         

            }
        }
        return $this->redirectToRoute('acme_core_homepage'); //If not in post/valid I redirect to the homepage
    }

最后代码是:

Acme \ CoreBundle \ Controller \ AuthController.php

<?php

namespace Acme\CoreBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Cookie;
use Acme\CoreBundle\Form\WhoIsItType;
use Acme\CoreBundle\Entity\WhoIsIt;

class AuthController extends Controller
{
    public function indexAction($cookies)
    {

        $who = new WhoIsIt;
        $session = $this->get('session');
        $who->setPersonality($this->setDefault('personality', 'eventType.All', $cookies, $session));
        $form = $this->get('form.factory')->create(WhoIsItType::class, $who, array(
                            'action' => $this->generateUrl('acme_core_auth'))
                            );
        return $this->render('AcmeCoreBundle:Form:Auth.html.twig', array(
            'form' => $form->createView()));
    }

    public function authAction (Request $request)
    {
        $who = new WhoIsIt;
        $session = $this->get('session');
        $form = $this->get('form.factory')->create(WhoIsItType::class, $who);
        if ($request->isMethod('POST')) {
            $form->handleRequest($request);
            if ($form->isValid()) {
                $whoisit = $form->getData();
                $response = new RedirectResponse($request->headers->get('referer'));
                $response->headers->setCookie(new Cookie('personality', $whoisit->getPersonality(), time() + 3600 * 48));
                $session->set('personality', $whoisit->getPersonality());
                return $response;         
            }
        }
        return $this->redirectToRoute('acme_core_homepage');
    }

    //This set default according to the order session>cookies>default
    private function setDefault($element, $default, $cookies, $session)
    {
        if ($session->has($element))
        {
            return $session->get($element);
        }
        if ($cookies->has($element))
        {
            $default = $cookies->get($element);
        }
        $session->set($element, $default);
        return $default;
    }
}

我希望这可以帮助其他人:)