Symfony2.2と組み合わせたSonataAdminBunleに問題があります。 ProjectエンティティとProjectImageエンティティがあり、次のようにこれら2つの間の1対多の関係を指定しました。
class Project
{
/**
* @ORM\OneToMany(targetEntity="ProjectImage", mappedBy="project", cascade={"all"}, orphanRemoval=true)
*/
private $images;
}
class ProjectImage
{
/**
* @ORM\ManyToOne(targetEntity="Project", inversedBy="images")
* @ORM\JoinColumn(name="project_id", referencedColumnName="id")
*/
private $project;
}
ProjectAdminとProjectImageAdminを構成しました。
class ProjectAdmin extends Admin
{
protected function configureFormFields(FormMapper $formMapper)
{
$formMapper
->add('title')
->add('website')
->add('description', 'textarea')
->add('year')
->add('tags')
->add('images', 'sonata_type_collection', array(
'by_reference' => false
), array(
'edit' => 'inline',
'inline' => 'table',
'sortable' => 'id',
))
;
}
}
class ProjectImageAdmin extends Admin
{
protected function configureFormFields(FormMapper $formMapper)
{
$formMapper
->add('file', 'file', array(
'required' => false
))
;
}
}
問題は、データベースのproject_imageテーブルにproject_idが保存されていないのに、他のすべてのデータが保存されており、画像も保存されていることです。他の場所で実用的な答えを見つけることができませんでした。
無関係ですが、1対多の注釈を少し微調整します。
class Project
{
/**
* @ORM\OneToMany(targetEntity="ProjectImage", mappedBy="project", cascade={"persist"}, orphanRemoval=true)
* @ORM\OrderBy({"id" = "ASC"})
*/
private $images;
}
軌道に戻ると、アノテーションとSonata Adminフォームは問題なく表示されるため、Projectエンティティクラスにこれらのメソッドの1つが欠落していると確信しています。
public function __construct() {
$this->images = new \Doctrine\Common\Collections\ArrayCollection();
}
public function setImages($images)
{
if (count($images) > 0) {
foreach ($images as $i) {
$this->addImage($i);
}
}
return $this;
}
public function addImage(\Acme\YourBundle\Entity\ProjectImage $image)
{
$image->setProject($this);
$this->images->add($image);
}
public function removeImage(\Acme\YourBundle\Entity\ProjectImage $image)
{
$this->images->removeElement($image);
}
public function getImages()
{
return $this->Images;
}
そしてあなたの管理者クラスで:
public function prePersist($project)
{
$this->preUpdate($project);
}
public function preUpdate($project)
{
$project->setImages($project->getImages());
}
Symfonyフォームコレクションでいくつかの変更があったため、addChild()とremoveChild()をby_referenceオプションをfalseに設定すると、コレクションが自動的に永続化され、期待どおりに逆側にIDが設定されます。
これが完全に機能するバージョンです: https://Gist.github.com/webdevilopers/1a01eb8c7a8290d0b951
protected function configureFormFields(FormMapper $formMapper)
{
$formMapper
->add('childs', 'sonata_type_collection', array(
'by_reference' => false
), array(
'edit' => 'inline',
'inline' => 'table'
))
;
}
addChild()メソッドには、子の親のセッターが含まれている必要があります。
public function addChild($child)
{
$child->setParent($this); // !important
$this->childs[] = $child;
return $this;
}
PreUpdate関数で直接実行できます
public function prePersist($societate)
{
$this->preUpdate($societate);
}
public function preUpdate($societate)
{
$conturi = $societate->getConturi();
if (count($conturi) > 0) {
foreach ($conturi as $cont) {
$cont->setSocietate($societate);
}
}
}
このリンクを通過します http://sonata-project.org/bundles/doctrine-orm-admin/master/doc/reference/form_field_definition.html#advanced-usage-many-to-one このリンクソナタ管理バンドルでのアソシエーションマッピングについて大いに役立ちます。
私が解決した1つの方法は、カスタムSonataモデルマネージャーを使用してすべての逆側の関連付けを手動で設定することでした。
<?php
namespace Sample\AdminBundle\Model;
class ModelManager extends \Sonata\DoctrineORMAdminBundle\Model\ModelManager
{
/**
* {@inheritdoc}
*/
public function create($object)
{
try {
$entityManager = $this->getEntityManager($object);
$entityManager->persist($object);
$entityManager->flush();
$this->persistAssociations($object);
} catch (\PDOException $e) {
throw new ModelManagerException('', 0, $e);
}
}
/**
* {@inheritdoc}
*/
public function update($object)
{
try {
$entityManager = $this->getEntityManager($object);
$entityManager->persist($object);
$entityManager->flush();
$this->persistAssociations($object);
} catch (\PDOException $e) {
throw new ModelManagerException('', 0, $e);
}
}
/**
* Persist owning side associations
*/
public function persistAssociations($object)
{
$associations = $this
->getMetadata(get_class($object))
->getAssociationMappings();
if ($associations) {
$entityManager = $this->getEntityManager($object);
foreach ($associations as $field => $mapping) {
if ($mapping['isOwningSide'] == false) {
if ($owningObjects = $object->{'get' . ucfirst($mapping['fieldName'])}()) {
foreach ($owningObjects as $owningObject) {
$owningObject->{'set' . ucfirst($mapping['mappedBy']) }($object);
$entityManager->persist($owningObject);
}
$entityManager->flush();
}
}
}
}
}
}
これをservices.ymlファイルで新しいサービスとして定義してください。
services:
sample.model.manager:
class: Sample\AdminBundle\Model\ModelManager
arguments: [@doctrine]
sample.admin.business:
class: Sample\AdminBundle\Admin\BusinessAdmin
tags:
- { name: sonata.admin, manager_type: orm, group: "Venues", label: "Venue" }
arguments: [~, Sample\AppBundle\Entity\Business, ~]
calls:
- [ setContainer, [@service_container]]
- [ setModelManager, [@sample.model.manager]]
public function prePersist($user)
{
$this->preUpdate($user);
}
public function preUpdate($user)
{
$user->setProperties($user->getProperties());
}
これは私にとって問題を完全に解決しましたありがとう!
最も簡単な解決策は、変数名を自然に置き換えることです。これは私のために働きます: 'by_reference' => false
次のように:
protected function configureFormFields(FormMapper $formMapper)
{
$formMapper
->add('name')
->add('articles', EntityType::class, array(
'class' => 'EboxoneAdminBundle:Article',
'required' => false,
'by_reference' => false,
'multiple' => true,
'expanded' => false,
))
->add('formInputs', CollectionType::class, array(
'entry_type' => FormInputType::class,
'allow_add' => true,
'allow_delete' => true,
'by_reference' => false,
))
;
}