📜 ⬆️ ⬇️

SonataAdminBundle: Creating an Object from a List View (Part 1)

Formulation of the problem


There is a set of some objects, for example, incoming one-to-one communications (for the purposes of this article, the type of communication does not matter) with objects from another set, for example, responses to letters. SonataAdminBundle is used to manage entities (i.e., an Admin class is defined for each entity). It is necessary to create new answers directly from the List View of the letters.

Entity entities, respectively, letters and responses can look like this:

The essence of the incoming letter
namespace AppBundle\Entity; use Doctrine\ORM\Mapping as ORM; /** * @ORM\Entity * @ORM\Table(name="incoming", options={"comment":" "}) */ class Incoming { /** * @ORM\Column(type="integer") * @ORM\Id * @ORM\GeneratedValue(strategy="AUTO") */ protected $id; protected $incomingTitle; /** * @ORM\OneToOne(targetEntity="Response", mappedBy="incoming") */ protected $response; //   /** *      * * @param \AppBundle\Entity\Response $response * * @return \AppBundle\Entity\Incoming */ public function setResponse( \AppBundle\Entity\Response $response) { $this->response = $response; return $this; } } 


The essence of the response to the incoming letter
  namespace AppBundle\Entity; use Doctrine\ORM\Mapping as ORM; /** * @ORM\Entity * @ORM\Table(name="response", options={"comment":"   "}) */ class Response { /** * @ORM\Column(type="integer") * @ORM\Id * @ORM\GeneratedValue(strategy="AUTO") */ protected $id; /** * @ORM\Column(type="text", options={"comment":" "}) */ protected $responseTitle; /** * @ORM\OneToOne(targetEntity="Incoming", inversedBy="response") * @ORM\JoinColumn(name="incoming_id", referencedColumnName="id") */ protected $incoming; /** * @ORM\Column(type="text", options={"comment":" "}) */ protected $text; /** *    * * @param \AppBundle\Entity\Incoming $incoming * * @return \AppBundle\Entity\Response */ public function setResponse( \AppBundle\Entity\Incoming $incoming) { $this->incoming = $incoming; return $this; } //  } 


Solution options


At first glance, solving the problem is similar to creating a Custom Admin Action in SonataAdminBundle, the process of which is described in [1] . Following this guide, we could implement an action that creates and saves the response object, attaches it to the current letter object and redirects the user to the edit form of the saved answer to enter its title and text.

In this case, we would need:
')

Such an approach is attractive because for its implementation it is sufficient to strictly follow the guidelines for creating the Custom Admin Action, but it leads to duplication of code and is fraught with unforeseen errors when finalizing createAction before createResponseAction. You can avoid the drawbacks of the approach by directly using the existing and also redefining the Sonata \ AdminBundle \ Controller \ CRUDController intended for this action.

To do this, we will solve the problem in stages:


Go to the form to create a new response


The process of creating a control in the ListView row is described in detail in [1] . Let us dwell on the features relating to the solution of our problem, namely, generating the url to switch to the form of creating a new object. Offered in [1] option

 {# src/AppBundle/Resources/views/CRUD/list__action_create_other_admin.html.twig #} <a class="btn btn-sm" href="{{ admin.generateObjectUrl('create', object) }}"> </a> 

not suitable, since the admin.generateObjectUrl function generates a url to create an object of the current Admin class; in our case, this is a letter (Incoming), but it is necessary that there be an answer (Response). Therefore, we use the following option, decorating the button with the icon:

 {# src/AppBundle/Resources/views/CRUD/list__action_create_other_admin.html.twig #} <a href="{{ admin.getRouteGenerator.generateUrl(template_variables.otherAdmin, 'create') }}" class="btn btn-sm btn-default edit_link" title=" "> <i class="fa fa-plus"></i>   </a> 

The key point here is the use of the admin.getRouteGenerator.generateUrl function, which takes as its argument the Admin service, to create an object of which you need to generate a url. Now the task is to transfer the desired Admin service to the template. This can be done by accessing the Symfony2 container directly from list__action_create_other_admin.html.twig, which will deprive the approach of universality, so we used the variable template_variables.otherAdmin, which is passed to the template as described below.

The templates corresponding to the _actions buttons in the ListView row are displayed using the SonataAdminBundle CRUD \ list__action.html.twig include template twig function, namely:

 {% include actions.template %} 

where actions.template is a variable that is defined in the Admin class in the configureListFields section.

  protected function configureListFields(ListMapper $listMapper) { $listMapper // other fields... ->add('_action', 'actions', array( 'actions' => array( // ... 'createOtherAdmin' => array( //    'template' => 'AppBundle:CRUD:list__action_create_other_admin.html.twig' ) ) )) ; } 

Thus, we need to add the with keyword to the CRUD \ list__action.html.twig to ensure that the variable is passed to the child templates. Since not all of them will use this variable, you should check for its presence:

  {% include actions.template with {template_variables : (actions.template_variables is defined ? actions.template_variables : null)} %} 

Now you can define the template_variables.otherAdmin variable in the admin class, assigning the required Admin service (in our case, sonata.admin.response) to it and it will be available in the list__action_create_other_admin.html.twig template.

  protected function configureListFields(ListMapper $listMapper) { $listMapper // other fields... ->add('_action', 'actions', array( 'actions' => array( // ... 'createOtherAdmin' => array( 'template' => 'AppBundle:CRUD:list__action_create_other_admin.html.twig', //  Admin-      'template_variables' => array('otherAdmin'=> $this->getConfigurationPool()->getContainer()->get('sonata.admin.response');) ) ) )) ; } 

Now, when you click on the button in the List View line of letters, a form opens to create a reply to the letter.

In the second part of the article, the implementation of automatic linking between the letter and the answer to it, as well as questions about the button display depending on whether the user has the rights to create the answer, is considered.


Links to used resources


  1. CREATING A CUSTOM ADMIN ACTION

Source: https://habr.com/ru/post/278987/


All Articles