8

I've been googling as crazy the last days trying to figure out (with no success) how override a SonataAdmin action to capture the session username and save it in the foreign key field.

AttachmentAdminController class:

<?php

namespace Application\Sonata\UserBundle\Controller;

use Sonata\AdminBundle\Controller\CRUDController as Controller;
#use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use FOS\UserBundle\Entity\User;
use Symfony\Component\Security\Core\SecurityContextInterface;
use Symfony\Bridge\Monolog\Logger;
use Mercury\CargoRecognitionBundle\Entity\Attachment;

class AttachmentAdminController extends Controller
{
    /**
     * (non-PHPdoc)
     * @see Sonata\AdminBundle\Controller.CRUDController::createAction()
     */
    public function createAction()
    {
        $result = parent::createAction();

        if ($this->get('request')->getMethod() == 'POST')
        {
            $flash = $this->get('session')->getFlash('sonata_flash_success');

            if (!empty($flash) && $flash == 'flash_create_success')
            {
                #$userManager = $this->container->get('fos_user.user_manager');
                #$user = $this->container->get('context.user');
                #$userManager = $session->get('username');
                $user = $this->container->get('security.context')->getToken()->getUser()->getUsername();

                $attachment = new Attachment();
                $attachment->setPath('/tmp/image.jpg');
                $attachment->setNotes('nothing interesting to say');
                $attachment->getSystemUser($user);

                $em = $this->getDoctrine()->getEntityManager();
                $em->persist($product);
                $em->flush();
            }
        }

        return $result;
    }
}

service attachment:

mercury.cargo_recognition.admin.attachment:
    class: Mercury\CargoRecognitionBundle\Admin\AttachmentAdmin
    tags:
        - { name: sonata.admin, manager_type: orm, group: General, label: Attachments }
    arguments: [ null, Mercury\CargoRecognitionBundle\Entity\Attachment, "SonataAdminBundle:CRUD" ]

Seems to me as the actionController() is been ignored by SonataAdminBundle (and maybe the whole class file), because there's not error messages at all, but I don't know why. Actually, I'm not sure if I'm fetching the username from the session.

I really need a good tutorial about this, but seems like any information I get about this is obsolete in some aspect. By the way, I'm using Symfony 2.0.16

abiyi
  • 394
  • 2
  • 6
  • 16
  • Mapping for attachment entity would be helpful in this case. It might be not possible to use username as a fk with D2. You might want to either user.id as a fk. – WizardZ Aug 15 '12 at 05:44
  • I'm not sure what you mean with "map entities". You're right about to use user.id in the foreign key, it was my main concern from the start, in fact, I added a doctrine query to find the user ID from the session username and it works, but... My last problem with override createAction() is that I'm generating two objects and therefor two records in the table (a record from the form, without FK, and another one hardcoded, with a FK). I'm reading about Event Listener using a prePersist() method, cause I NEED just one record, with the user ID logged in the foreign key. – abiyi Aug 15 '12 at 13:35

2 Answers2

10

Finally I got to the solution. I'm sure there are some others (like using event listeners, for example, that seems to be simpler), but right now it's the best I could find (it works, and that's what matters).

I was trying to override the createAction() based on examples that I found in another forum thread, but I was getting two records in the table instead of one only. The most important thing was overriding the WHOLE action method and put the custom code in it.

Controller:

<?php

namespace Mercury\CargoRecognitionBundle\Controller;

use Symfony\Component\Security\Core\SecurityContextInterface;
use Symfony\Bridge\Monolog\Logger;
use Sonata\AdminBundle\Controller\CRUDController as Controller;
use Application\Sonata\UserBundle\Entity\User;
use Mercury\CargoRecognitionBundle\Entity\Attachment;
use Mercury\CargoRecognitionBundle\Entity\SystemUser;
use Mercury\CargoRecognitionBundle\Repository\SystemUserRepository;

class AttachmentAdminController extends Controller
{
    /**
     * Set the system user ID
     */
    private function updateFields($object)
    {
        $userName = $this->container->get('security.context')
                        ->getToken()
                        ->getUser()
                        ->getUsername();

        $user = $this->getDoctrine()
                    ->getRepository('ApplicationSonataUserBundle:User')
                    ->findOneByUsername($userName);

        $object->setSystemUser($user);

        return $object;
    }

    /**
     * (non-PHPdoc)
     * @see Sonata\AdminBundle\Controller.CRUDController::createAction()
     */
    public function createAction()
    {
        // the key used to lookup the template
        $templateKey = 'edit';

        if (false === $this->admin->isGranted('CREATE')) {
            throw new AccessDeniedException();
        }

        $object = $this->admin->getNewInstance();

        $object = $this->updateFields($object);

        // custom method
        $this->admin->setSubject($object);

        $form = $this->admin->getForm();
        $form->setData($object);

        if ($this->get('request')->getMethod() == 'POST') {
            $form->bindRequest($this->get('request'));

            $isFormValid = $form->isValid();

            // persist if the form was valid and if in preview mode the preview was approved
            if ($isFormValid && (!$this->isInPreviewMode() || $this->isPreviewApproved())) {
                $this->admin->create($object);

                if ($this->isXmlHttpRequest()) {
                    return $this->renderJson(array(
                        'result' => 'ok',
                        'objectId' => $this->admin->getNormalizedIdentifier($object)
                    ));
                }

                $this->get('session')->setFlash('sonata_flash_success','flash_create_success');
                // redirect to edit mode
                return $this->redirectTo($object);
            }

            // show an error message if the form failed validation
            if (!$isFormValid) {
                $this->get('session')->setFlash('sonata_flash_error', 'flash_create_error');
            } elseif ($this->isPreviewRequested()) {
                // pick the preview template if the form was valid and preview was requested
                $templateKey = 'preview';
            }
        }

        $view = $form->createView();

        // set the theme for the current Admin Form
        $this->get('twig')->getExtension('form')->setTheme($view, $this->admin->getFormTheme());

        return $this->render($this->admin->getTemplate($templateKey), array(
            'action' => 'create',
            'form'   => $view,
            'object' => $object,
        ));
    }
}

Service for the controller:

mercury.cargo_recognition.admin.attachment:
    class: Mercury\CargoRecognitionBundle\Admin\AttachmentAdmin
    tags:
        - { name: sonata.admin, manager_type: orm, group: General, label: Attachments }
    arguments: [ null, Mercury\CargoRecognitionBundle\Entity\Attachment, "MercuryCargoRecognitionBundle:AttachmentAdmin" ]

I took the solution from the following sites:

(And the Sonata Project documentation)

Mick
  • 30,759
  • 16
  • 111
  • 130
abiyi
  • 394
  • 2
  • 6
  • 16
4

It might be useful to override only the preCreate hook with your own logic:

/**
 * This method can be overloaded in your custom CRUD controller.
 * It's called from createAction.
 *
 * @param mixed $object
 *
 * @return Response|null
 */
protected function preCreate(Request $request, $object)
{
}
Sebastian Viereck
  • 5,455
  • 53
  • 53