A substitute for render(controller()) - symfony

actually in my project I need to display in the navbar if the user have requests. To do this I use in the twig template a:
{{ render(controller("AppBundle:TeamRequest:numberRequests")) }}
The controller is very simple, just do a doctrine request, and generate a view.
But this part of code is slow... It take 200ms more than if I disable it.
Is there a better way to do this ?
PS: Someone know what is the Symfony\Component\HttpKernel\EventListerner\ProfilerListener ? Because it's this part that take a lot of time in the main and subrequest.
Thanks a lot :-)
Thanks to the answers, the idea is to do a service. In my case, I don't change it, because as you can see in graph, the main part of the time is for the debugbar, finally, it takes few ms to generate it.
All the Timeline (Threshold: 50ms)
Only the subrequest Timeline (Threshold: 1ms)

Try to move this function into a service. Then register this service in twig as a global variable. config.yml:
# Twig Configuration
twig:
globals:
number_requests_service: %your_service_name%
Then in twig you can load it:
{{ number_request_service.renderSomething }}
If you need the user request in the service itself, then give them the request_stack in service configuration.

I had the same problem few day ago, and i solve it with a twig extension you can create it like a service and inject your entityManager to do your request and return a view. With this way Symfony2 isn't load a second time.

Related

How to Generate Controller in Symfony 3.0?

Hope you are all fine, I am a beginner trying to learn Symfony 3.0, so I want to generate my controller in a folder called Bundles, but it is not created, here is the command I taped :
php bin/console generate:controller
And this is fine, when I tape the controller name, that was what I wrote :
?[32mController name?[39m: Bundles/FrontBundle
But their answer is :
?[37;41m The controller name must contain a : ("Bundles/FrontBundle"
given, expecting something like AcmeBlogBundle:Post) ?[39;49m
I don't know if I have to do something before this to noy have such error.
Any Help would be much appreciated.
This is because controller name should be a combination of BundleName:ControllerName and you have provided a relative path to your bundle. If that doesn't work make sure you have your autloading properly setup and Symfony knows about your bundle
According to his doc you should use the shortcut notation when you are declaring a controller, entity, etc.
also you need to read the output of the command.
Welcome to the Symfony controller generator
Every page, and even sections of a page, are rendered by a controller.
This command helps you generate them easily.
First, you need to give the controller name you want to generate. You
must use the shortcut notation like AcmeBlogBundle:Post
Controller name: BundleNameEndingBundle:ControllerName

Symfony Forms manual submission of both GET and POST requests

Is there any way to get merged data from Request class? Because currently we are submitting forms manually for API controller that accepts both POST and GET queries (this is not an REST API because of legacy project).
$data = array_merge($request->query->all(), $request->request->all());
$form->submit($data);
Is there any way to write something cleaner instead of code below?
$data = array_merge($request->query->all(), $request->request->all());
I think that is not possible. (Maybe I'm wrong)
If you look at the source code of Request, you can see that when Symfony create the request, Symfony put the global variable $_GET in $this->query and $_POST in $this->request.
There is no Symfony variable that takes both.
If you need it in only one place, I think what you have done is fine.
If not, create a service that will or another solution that factors this code.
Another solution is to use the global variable $_REQUEST, because Symfony makes the merge, but it depends on your php configuration (request_order parameter of your php.ini).
But I do not think using Superglobals variables with Symfony is a good idea ... (Besides symfony overwrites them)

Symfony2: Access Request object in Entity

I'd like to know how to access the Request object in an entity (Symfony2) to modify the user locale.
If someone has found a solution for my problem, please let me know.
It's not possible. This is by design: the entity is just a simple object that should know nothing about the request - it's the responsibility of the controller to interpret the request, and manipulate the entity based on that.
Something like:
//inside your controller:
public function fooBarAction(Request $request)
{
$entity = // get entity
$entity->setLocale($request->getSession()->getLocale());
}
The above is just example code, it won't work if you just copy and paste it. It's just to demonstrate the general idea. The entity should just be a very simple object, who's only responsibility is to hold some data. It shouldn't know where the data is coming from - that keeps it flexible (if you want to set the locale based on something else, you only have to change your controller, not all your entities).
It is possible, but...
What you can but never should do is inject the Request object into the entity (Practically turning your entity into service, see here). Also, even worse idea (but which people still do), you could inject the whole container and get Request from there. The reason why you shouldn't do it is you never should have any code that deals with business rules or any system code in your entities.
You can switch your locale directly in your routes by using _locale custom variable (accessible also from the Request). Or you can create a kernel listener, which will do the required functionality for you. This way you keep your code testable and decoupled.

add custom logic to internal Symfony classes like SwitchUserListener or TemplateGuesser

I got a problem to add custom logic to some Symfony classes.
SwitchUserListener
I want to add a check, that a user cannot switch to a another user, which have more rights/roles, than the initial user.
First attempt
Overwrite the parameter in the security_listeners.xml with the key:
security.authentication.switchuser_listener.class But where can I overwrite it?
In the security.yml it didn't work:
security:
...
authentication:
switchuser_listener:
class: Symfony\Component\Security\Http\Firewall\SwitchUserListener
Second attempt
Overwrite the service for the SwitchUserListner service id: security.authentication.switchuser_listener
I create the same service in my service.xml of my bundle, but my class was not used / called.
Another idea was to overwrite only the class, but that only works for bundles, but the SwitchUserListener was not in the SecurityBundle, it was in the symfony component directory and that seemed to me as a really bad idea to overwrite the SecurityBundle
Third attempt
Now I get the solution: First time I didn't realize that the dispatcher call listener for the SWTICH_USER event in the SwitchUserListener:
$switchEvent = new SwitchUserEvent($request, $token->getUser());
$this->dispatcher->dispatch(SecurityEvents::SWITCH_USER, $switchEvent);
So I need only to create a service with the special tag for this event type:
<tag name="kernel.event_listener" event="security.switch_user" method="onSecuritySwitchUser" />
And do the check in the given method.
This seems to be a better solution thatn the other two. But there is still a problem. In my listener for the SwitchUserEvent I need to ignore my custom check if the user wants to exit the switched user.
So I need to check the requested path: ignore if path containts '?switch_user=_exit'
But the path (URL parameter) can be changed:
# app/config/security.yml
security:
firewalls:
main:
# ...
switch_user: { role: ROLE_ADMIN, parameter: _want_to_be_this_user }
But in my bundle I can't read this parameter, because it will not be passed to the service container. It will be passed to the constructor of the SwitchUserListner class and will be saved there as private attribute, never accessable (without Reflection) from outside. (that happens here: SecurityExtension.php line 591) So what to do? Define the parameter twice go against DRY. Use Reflection?
And the other point is that there aren' every time events that will be fired on which I write a subscriber class. So what would be another / best solution for it?
I ask this question because I will get some similar problem where I want to add or overwrite something of the symfony intern components.
TemplateGuesser
I wanted to modify the TemplateGuesser: For a specific bundle all Templates which has the annotation #Tempalte the tempate file should be located with the controller TestController#showAction at this path:
Resources/views/customDir/Test/show.html.twig
So the guesser should be put and locate everything into a additional folder customDir instead of using only views. When using the render function with a specific template, the guesser should ignore the annotation.
I created my own Guesser and overwrite the service id: sensio_framework_extra.view.guesser and in comparision to the SwitchUserListener this time my class is really called instead of the original guesser. Why it works here but not with the SwitchUserListener?
Is this a good solution at all? I also tried to add a second listener, which calls the TemplateGuesser, its the service sensio_framework_extra.view.listener with the class Sensio\Bundle\FrameworkExtraBundle\EventListener\TemplateListener But that didn't work.
Whenever you need to add custom logic or extend the framework behaviour, you can use and abuse the container configuration. That means you can overwrite pretty much every service Symfony defines by just creating a new class that extends that service – or not, really – and creating the service definition for it with the same key as the original service you wanted to extend or change behaviour.
For instance, Symfony has a base template guesser registered as a service with the sensio_framework_extra.view.guesser id. If you want to extend that or change behaviour, you only need to create your own class and register it with the same id of the original service – remember that the bundles loading order affects the service definitons with the same id, where the last one loaded is the one that will be created.
That should solve both of your problems.

Symfony2 - passing values between ESI and main request

I need to pass a value from the main controller in a route to the controller used by an ESI.
So a controller renders a Twig template and in Twig this is called:
{{ render_esi(url('route_name')) }}
The above renders a controller. It's those two controllers I need to pass information between.
I've noticed that using $request->attributes does't work, even though it would if one wasn't an ESI:
//these WON'T pass between master request and ESI
$request->attributes->set('the_value');
$request->attributes->get('the_value');
Sessions aren't ideal as I would need to ensure they were cleared on some occasions.
I really just want the same request to pass some information once. I was hoping that the $request->attributes would be shared as to me it's one request (although I believe Symfony calls it one master request with various sub-requests and I'm guessing $request->attributes are locked to that scope).
Passing it as a query param in the ESI call isn't good either as it can sometimes be an array of info that needs to be passed.
Any ideas?
You can pass arguments to your action like this:
{{ render_esi(controller('YourBundle:Default:news', { 'max': 5 })) }}
or use route parameters like this
{{ render_esi(url('latest_news', { 'max': 5 })) }}
as correctly answered in this question.

Resources