Question

Here is what I am trying to accomplish:

I have a simple app that manages product and category entities. The CRUD for these is managed with SonataAdmin.

My Product entity is associated with the Category entity (many-to-one association). What I want is that when Sonata's CRUD shows the form to create Products, in the category select, it lists only the categories on which the user has an EDIT Access Control Entry.

Here is some code to illustrate this:

Product entity

<?php

namespace Acme\DemoBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * Product
 *
 * @ORM\Table()
 * @ORM\Entity
 * @ORM\HasLifecycleCallbacks()
 */
class Product
{

    /**
     * @var integer id
     *
     * @ORM\Id
     * @ORM\Column(name="id", type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @var string
     *
     * @ORM\Column(name="name", type="string", length=255)
     */
    private $name;

    /**
     * @var float
     *
     * @ORM\Column(name="price", type="float")
     */
    private $price;

    /**
     * @var string
     *
     * @ORM\Column(name="description", type="text")
     */
    private $description;

    /**
     * @ORM\ManyToOne(targetEntity="Category", inversedBy="products")
     * @ORM\JoinColumn(name="category_id", referencedColumnName="id")
     */
    protected $category;

    /**
     * Get id
     *
     * @return integer 
     */
    public function getId()
    {
        return $this->id;
    }

    /*Getters and setters
    ...
    */
}

Category entity

<?php

namespace Acme\DemoBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;

/**
 * Category
 *
 * @ORM\Table()
 * @ORM\Entity
 */
class Category
{
    /**
     * @var integer
     *
     * @ORM\Id
     * @ORM\Column(name="id", type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @var string
     *
     * @ORM\Column(name="name", type="string", length=255)
     */
    private $name;

    /**
     * @ORM\OneToMany(targetEntity="Product", mappedBy="category")
     */
    protected $products;

    public function __construct()
    {
        $this->products = new ArrayCollection();
    }

    /*Getters and setters
    ...
    */
}

The ProductAdmin for Sonata CRUD

<?php

namespace Acme\DemoBundle\Admin;

use Symfony\Component\Security\Acl\Domain\ObjectIdentity;
use Symfony\Component\Security\Acl\Domain\UserSecurityIdentity;
use Symfony\Component\Security\Acl\Permission\MaskBuilder;

use Sonata\AdminBundle\Admin\Admin;
use Sonata\AdminBundle\Datagrid\ListMapper;
use Sonata\AdminBundle\Datagrid\DatagridMapper;
use Sonata\AdminBundle\Form\FormMapper;

class ProductAdmin extends Admin
{

    // Fields to be shown on create/edit forms
    protected function configureFormFields(FormMapper $formMapper)
    {
        $formMapper
            ->add('name', 'text', array('label' => 'Product name'))

            // HOWTO FILTER THESE ???
            ->add('category', 'entity', array('class' => 'Acme\DemoBundle\Entity\Category'))

            ->add('price')
            ->add('description')
        ;
    }

    /* More here, but kept short for the example
    ...
    */

}

What I'd like is a way to check for ACL in the ProductAdmin::configureFormFields whithin the call to ->add('category', 'entity', array('class' => 'Acme\DemoBundle\Entity\Category'))

Any help much appreciated. FL.

Was it helpful?

Solution

A solution would be to filter your entity list with the query_builder option of your field (doc is here) but I'm not sure about how to create a query builder filtering on ACL.

Another (better?) solution I see is :

  1. declare your form as a service (doc)
  2. inject the security context as a dependance and any other dependance you need
  3. request the list of Category you want in your form using injected services
  4. set your form categories with the choices option of entity field, give its your Category list as an array (doc)

Should works...

OTHER TIPS

I'm writing this answer just to make F.L. comment in maphe answer standing up, as it was the solution for his own question and a great help for me.

The Symfony cookbook has the answer documented: http://symfony.com/doc/current/cookbook/form/dynamic_form_modification.html

The document describes how to solve many common problems where dynamic forms are needed. I cite the intro of the document here:

Often times, a form can't be created statically. In this entry, you'll learn how to customize your form based on three common use-cases:

  1. Customizing your Form Based on the Underlying Data

    Example: you have a "Product" form and need to modify/add/remove a field based on the data on the underlying Product being edited.

  2. How to dynamically Generate Forms Based on user Data

    Example: you create a "Friend Message" form and need to build a drop-down that contains only users that are friends with the current authenticated user.

  3. Dynamic Generation for Submitted Forms

    Example: on a registration form, you have a "country" field and a "state" field which should populate dynamically based on the value in the "country" field.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top