简体   繁体   中英

Use same entity field multiple times with different admin code in sonata form

I'm using Sonata admin in my Symfony project. I have 2 entities like Parent and Child . Parent entity is connected to child by one-to-many relationship.

I have created 2 admin classes for child entity with different baseRoutName. I need to use Child entity fields in Parent entity sonata form for 2 times.

//ParentAdmin.php
    $formMapper
            ->with('Child 1', ['class' => 'col-md-4'])
            ->add('child', CollectionType::class, [], [
                'edit' => 'inline',
                'inline' => 'table',
                'sortable' => 'position',
                'admin_code' => 'admin.child1'
            ])
            ->end()
            ->with('Child 2', ['class' => 'col-md-4'])
            ->add('child', CollectionType::class, [], [
                'edit' => 'inline',
                'inline' => 'table',
                'sortable' => 'position',
                'admin_code' => 'admin.child2'
            ])
            ->end();

The problem here is that I need to use child field for multiple times. But the child field within Child 2 is overriding the child field in Child 1 . As you can see I have used different admin_code for these 2 fields.

My expected output is,

在此处输入图片说明

But the actual output I'm getting is,

在此处输入图片说明

I know the problem here is duplicate entity fields. Is it possible to display same field for multiple times?

Does anyone have solution/suggestion? Thanks in advance!!

maybe it's late but i had the same problem, found this post with no answer, and finally found a solution, so here it is for future purpose.

i have a Request class with generated document, get an eye on get and add functions:

class Request
{
    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $id;

    /**
     * @ORM\OneToMany(targetEntity="GeneratedDocument", mappedBy="request", cascade={"all"}, orphanRemoval=true)
     */
    protected $generatedDocuments;

    /**
     * @var ArrayCollection
     * each of this attributes will get one type of $generatedDocuments
     */
    protected $generatedAttestationDocuments;
    protected $generatedCertificationDocuments;

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

    /**
     * Set the value of id.
     *
     * @param integer $id
     * @return \App\Entity\Request
     */
    public function setId($id)
    {
        $this->id = $id;

        return $this;
    }

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

    /**
     * @return Collection|GeneratedDocument[]
     */
    public function getGeneratedDocuments(): Collection
    {
        return $this->generatedDocuments;
    }

    public function addGeneratedDocument(GeneratedDocument $generatedDocument): self
    {
        if (!$this->generatedDocuments->contains($generatedDocument)) {
            $this->generatedDocuments[] = $generatedDocument;
            $generatedDocument->setRequest($this);
        }

        return $this;
    }

    public function removeGeneratedDocument(GeneratedDocument $generatedDocument): self
    {
        if ($this->generatedDocuments->contains($generatedDocument)) {
            $this->generatedDocuments->removeElement($generatedDocument);
            // set the owning side to null (unless already changed)
            if ($generatedDocument->getRequest() === $this) {
                $generatedDocument->setRequest(null);
            }
        }

        return $this;
    }

    /**
     * @return Collection|GeneratedDocument[]
     *
     * @param int $type
     */
    protected function getTypedGeneratedDocuments(int $type): Collection
    {
        return $this->getGeneratedDocuments()->filter(function (GeneratedDocument $gd) use ($type) {
            if ($gd->getGeneratedDocumentModel()) {
                return $type === $gd->getGeneratedDocumentModel()->getType();
            }
            return false;
        });
    }

    /**
     * @return Collection|GeneratedDocument[]
     */
    public function getGeneratedAttestationDocuments(): Collection
    {
        if (empty($this->generatedAttestationDocuments)) {
            $this->generatedAttestationDocuments =
                $this->getTypedGeneratedDocuments(GeneratedDocumentModel::TYPE_ATTESTATION);
        }

        return $this->generatedAttestationDocuments;
    }

    public function addGeneratedAttestationDocument(GeneratedDocument $generatedDocument): self
    {
        $this->generatedAttestationDocuments[] = $generatedDocument;
        return $this->addGeneratedDocument($generatedDocument);
    }

    public function removeGeneratedAttestationDocument(GeneratedDocument $generatedDocument): self
    {
        return $this->removeGeneratedDocument($generatedDocument);
    }

    /**
     * @return Collection|GeneratedDocument[]
     */
    public function getGeneratedCertificationDocuments(): Collection
    {
        if (empty($this->generatedCertificationDocuments)) {
            $this->generatedCertificationDocuments =
                $this->getTypedGeneratedDocuments(GeneratedDocumentModel::TYPE_CERTIFICATE);
        }

        return $this->generatedCertificationDocuments;
    }

    public function addGeneratedCertificationDocument(GeneratedDocument $generatedDocument): self
    {
        $this->generatedCertificationDocuments[] = $generatedDocument;
        return $this->addGeneratedDocument($generatedDocument);
    }

    public function removeGeneratedCertificationDocument(GeneratedDocument $generatedDocument): self
    {
        return $this->removeGeneratedDocument($generatedDocument);
    }
}

Then in admin you have to give a different name in each add, here I use my typed generated documents so there's no duplication problem, but they are not mapped and symfony complain about it.

Trying to use 'mapped' => false resolved nothing, the simplest way I found was a 'virtual mapping', based on the original mapped attribute 'generatedDocuments, just the time to fool symfony when building the form.

class RequestAdmin extends AbstractAdmin
{
    protected function configureFormFields(FormMapper $formMapper): void
    {
        /** @var Request $createdRequest */
        $createdRequest = $this->getSubject();

        $metaData = $this->getModelManager()->getMetadata($this->getClass());
        //We need many CollectionType based on 'generatedDocuments', and we need an ArrayCollection for each of them
        //so here is a virtual mapping to make symfony accept the persistence of our CollectionType
        //then setter should fill 'generatedDocuments'
        $mapping = $metaData->getAssociationMappings()['generatedDocuments'];
        $mapping['fieldName'] = 'generatedAttestationDocuments';
        $metaData->mapOneToMany($mapping);
        $mapping['fieldName'] = 'generatedCertificationDocuments';
        $metaData->mapOneToMany($mapping);

        $formMapper
            ->with(('Attestation Deposit'))
                ->add('generatedAttestationDocuments', CollectionType::class, [
                    'label' => false,
                    'by_reference' => false,
                    'btn_add' => 'Add Attestation',
                    'data' => $createdRequest->getGeneratedAttestationDocuments(),
                ], [
                    'edit' => 'inline',
                    'inline' => 'table',
                    'admin_code' => 'admin.generated_document_attestation',
                ])
            ->end()
            ->with(('Certificate'))
                ->add('generatedCertificationDocuments', CollectionType::class, [
                    'label' => false,
                    'by_reference' => false,
                    'btn_add' => 'Add Certification',
                    'data' => $createdRequest->getGeneratedCertificationDocuments(),
                ], [
                    'edit' => 'inline',
                    'inline' => 'table',
                    'admin_code' => 'admin.generated_document_certification',
                ])
            ->end()

        //delete virtual mapping to avoid it to get handle like a real mapping
        unset($metaData->associationMappings['generatedAttestationDocuments']);
        unset($metaData->associationMappings['generatedCertificationDocuments']);
    }
}

I would like to know a simplest way, but It really work like individual CollectionType for me.

Hope it will help!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM