3

У меня есть три сущности, Блок, BlockPlacement, BlockPosition:Symfony Форма ManyToOne OneToMany

class BlockEntity 
{ 
    private $bid; 
    /** 
    * @ORM\OneToMany(
    *  targetEntity="BlockPlacementEntity", 
    *  mappedBy="block", 
    *  cascade={"remove"}) 
    */ 
    private $placements; 
} 

class BlockPlacementEntity 
{ 
    /** 
    * The id of the block postion 
    * 
    * @ORM\Id 
    * @ORM\ManyToOne(targetEntity="BlockPositionEntity", inversedBy="placements") 
    * @ORM\JoinColumn(name="pid", referencedColumnName="pid", nullable=false) 
    */ 
    private $position; 

    /** 
    * The id of the block 
    * 
    * @var BlockEntity 
    * @ORM\Id 
    * @ORM\ManyToOne(targetEntity="BlockEntity", inversedBy="placements") 
    * @ORM\JoinColumn(name="bid", referencedColumnName="bid", nullable=false) 
    */ 
    private $block; 

    private $sortorder; 
} 

class BlockPositionEntity 
{ 
    private $pid; 
    /** 
    * @ORM\OneToMany(
    *  targetEntity="BlockPlacementEntity", 
    *  mappedBy="position", 
    *  cascade={"remove"}) 
    * @ORM\OrderBy({"sortorder" = "ASC"}) 
    */ 
    private $placements; 
} 

Таким образом, вы можете видеть отношения: Блок < OneToMany> Размещение < ManyToOne> Положение.

Теперь я пытаюсь построить форму создания/редактирования блока:

$builder 
     ->add($builder->create('placements', 'entity', [ 
      'class' => 'Zikula\BlocksModule\Entity\BlockPositionEntity', 
      'choice_label' => 'name', 
      'multiple' => true, 
      'required' => false 
     ])) 
    ; 

Это дает мне хорошее поле выбора с выбора нескольких возможных с надлежащей список позиций на выбор. Но он не показывает предыдущие варианты размещения (я использую существующие данные), например. маркировка позиций как «выбрана». Я еще не пробовал создавать новый блок, только редактируя существующие данные.

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

Я просмотрел тип формы collection, и мне не нравится это решение, потому что оно не является полем с несколькими выборами. Он требует JS и не настолько интуитивно понятен, как простой элемент select.

Это похоже на такую ​​общую проблему для людей. Я искал и не нашел общего ответа, и ничего не помогло.

+0

Почему вы думаете о DataTransformers для этой проблемы? Они используются, когда вам необходимо преобразовать данные модели. И да, поле сбора намного сложнее для этого случая. Я добавлю ссылки на мой ответ ниже, чтобы показать вам рабочий код для одного и того же случая из моего проекта –

ответ

0

ОК - так, в конце концов, я нашел другой способ. Ответ @Stepan Yudin работал, но сложный (слушатели и т. Д.), И не совсем так, как я надеялся.

Итак, у меня есть те же три сущности. BlockPlacement и BlockPosition остаются теми же (и так не повторно отправил, см.выше), но я сделал некоторые изменения в BlockEntity:

class BlockEntity 
{ 
    private $bid; 
    /** 
    * @ORM\OneToMany(
    *  targetEntity="BlockPlacementEntity", 
    *  mappedBy="block", 
    *  cascade={"remove", "persist"}, 
    *  orphanRemoval=true) 
    */ 
    private $placements; 

    /** 
    * Get an ArrayCollection of BlockPositionEntity that are assigned to this Block 
    * @return ArrayCollection 
    */ 
    public function getPositions() 
    { 
     $positions = new ArrayCollection(); 
     foreach($this->getPlacements() as $placement) { 
      $positions->add($placement->getPosition()); 
     } 

     return $positions; 
    } 

    /** 
    * Set BlockPlacementsEntity from provided ArrayCollection of positionEntity 
    * requires 
    * cascade={"remove, "persist"} 
    * orphanRemoval=true 
    * on the association of $this->placements 
    * @param ArrayCollection $positions 
    */ 
    public function setPositions(ArrayCollection $positions) 
    { 
     // remove placements and skip existing placements. 
     foreach ($this->placements as $placement) { 
      if (!$positions->contains($placement->getPosition())) { 
       $this->placements->removeElement($placement); 
      } else { 
       $positions->removeElement($placement->getPosition()); // remove from positions to add. 
      } 
     } 

     // add new placements 
     foreach ($positions as $position) { 
      $placement = new BlockPlacementEntity(); 
      $placement->setPosition($position); 
      // sortorder is irrelevant at this stage. 
      $placement->setBlock($this); // auto-adds placement 
     } 
    } 
} 

Таким образом, вы можете увидеть, что BlockEntity теперь обработки параметр positions который Безразлично» t существует в сущности вообще. Вот соответствующая форма компонента:

$builder 
    ->add('positions', 'Symfony\Bridge\Doctrine\Form\Type\EntityType', [ 
     'class' => 'Zikula\BlocksModule\Entity\BlockPositionEntity', 
     'choice_label' => 'name', 
     'multiple' => true, 
    ]) 

обратите внимание, что я изменил в Symfony 2.8 формы стиля, так как мой первый пост

Это делает множественного выбора элемента на странице, которая принимает любое количество позиций и преобразует их в ArrayCollection на submit. Затем это обрабатывается непосредственно методами get/set позиции формы, и они преобразуются в/из свойства размещения. cascade и orphanRemoval важны, потому что они заботятся о том, чтобы «очистить» оставшиеся объекты.

, потому что ссылки выше здесь является BlockPlacement setBlock($block) метод:

public function setBlock(BlockEntity $block = null) 
{ 
    if ($this->block !== null) { 
     $this->block->removePlacement($this); 
    } 

    if ($block !== null) { 
     $block->addPlacement($this); 
    } 

    $this->block = $block; 

    return $this; 
} 
1

Update: пожалуйста, посмотрите на эту example repo

Update 2: Я обновил репо.

Я сделал это с помощью прослушивателей форм и неотображаемого поля выбора. Познакомьтесь подробнее с BlockType form type Вы можете задать нам вопрос.

+0

да, могу ли я его опубликовать, чтобы я мог поближе посмотреть? – craigh

+0

@craigh, конечно, см. Блок обновления в этом ответе, чтобы получить github link –

+0

спасибо. Я посмотрю в ближайшие пару дней и вернусь. – craigh