web-dev-qa-db-ja.com

Sonata AdminBundle外部IDを保存しない1対多の関係

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が保存されていないのに、他のすべてのデータが保存されており、画像も保存されていることです。他の場所で実用的な答えを見つけることができませんでした。

9
René

無関係ですが、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());
}
25

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;
} 
9
webDEVILopers

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);
        }
    }
}
2
Razvan.432

このリンクを通過します http://sonata-project.org/bundles/doctrine-orm-admin/master/doc/reference/form_field_definition.html#advanced-usage-many-to-one このリンクソナタ管理バンドルでのアソシエーションマッピングについて大いに役立ちます。

1
Sandeep Gupta

私が解決した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]]
0
coryjb
public function prePersist($user)
{
    $this->preUpdate($user);
}

public function preUpdate($user)
{
    $user->setProperties($user->getProperties());
}

これは私にとって問題を完全に解決しましたありがとう!

0
Cyrille Hejl

最も簡単な解決策は、変数名を自然に置き換えることです。これは私のために働きます: '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,
        ))
    ;
}
0
Shadi Akil