Я объясню, что пытаюсь сделать.

У меня есть следующие организации, бренды и типы дилеров.

1 Дилер может иметь множество связанных брендов, и каждое отношение также будет иметь один тип, поэтому связь manyToMany связана с промежуточной таблицей.

Я хочу создать форму для добавления дилеров в нашу систему, и при этом они могут выбирать, какие бренды связаны (брендов немного, поэтому мы хотим отображать их в виде флажков) и какого типа, но пытаясь показать эту форму с помощью до сих пор было сложно.

Бренд Entity

/**
 * Brand
 *
 * @ORM\Table()
 * @ORM\Entity
 */

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

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

/**
 * @ORM\ManyToMany(targetEntity="TypeBrand")
 * @ORM\JoinTable(name="brand_type",
 *      joinColumns={@ORM\JoinColumn(name="brand_id", referencedColumnName="id")},
 *      inverseJoinColumns={@ORM\JoinColumn(name="type_id", referencedColumnName="id")}
 *      )
 */
private $type;

/**
 * @ORM\OneToMany(targetEntity="DealerBrand", mappedBy="brand")
*/
private $dealerBrand;

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

public function __toString()
{
    return $this->getName();
}

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

/**
 * Set name
 *
 * @param string $name
 * @return Brand
 */
public function setName($name)
{
    $this->name = $name;
    $this->setSlug($name);

    return $this;
}

/**
 * Get name
 *
 * @return string 
 */
public function getName()
{
    return $this->name;
}

public function addType(TypeBrand $type)
{
    $this->type[] = $type;
}

public function getType()
{
    return $this->type;
}

public function addDealerBrand($dealerBrand)
{
    $this->dealerBrand[] = $dealerBrand;
}

public function getDealerBrand()
{
    return $this->dealerBrand;
}

}

Дилерская организация

/**
* Dealer
*
* @ORM\Table("dealer")
* @ORM\Entity(repositoryClass="Project\DealersBundle\Entity\Repository\DealerRepository")
* @Gedmo\Loggable
*/
class Dealer
{
/**
 * @var integer
 *
 * @ORM\Column(name="id", type="integer")
 * @ORM\Id
 * @ORM\GeneratedValue(strategy="AUTO")
 */
private $id;

/**
 * @var string
 *
 * @ORM\Column(name="name", type="string", length=255, unique=true)
 * @Assert\NotBlank()
 * @Assert\Length(min = "10")
 */
private $name;

/**
 * @ORM\OneToMany(targetEntity="DealerBrand", mappedBy="dealer")
 *
*/
private $dealerBrand;

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

public function __toString()
{
    return $this->getName();
}

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

/**
 * Set name
 *
 * @param string $name
 * @return Dealer
 */
public function setName($name)
{
    $this->name = $name;

    return $this;
}

/**
 * Get name
 *
 * @return string
 */
public function getName()
{
    return $this->name;
}

public function addDealerBrand($dealerBrand)
{
    $this->dealerBrand[] = $dealerBrand;
}

public function getDealerBrand()
{
    return $this->dealerBrand;
}
}

ДилерБренд

/**
* DealerBrand
*
* @ORM\Table("dealer_brand")
* @ORM\Entity
*/
class DealerBrand
{
/**
 * @var integer
 *
 * @ORM\Id
 * @ORM\ManyToOne(targetEntity="Dealer", inversedBy="dealerBrand")
 */
private $dealer;

/**
 * @var integer
 *
 * @ORM\Id
 * @ORM\ManyToOne(targetEntity="Brand", inversedBy="dealerBrand")
 */
private $brand;

/**
 * Set dealer
 *
 * @param integer $dealer
 * @return DealerBrand
 */
public function setDealer($dealer)
{
    $this->dealer = $dealer;

    return $this;
}

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

/**
 * Set brand
 *
 * @param integer $brand
 * @return DealerBrand
 */
public function setBrand($brand)
{
    $this->brand = $brand;

    return $this;
}

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

Теперь это мои типы форм

ДилерБрендТип

class DealerBrandType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder->add('brand', 'entity', array(
                'class'     => 'Project\DealersBundle\Entity\Brand',
                'property'  => 'name',
                'multiple'  => true,
                'expanded'  => true,
            ));
}

public function setDefaultOptions(OptionsResolverInterface $resolver)
{
    $resolver->setDefaults(
        array(
            'data_class' => 'Project\DealersBundle\Entity\DealerBrand'
        )
    );
}

public function getName()
{
    return 'DealerBrand';
}

}

DealerType

    class DealerType extends AbstractType
    {
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('name')
            ->add('dealerBrand', 'collection', array(
                    'type'          => new DealerBrandType(),
                    'allow_add'     => true,
                    'allow_delete'  => true,
                ))
            ->add('Save', 'submit');
    }

    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(
            array(
                'data_class' => 'Project\DealersBundle\Entity\Dealer'
            )
        );
    }

    public function getName()
    {
        return 'dealerType';
    }
    } 

And this is my controller

public function addAction()
{
        $dealer = new Dealer();

        $form = $this->createForm(new DealerType(), $dealer);

        $form->handleRequest($this->getRequest());

        if ($form->isValid()) {

            $this->getDoctrine()->getManager()->persist($dealer);
            $this->getDoctrine()->getManager()->flush();

            return $this->redirect($this->generateUrl('dealers_list'));
        }

        return $this->render(
            'ProjectDealersBundle:Dealers:AddDealer.html.twig',
            array(
                'form' => $form->createView()
            )
        );
    }

Если это неправильный подход, скажите мне, скажите мне также, если вы видите плохой код, таким образом я могу улучшить

* ИЗМЕНИТЬ *

Это результат, который мне нужен

http://tinypic.com/r/24pkzdc/8

Вы можете увидеть там бренды и так далее ... так что идея состоит в том, что при сохранении дилера вы также сохраняете ассоциацию с брендами

* КОНЕЦ РЕДАКТИРОВАНИЯ *

Спасибо!

0
Strate 25 Фев 2014 в 13:58

1 ответ

Лучший ответ

Я не уверен, что это лучший ответ, но вы можете добиться его, сделав собственный запрос в своей форме:

        ->add('contact', 'entity', array(
            'class'         => 'AcmeBundle:Entity'
            'query_builder' => function ( \acme\bundle\Entity\entityRepository $c){

                $qb = $c->createQueryBuilder('a');

                return  $qb->orderBy('a.nom', 'ASC')
                            ->join('a.categories', 'c')
                            ->where( $qb->expr()->in ( 'c.id', ':listCategories') )
                                ->setParameter( 'listCategories', array (
                                    7, 
                                ));
            },
            'attr'          => array( 'class' => 'other')                
        ))
    ;
}

Используя тип поля 'entity', я могу ввести собственный запрос с опцией 'query_builder' (для получения дополнительной информации: http://symfony.com/doc/current/reference/forms/types/entity.html)

Затем внутри я объявляю анонимную функцию (http://php.net/manual/en/ functions.anonymous.php), чтобы создать собственный запрос с помощью createQueryBuilder.

С помощью createQueryBuilder вы создаете свой собственный запрос (здесь у меня были почти такие же отношения, как у вас, и я хотел получить только некоторые из них с помощью массива фильтрации (параметр set).

Вот документ для пользовательского запроса: http://symfony.com/doc/current/book /doctrine.html

Результаты запроса, если они не нулевые, будут отображаться в вашей форме

/ ** АЛЬТЕРНАТИВНЫЙ ОТВЕТ ** /

Если вы хотите отображать своих дилеров И бренды с выбранным деревом, вам необходимо:

1) сделайте запрос на возврат контейнера объекта вашим дилерам и брендам

2) создайте массив с глубиной, которую выбор будет отображать в виде дерева:

Вот пример для иллюстрации:

    ->add('contact', 'entity', array(
        'class'         => 'AcmeBundle:Entity'
        'query_builder' => function ( \acme\bundle\Entity\entityRepository $c){

            $dealers = $c->yourFunctionThatReturnesDealers('d');

            $dealersGroupedByBrands = array();
    foreach ( $dealers as $dealer) {
                    foreach ($dealers->getBrands() as $brand) {
            $dealersGroupedByBrands[$brand->getName()][] = $dealer;
        }

            return  $dealersGroupedByBrands;
        },
        'attr'          => array( 'class' => 'other')                
    ))
;

    }

Довольно круто, не так ли?

1
Charles-Antoine Fournel 25 Фев 2014 в 20:22
Проблема не в отображении объекта, я могу сделать это, как вы сказали, но это не сохраняется в базе данных ...
 – 
Strate
25 Фев 2014 в 14:57
У вас отображается ошибка? или хоть что-то?
 – 
Charles-Antoine Fournel
25 Фев 2014 в 15:00
Нет, это не отображается, если я создаю коллекцию, если я использую поле формы как объект, ошибка следующая ... Найден объект типа Project \ DealerBundle \ Entity \ Brand в ассоциации Project \ DealerBundle \ Entity \ Dealer #dealerBrand, но ожидается Project \ DealerBundle \ Entity \ DealerBrand
 – 
Strate
25 Фев 2014 в 15:05
В каком репозитории вы вызываете анонимную функцию?
 – 
Charles-Antoine Fournel
25 Фев 2014 в 15:14
Это то, что я добавляю в DealerType -> add ('diverBrand', 'entity', array ('class' => 'Project \ DeilersBundle \ Entity \ Brand', 'extended' => true, 'multiple' => true ,))
 – 
Strate
25 Фев 2014 в 15:22