9
votes

I want to generate a small form inside a Sonata Admin show template. What I have done so far is creating the function in the custom CRUD for that specific entity (order) that extends from Sonata's default CRUD;

public function approveOrderAction($id = null)
{
    $request = $this->getRequest();

    $id = $request->get($this->admin->getIdParameter());
    $order = $this->admin->getObject($id);

    $approveForm = $this->createFormBuilder($order)
        ->add('reqSecondApprover', 'checkbox', array('label' => 'Require second Approval', 'required' => false))
        ->add('secondApprover', 'choice', array('choices' => Crud::getWhatever(array('Developer')), 'required' => false))
        ->getForm();

    $approveForm->handleRequest($request);

    if ($approveForm->isSubmitted() && $approveForm->isValid()) {
        $secondApproval = $request->request->get('form');
        $approval = $approveForm->getData();

        if (isset($secondApproval['reqSecondApprover'])) {
            $order->setStatus(PmodOrder::STATUS_PARTLY_APPROVED);
        } else {
            $order->setStatus(PmodOrder::STATUS_APPROVED);
            $order->setSecondApprover(null);
        }   

        $em->persist($approval);
        $em->flush();

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

    return $this->render('AppBundle:PmodOrder:order_approve.html.twig', array(
        'order' => $order,
        'form' => $approveForm->createView(),
    ));
}

In my orderAdmin I have the configShowFields method;

protected function configureShowFields(ShowMapper $showMapper)
{
    $order = $this->getSubject();

    $showMapper
        ->with('General')
            ->add('createdBy', null, array('label' => 'Requested By'))
            ->add('createdAt', null, array('label' => 'Date Requested'))
        ->with('Order Details')
            ->add('orderRows', NULL, array('template' => 'AppBundle:PmodOrderRow:orderrow_overview.html.twig'))
        ->end()
        ->with('Actions')
            ->add('actions', NULL, array('template' => 'AppBundle:PmodOrderAction:order_actions.html.twig', 'route' => 'approve'))
        ->end()
    ;
}

The order_actions template looks like this and will show the relevant functionality according to the status of the order and who is logged in, thus how do work with so many diffent routes?;

<td>
    {% if app.user.id == object.firstApprover and object.status == 1%}
        {{ render(controller('AppBundle:PmodOrderCRUD:approveOrder', { 'id': object.id })) }}
    {% elseif app.user.id == object.secondApprover and object.status == 2 %}
        <a href="{{ path('order_second_approve', { 'id': object.id })}}" class="btn btn-primary"><i class="fa fa-check"></i> Approve</a>
        <a href="{{ path('order_disapprove', { 'id': object.id })}}" class="btn btn-default"><i class="fa fa-times"></i> Disapprove</a>
    {% elseif app.user == object.createdBy and object.status == 3 %}
        <a href="{{ path('order_place', { 'id': object.id })}}" class="btn btn-primary">Place Order</a>
        <a href="{{ path('order_place', { 'id': object.id })}}" class="btn btn-default">Cancel Order</a>
    {% else %}
        -
    {% endif %}
</td>

When trying this I get an error;

An exception has been thrown during the rendering of a template ("There is no _sonata_admin defined for the controller ApBundle\Controller\PmodOrderCRUDController and the current route ``") in AppBundle:PmodOrderAction:order_actions.html.twig at line 3.

I understand from the documentation that I need to make use of this configureRoutes method;

protected function configureRoutes(RouteCollection $collection)
{
    $collection->add('clone', $this->getRouterIdParameter().'/clone');
}

But I can't get it to work and I am not sure about how to render forms instead of a simple link button.

Can somebody please help me fix my problem?

1

1 Answers

3
votes

The _sonata_admin (route) attribute is used by SonataAdminBundle to get the required admin instance ($this->admin) and be able to configure/process your requests:

After to add the right route definition:

protected function configureRoutes(RouteCollection $collection)
{
    $collection->add('approve_order', $this->getRouterIdParameter().'/approve');
}

You need to add also the _sonata_admin code to generate the right request to approveOrderAction():

{{ render(controller('QiBssFrontendBundle:PmodOrderCRUD:approveOrder', { 'id': object.id, '_sonata_admin': '...' })) }}

Let's make a simple example:

You have an Order entity and its admin class: OrderAdmin into PurchaseBundle, so this is the Sonata's service definition for OrderAdmin class (Yaml):

services:
    purchase_bundle.admin.order_admin:
        class: PurchaseBundle\Admin\OrderAdmin
        arguments:
            - ~
            - PurchaseBundle\Entity\Order
            - ~
        tags:
            - { name: 'sonata.admin', manager_type: orm }

Now, based on your own approveOrderAction(), you can render this action in the follows way:

{{ render(controller('PurchaseBundle:OrderAdmin:approveOrder', { 'id': object.id, '_sonata_admin': 'purchase_bundle.admin.order_admin' })) }}

Just you have to add the admin code: 'purchase_bundle.admin.order_admin' and it should work!