I have a formMapper Sonata. I have add the prePersist and preUpdate function who are performing some checks before approving changes.
If it fail, I would like to display a nice error message. I have seen that there is some flags who can use but nothing really interesting. Even more, a return false does not stop the action.
Des someone know how could I manage this feature ?
Thanks a lot.
You can show a flash message in your hooks accessing the getRequest method.
public function prePersist($object) {
$this->getRequest()->getSession()->getFlashBag()->add('error', 'Error message');
}
To stop an action from inside an Admin hook, I found that the best way is to throw a ModelManagerException. This particular exception is, in fact, handled by the CRUDController.
Not too clean I have to admit, but effective.
Note: The way to access the flashbag may be a little different with respect to your SonataAdmin version.
I don't really understand what you don't get in the doc. Here it says that in your controller you need to add
$session->getFlashBag()->add('key', 'message');
And to get it in the view :
{% for message in app.session.flashbag.get('key') %}
<p>{{ message }}</p>
{% endfor %}
What you are probably searching for is a custom validator constraint.
The validator will automatically check for all validator constraints when you submit a sonata form. If there's an error, the entity is not persisted and a nice message is displayed (depending on what constraint validation message you set).
Related
I am a total beginner in Symfony. I would like to implement a master detail view in Symfony. So I have a table with user entries shown in a twig template. If a user clicks one of the rows, in the lower part of the page the users details should be shown. How is this best done with Symfony?
Should I use a fragment with hidden content if the parameter from controller for details is empty?
e.g. {% if .... }
Should I use javascript to call the controller action?
Thank you.
I my application i have a listview representing News-items. On each row end i want to add a plus-sign button and by clicking it, a little inline form should pop up in a bubble (via bootstrap dropdown). To render this form, my actually approach is to render this via the render(controller(...)) mechanism in the field template.
{% extends 'SonataAdminBundle:CRUD:base_list_field.html.twig' %}
{% block field %}
{{ render(controller(...)) }}
{% endblock %}
The render controller call renders a form according to the official symfony documentation ...
The rendered form sends it data back to the commentAction in the same controller.
In theory it works fine, but practical its slow as hell. My site runs in timeout after 60 seconds just because in the listview are default 64 items shown and each item calls this render controller function ...
Is there a clean way to render a little extra form not by invoking a expensive render controller call?
I think it could work with manipulating the listAction method in the controller (injecting here the extra form?) ... but this does not seem a clean solution.
Any ideas?
Thanks
Edit:
Ok, i think i found out, where the bottleneck is ... the example above was simplified. In reality i load a collection into the form for every row ... in the form you can choose, which author created the news. There are at least 500 Authors in that list ... so displaying these authors for a single new, everything is fine. But rendering the choose options 64 times is too much. Is there a way to make this faster? Some caching mechanism?
I think in this case, instead of rendering all forms at once, just load the form via AJAX once user click on the button. Another solution could be to replace collection for some autocomplete somyou dont need to render all data at once.
I have this piece of code in several Twig templates:
{% if is_granted('IS_AUTHENTICATED_REMEMBERED') == false %}
{{ render(controller('FOSUserBundle:Security:login')) }}
{% include 'FOSMapyetBundle:Registration:register.html.twig' with {form:form} %}
{% endif %}
As you may see it receive the parameter form from controllers but here comes the problem in every site I like to use the code lets said in templates I need to pass the parameter form to the view. By now it's only on 15 templates but this make me think, what about if tomorrow should be 20 or 60 or even 100 templates? So what is the best solution to handle this? Twig Extensions? Symfony Services? Any advice or help on this one?
A kernel event listener may work for this. Render your mini template inside the listener and then "inject" it into the final response, similar to how the debug toolbar works:
https://github.com/symfony/symfony/blob/master/src/Symfony/Bundle/WebProfilerBundle/EventListener/WebDebugToolbarListener.php#L106
Note that this is the approach you may want if you want to modify all pages universally. You can apply checks inside the listener to ignore ajax requests, redirection, and the like. You could also probably implement a simple map that knows which routes should have the response modified.
If you want to explicitly render the template in specific pages, then I agree with Maerlyn.
When you need logic like this, your best option is to render a sub-controller, like you already do with your login form.
Create a RegistrationController in your bundle that creates the form and returns the rendered register.html.twig, then embed it like the line above the include.
You can use Response event, and inject your peace on code at the end of the template.
http://api.symfony.com/2.4/Symfony/Component/HttpKernel/KernelEvents.html
I've got a small question here: is there a way to do some actions after a template has been rendered ? A sort of Listener or hook which is called after a specific template has been rendered ?
In my case I want to know the last datetime the user visited the homepage. If I persist this value in the Controller, so before the rendering of the corresponding template, I won't be able to use my app.user.getLastHomepageVisit datetime variable in the twig template, as the value of the latter variable would be 'now' which is not what I want. I want to update and persist this value to 'now' after the page has been rendered.
Thanks!
There's a hook on kernel.response:
http://symfony.com/doc/current/cookbook/event_dispatcher/before_after_filters.html
I try to call controller/view in another view. I have a homepage Default:index using a block view of my controller Event and I want to put this block.html.twig in my folder of my controller. In my controller Event, I want an action block, in this way I keep the logic of events, in my controller Event.
How can I do for in Event:index.html.twig call my controller/view ?
I saw the helper render, but I think it makes many requests to include the result.
You seem to be on the right track. When calling sub-renders from a view, you have several options, as detailed here: http://symfony.com/doc/current/book/templating.html
The one I think you're looking for is:
{{ render(controller('YourBundle:Event:index')) }}
which will call the controller action and relevant view.
As an aside, if you want a sub-render, but require no controller logic, use
{{ include('YourBundle:Event:index.html.twig') }}
as this seems to be a lot more lightweight.
If you need to use any of these with parameters, normal format is used.