Pavel Petrov
Pavel Petrov

Reputation: 867

How to add extra bag to symfony session

I want to add an extra bag to symfony session.

I do that in compiler pass:

public function process(ContainerBuilder $container)
{   
    $bag = new AttributeBag("my_session_attributes");

    $container->getDefinition("session")
        ->addMethodCall("registerBag", [$bag]);
}

But i get an exception with message:

Unable to dump a service container if a parameter is an object or a resource.

Here is the trace stack:

  1. in XmlDumper.php line 379
  2. at XmlDumper::phpToXml(object(AttributeBag)) in XmlDumper.php line 328
  3. at XmlDumper->convertParameters(array(object(AttributeBag)), 'argument', object(DOMElement)) in XmlDumper.php line 94
  4. at XmlDumper->addMethodCalls(array(array('registerBag', array(object(AttributeBag)))), object(DOMElement)) in XmlDumper.php line 183
  5. at XmlDumper->addService(object(Definition), 'session', object(DOMElement)) in XmlDumper.php line 272
  6. at XmlDumper->addServices(object(DOMElement)) in XmlDumper.php line 52
  7. at XmlDumper->dump() in ContainerBuilderDebugDumpPass.php line 34
  8. at ContainerBuilderDebugDumpPass->process(object(ContainerBuilder)) in Compiler.php line 104
  9. at Compiler->compile(object(ContainerBuilder)) in ContainerBuilder.php line 598
  10. at ContainerBuilder->compile() in Kernel.php line 514
  11. at Kernel->initializeContainer() in Kernel.php line 133
  12. at Kernel->boot() in Kernel.php line 182
  13. at Kernel->handle(object(Request)) in app_dev.php line 29

How should I add new bag if I can't pass object arguments in service definitions?

Upvotes: 2

Views: 2327

Answers (3)

Syfon
Syfon

Reputation: 1

Another approach would be to add a new AttributeBag through an EventListener.

Something like this:

<?php
 
namespace App\EventListener;
 
use Symfony\Component\HttpKernel\Event\RequestEvent; 
use Symfony\Component\HttpFoundation\Session\Attribute\AttributeBag;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
 
class AddSessionAttributeBagListener
{
    
    /**
     * @param RequestEvent $event
     */
    public function onKernelRequest(RequestEvent $event)
    {
        if (!$event->isMainRequest()) {
            return;
        }

        $session = $event->getRequest()->getSession();
        $bag = new AttributeBag('metrics');
        $bag->setName('metrics');
 
        $session->registerBag($bag);
    }
}

When registering the event listener, set priority to make sure it's executed at the right moment

    app.event_listener.add_session_attribute_bag:
        class: App\EventListener\AddSessionAttributeBagListener
        tags:
            - { name: kernel.event_listener, event: kernel.request, method: onKernelRequest, priority: 127}

Upvotes: 0

job3dot5
job3dot5

Reputation: 900

This matter is not clear in doc, your example helped a bit but I think there is a more clean way to add a bag to symfony session, here is what I did (symfony 4+)

Add a bag class, for instance you can extends the AttributeBag one

namespace App\Tracking;
use Symfony\Component\HttpFoundation\Session\Attribute\AttributeBag;    

class TrackingBag extends AttributeBag
{
    public function __construct(string $storageKey = 'trackings')
    {
        parent::__construct($storageKey);
        $this->setName($storageKey);
    }
}

Then add a CompilerPass

public function process(ContainerBuilder $container)
{
    $container->getDefinition("session")->addMethodCall(
        "registerBag",
        [new Reference('App\\Tracking\\TrackingBag')]
    );
}

Then you can use it like that in twig

{{ app.session.bag('trackings').all }}

I still believe there is cleaner way but this was the only one which worked for me.

Upvotes: 1

Pavel Petrov
Pavel Petrov

Reputation: 867

Ok, just after posting the question I had an idea which I consider a workaround but it works.

The AttributeBag has to be registered as service too:

public function process(ContainerBuilder $container)
{   
    $bagDefinition = new Definition();
    $bagDefinition->setClass(AttributeBag::class);
    $bagDefinition->addArgument("my_session_attributes");
    $bagDefinition->addMethodCall("setName", ["my_session_attributes"]);
    $bagDefinition->setPublic(false);
    $container->setDefinition("my_session_attributes_service", $bagDefinition);

    $container->getDefinition("session")
        ->addMethodCall("registerBag", [new Reference("my_session_attributes_service")]);
}

Upvotes: 2

Related Questions