To add an object duplication feature to a CRUD list, you
need to modify the list by adding the button, configure a route,
execute object duplication code, and finally, reference the
controller that will host our function in our interface, via its
service.
Adding the button:
In your controller, add the
button by referencing the button template.
Here we set the path
'Admin/list__action_clone.html.twig'. The system will look for the
file at: /templates/Admin/list__action_clone.html.twig
protected function configureListFields(ListMapper $listMapper)
{
$listMapper->addIdentifier('id', null, ['label' => 'id']);
$listMapper->addIdentifier('label', null, ['label' => 'type']);
$listMapper->addIdentifier('description', null, ['label' => 'Label']);
$listMapper->add('actif', null, ['editable' => true]);
$listMapper->add('_action', null, [
'actions' => [
'clone' => [
'template' => 'Admin/list__action_clone.html.twig'
]
]
]);
}
The content of our twig file is very simple. It's just the display of an icon.
<a class="btn btn-sm btn-default"
href="{{ admin.generateObjectUrl('clone', object) }}"
title="{{ 'Clone'|trans({}, 'default') }}"
alt="{{ 'Clone'|trans({}, 'default') }}">
<i class="fa fa-clone"></i>
</a>
The next step is to create the route in our controller:
protected function configureRoutes(RouteCollection $collection)
{
$collection->add('clone', $this->getRouterIdParameter().'/clone');
}
And the last step, clone our object along with all of its
configurations. To do this, we will create a controller
specifically dedicated to managing our additional functions and
add it to our service so it becomes available.
In App/Admin
we're going to create a file called CustomAction.php which will
contain our function cloneAction().
This must be extended by
CRUDController and not AbstractAdmin as with our interfaces. This
is why we put our function in a new file. But it also allows us to
reuse this function if needed.
In src/Admin/CustomAction.php:
<?php
namespace App\Admin;
use Sonata\AdminBundle\Controller\CRUDController;
use Symfony\Component\HttpFoundation\RedirectResponse;
class CustomAction extends CRUDController
{
/**
* @param $id
*/
public function cloneAction($id)
{
$object = $this->admin->getObject($id);
$objectConf=$object->getWtypeWconf()->toArray();
if (!$object) {
throw new NotFoundHttpException(sprintf('unable to find the object with id: %s', $id));
}
$clonedObject = clone $object;
$clonedObject->unsetId();
$clonedObject->setLabel($object->getLabel().' clone('.uniqid().')');
$this->admin->create($clonedObject);
if(!empty($objectConf)){
foreach($objectConf as $c){
$clonedConf=clone $c;
$clonedConf->setWconfTypcont($clonedObject);
$this->admin->create($clonedConf);
}
}
$this->addFlash('sonata_flash_success', 'L\'élément a correctement été dupliqué.');
return new RedirectResponse($this->admin->generateUrl('list'));
// if you have a filtered list and want to keep your filters after the redirect
// return new RedirectResponse($this->admin->generateUrl('list', ['filter' => $this->admin->getFilterParameters()]));
}
}
As you can see, our clone function is responsible for cloning our
object as well as all of its OneToMany relationships.
The line
$clonedConf->setWconfTypcont($clonedObject); is used to put the id
of the parent relationship in the field of the child relationship.
Otherwise, all objects would keep their relationships with the
initial object.
Last step, we need to reference our new
controller in the service of our interface.
Before:
admin.wtype:
class: App\Admin\WtypeAdmin
arguments: [~, App\Entity\Wtype, ~]
calls:
- [addChild, ["@admin.wconf"]]
tags:
- { name: sonata.admin, manager_type: orm, label: "Types de contrats" }
public: true
After:
admin.wtype:
class: App\Admin\WtypeAdmin
arguments: [~, App\Entity\Wtype, App\Admin\CustomAction]
calls:
- [addChild, ["@admin.wconf"]]
tags:
- { name: sonata.admin, manager_type: orm, label: "Types de contrats" }
public: true