Adding your own action to the SonataAdminBundle dropdown menu
We are using SonataAdminBundle with our Symfony2 application. When editing an object, I want to add my own action to the dropdown menu that is in the upper right corner, but I have no idea how it works.
I know I can add my own routes via configureRoutes(RouteCollection $collection)
and how to add batch actions or add my own actions behind objects in the list view, but how do I add my own link to the action dropdown in edit view?
It is mostly just a link like "Show me this entity in the interface" so it doesn't need a lot of logic.
source to share
One way is to override the template used when editing. Now you need to do the following:
-
Create a new directory (if you don't already have one) in
app/Resources
that calledSonataAdminBundle
. Inside, create another one calledviews
. This would create a path similarapp/Resources/SonataAdminBundle/views
. This is the main Symfony template. You can read more about this topic here. -
Now you should copy the original template in the same path as it inside the original package. The template file we are interested in is in
sonata-project/admin-bundle/Resources/views/CRUD/base_edit.html.twig
. This means that you need to create another folder insideviews
(the one we just created inapp
is calledCRUD
. So now we have to follow the next pathapp/Resources/SonataAdminBundle/views/CRUD
. Insert the template (base_edit.html.twig
) inside and we can start editing.
Remember that each edit action uses the following template. So it's up to you whether you want to display this link in every edit_action or not. I'll show you one way to limit this to specific actions.
The block that you are going to edit {% block actions %}
, which is responsible for rendering the dropdown. This is how it should look now:
{% block actions %}
<li>{% include 'SonataAdminBundle:Button:show_button.html.twig' %}</li>
<li>{% include 'SonataAdminBundle:Button:history_button.html.twig' %}</li>
<li>{% include 'SonataAdminBundle:Button:acl_button.html.twig' %}</li>
<li>{% include 'SonataAdminBundle:Button:list_button.html.twig' %}</li>
<li>{% include 'SonataAdminBundle:Button:create_button.html.twig' %}</li>
{% endblock %}
Now all that's left to do is insert the link after the last tag <li>
.
{% if admin.id(object) is not null and app.request.get('_route') == 'my_route' %}
<li>
<a href="/generate/path/with/your/route">View in Frontend</a>
</li>
{% endif %}
admin.id(object)
will return the current id of the item being edited. app.request.get('_route')
will return the route of your edit action. You can remove this if you want your link to appear in all edit actions. Change <a href="/generate/path/with/your/route">View in Frontend</a>
your route name using admin.id(object)
, and you should be good to go.
source to share
In your admin class, override the following method:
public function getActionButtons($action, $object = null)
{
$list = parent::getActionButtons($action, $object);
$list['upload'] = [
'template' => ':admin:my_upload_button.html.twig',
];
return $list;
}
This will add a custom action button on all pages of this admin. You can add any logic here to decide on which pages ( $action
-s) you want to display the button.
You can do what you want in the template, but just to complete my example and show the connection to my custom action:
<li>
<a class="sonata-action-element" href="{{ admin.generateUrl('upload') }}">
<i class="fa fa-cloud-upload" aria-hidden="true"></i>
Upload stuff
</a>
</li>
source to share
Another way would be to override the method generateObjectUrl()
in the class of the object class.
/**
* @see \Sonata\AdminBundle\Admin\Admin::generateObjectUrl()
*/
public function generateObjectUrl($name, $object, array $parameters = array(), $absolute = false)
{
if ('show' == $name) {
return $this->getRouteGenerator()->generate('your_route_to_public_facing_view', [
'id' => $this->getUrlsafeIdentifier($object),
], $absolute );
}
$parameters['id'] = $this->getUrlsafeIdentifier($object);
return $this->generateUrl($name, $parameters, $absolute);
}
What is it. No template junk. And no boilerplate code that will work for all other admins.
To get the link to appear automatically, you need to add something in $showMapper
via configureShowFields()
. (If anyone knows a better way, please tell me.)
Overriding generateObjectUrl()
has another bonus: if you click show
on the button $listMapper
, the URL will be updated there.
Edited to say: since this overrides the route show
, you will no longer be able to use this built-in function. This is ok for me, since I need to view my object with all loading css and js frontend.
source to share