Symfony 2.1 と Doctrine 2 を使用しています。
私は2つの主要なエンティティを扱っています.PlaceとFeatureで、それらの間にManyToManyの関係があります。データベースには多くの機能があり、それらをテーマ別にグループ化するために、Feature は ManyToOne 関係を持つ FeatureCategory エンティティにも関連付けられています。
さまざまなエンティティのコードは次のとおりです。
プレイスエンティティ_
namespace Mv\PlaceBundle\Entity;
…
/**
* Mv\PlaceBundle\Entity\Place
*
* @ORM\Table(name="place")
* @ORM\Entity(repositoryClass="Mv\PlaceBundle\Entity\Repository\PlaceRepository")
* @ORM\HasLifecycleCallbacks
*/
class Place
{
/**
* @var integer $id
*
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @var string $name
*
* @ORM\Column(name="name", type="string", length=255, unique=true)
* @Assert\NotBlank
*/
private $name;
/**
* @ORM\ManyToMany(targetEntity="\Mv\MainBundle\Entity\Feature")
* @ORM\JoinTable(name="places_features",
* joinColumns={@ORM\JoinColumn(name="place_id", referencedColumnName="id")},
* inverseJoinColumns={@ORM\JoinColumn(name="feature_id", referencedColumnName="id")}
* )
*/
private $features;
/**
* Get id
*
* @return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* @param string $name
* @return Place
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* Add features
*
* @param \Mv\MainBundle\Entity\Feature $features
* @return Place
*/
public function addFeature(\Mv\MainBundle\Entity\Feature $features)
{
$this->features[] = $features;
echo 'Add "'.$features.'" - Total '.count($this->features).'<br />';
return $this;
}
/**
* Remove features
*
* @param \Mv\MainBundle\Entity\Feature $features
*/
public function removeFeature(\Mv\MainBundle\Entity\Feature $features)
{
$this->features->removeElement($features);
}
/**
* Get features
*
* @return Doctrine\Common\Collections\Collection
*/
public function getFeatures()
{
return $this->features;
}
public function __construct()
{
$this->features = new \Doctrine\Common\Collections\ArrayCollection();
}
機能エンティティ:
namespace Mv\MainBundle\Entity;
…
/**
* @ORM\Entity
* @ORM\Table(name="feature")
* @ORM\HasLifecycleCallbacks
*/
class Feature
{
use KrToolsTraits\PictureTrait;
/**
* @ORM\Id
* @ORM\Column(type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* @ORM\Column(name="label", type="string", length=255)
* @Assert\NotBlank()
*/
protected $label;
/**
* @ORM\ManyToOne(targetEntity="\Mv\MainBundle\Entity\FeatureCategory", inversedBy="features", cascade={"persist"})
* @ORM\JoinColumn(name="category_id", referencedColumnName="id")
*/
private $category;
/**
* Get id
*
* @return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set label
*
* @param string $label
* @return Feature
*/
public function setLabel($label)
{
$this->label = $label;
return $this;
}
/**
* Get label
*
* @return string
*/
public function getLabel()
{
return $this->label;
}
/**
* Set category
*
* @param Mv\MainBundle\Entity\FeatureCategory $category
* @return Feature
*/
public function setCategory(\Mv\MainBundle\Entity\FeatureCategory $category = null)
{
$this->category = $category;
return $this;
}
/**
* Get category
*
* @return Mv\MainBundle\Entity\FeatureCategory
*/
public function getCategory()
{
return $this->category;
}
}
FeatureCategoryエンティティ:
namespace Mv\MainBundle\Entity;
...
/**
* @ORM\Entity
* @ORM\Table(name="feature_category")
*/
class FeatureCategory
{
/**
* @ORM\Id
* @ORM\Column(type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* @ORM\Column(name="code", type="string", length=255)
* @Assert\NotBlank()
*/
protected $code;
/**
* @ORM\Column(name="label", type="string", length=255)
* @Assert\NotBlank()
*/
protected $label;
/**
* @ORM\OneToMany(targetEntity="\Mv\MainBundle\Entity\Feature", mappedBy="category", cascade={"persist", "remove"}, orphanRemoval=true)
* @Assert\Valid()
*/
private $features;
public function __construct()
{
$this->features = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Get id
*
* @return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set code
*
* @param string $code
* @return Feature
*/
public function setCode($code)
{
$this->code = $code;
return $this;
}
/**
* Get code
*
* @return string
*/
public function getCode()
{
return $this->code;
}
/**
* Set label
*
* @param string $label
* @return Feature
*/
public function setLabel($label)
{
$this->label = $label;
return $this;
}
/**
* Get label
*
* @return string
*/
public function getLabel()
{
return $this->label;
}
/**
* Add features
*
* @param \Mv\MainBundle\Entity\Feature $features
*/
public function addFeatures(\Mv\MainBundle\Entity\Feature $features){
$features->setCategory($this);
$this->features[] = $features;
}
/**
* Get features
*
* @return Doctrine\Common\Collections\Collection
*/
public function getFeatures()
{
return $this->features;
}
/*
* Set features
*/
public function setFeatures(\Doctrine\Common\Collections\Collection $features)
{
foreach ($features as $feature)
{
$feature->setCategory($this);
}
$this->features = $features;
}
/**
* Remove features
*
* @param Mv\MainBundle\Entity\Feature $features
*/
public function removeFeature(\Mv\MainBundle\Entity\Feature $features)
{
$this->features->removeElement($features);
}
/**
* Add features
*
* @param Mv\MainBundle\Entity\Feature $features
* @return FeatureCategory
*/
public function addFeature(\Mv\MainBundle\Entity\Feature $features)
{
$features->setCategory($this);
$this->features[] = $features;
}
}
機能テーブルは既に入力されており、ユーザーは機能を追加することはできず、フォーム コレクションでそれらを選択してプレイスにリンクすることしかできません。(Feature エンティティは、現時点では Places にのみリンクされていますが、後でアプリケーションから他のエンティティに関連付けられ、すべてのエンティティで使用できるすべての機能が含まれます)
Place フォームでは、Place で利用可能な機能のチェックボックスを表示する必要がありますが、それらをカテゴリ別にグループ化して表示する必要があります。例 :
訪問 (FeatureCategory - コード VIS) :
- 無料(機能)
- 支払い (機能)
話される言語 (FeatureCategory - コード LAN) :
- 英語(機能)
- フランス語 (機能)
- スペイン語 (機能)
私の考え
次のように、PlaceType フォームで仮想フォームを使用します。
$builder
->add('name')
->add('visit', new FeatureType('VIS'), array(
'data_class' => 'Mv\PlaceBundle\Entity\Place'
))
->add('language', new FeatureType('LAN'), array(
'data_class' => 'Mv\PlaceBundle\Entity\Place'
));
そして、次のような FeatureType 仮想フォームを作成します。
class FeatureType extends AbstractType
{
protected $codeCat;
public function __construct($codeCat)
{
$this->codeCat = $codeCat;
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('features', 'entity', array(
'class' => 'MvMainBundle:Feature',
'query_builder' => function(EntityRepository $er)
{
return $er->createQueryBuilder('f')
->leftJoin('f.category', 'c')
->andWhere('c.code = :codeCat')
->setParameter('codeCat', $this->codeCat)
->orderBy('f.position', 'ASC');
},
'expanded' => true,
'multiple' => true
));
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'virtual' => true
));
}
public function getName()
{
return 'features';
}
}
このソリューションを使用すると、必要なものが得られますが、バインド プロセスですべての機能が保持されるわけではありません。それらをグループ化する代わりに、それは私を保持し、最後のグループ「言語」を保持し、すべての以前の機能データを消去します。実際の動作を確認するには、5 つのチェックボックスをオンにすると、Place->addFeature() 関数に 5 回入りますが、フィーチャー arrayCollection の長さは連続して 1、2、1、2、3 になります。
別の方法でそれを行う方法について何か考えはありますか? モデルを変更する必要がある場合でも、それを行うことができます。これを処理するための、機能に関連する将来の他のエンティティでも再利用可能な最良の方法は何ですか?
君たちありがとう。