10. Decouple from CRUDControllerΒΆ

New in version 3.99: The ability to inject an Admin to an action and AdminFetcherInterface service were introduced in 3.99.

When creating custom actions, we can create our controllers without extending CRUDController. What we usually need is to access the admin instance associated to the action, to do so we can type-hint to the admin class or use the AdminFetcherInterface service.

You can add your Admin as parameter of the action:

// src/Controller/CarAdminController.php

namespace App\Controller;

use Symfony\Component\HttpFoundation\RedirectResponse;

final class CarAdminController
{
    public function clone(CarAdmin $admin, Request $request)
    {
        $object = $admin->getSubject();

        // ...

        $request->getSession()->getFlashBag()->add('sonata_flash_success', 'Cloned successfully');

        return new RedirectResponse($admin->generateUrl('list'));
    }
}

Or you can use AdminFetcherInterface service to fetch the admin from the request, in this example we transformed the controller to make it Invokable:

// src/Controller/CarAdminController.php

namespace App\Controller;

use Symfony\Component\HttpFoundation\RedirectResponse;

final class CarAdminSoldAction
{
    /**
     * @var AdminFetcherInterface
     */
    private $adminFetcher;

    public function __construct(AdminFetcherInterface $adminFetcher)
    {
        $this->adminFetcher = $adminFetcher;
    }

    public function __invoke(Request $request)
    {
        $admin = $this->adminFetcher->get($request);

        $object = $admin->getSubject();

        // ...

        $request->getSession()->getFlashBag()->add('sonata_flash_success', 'Sold successfully');

        return new RedirectResponse($admin->generateUrl('list'));
    }
}

Now we only need to add the new route in configureRoutes:

use App\Controller\CarAdminCloneAction;
use Sonata\AdminBundle\Route\RouteCollection;

protected function configureRoutes(RouteCollection $collection)
{
    $collection
        ->add('clone', $this->getRouterIdParameter().'/clone', [
            '_controller' => 'App\Controller\CarAdminController::clone',
        ])

        // Using invokable controller:
        ->add('sold', $this->getRouterIdParameter().'/sold', [
            '_controller' => CarAdminSoldAction::class,
        ]);
}