简体   繁体   English

Symfony表单:EntityType,Choice Label和相关实体

[英]Symfony Form: EntityType, Choice Label and related entity

I´ve got an entity News and a related entity NewsArticle which holds the translations of some News attributes ( Headline , Subheader , Bodytext ). 我有一个实体News和相关实体NewsArticle ,其中包含一些News属性( HeadlineSubheaderBodytext )的翻译。 The form to add/edit the News records needs a field to select related News , so I defined a EntityType field for this purpose. 添加/编辑News记录的表单需要一个字段来选择相关的News ,因此我为此目的定义了一个EntityType字段。 The label of each selectable News record should display the headline of the NewsArticle record with a specific field value (the default language). 每个可选News记录的标签应显示具有特定字段值(默认语言)的NewsArticle记录的标题。 But how can I realise this? 但我怎么能意识到这一点呢?

Even my first attempt by using the __toString() method failed with this error message: 即使我第一次使用__toString()方法尝试失败也会显示以下错误消息:

Catchable Fatal Error: Object of class Doctrine\\ORM\\PersistentCollection could not be converted to string 可捕获的致命错误:类Doctrine \\ ORM \\ PersistentCollection的对象无法转换为字符串

The News entity: News实体:

<?php

// src/Acme/Bundle/Entity/News.php
namespace Acme\Bundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;

/**
 * @ORM\Entity
 * @ORM\Table(name="news")
 */
class News {
    /**
     * @ORM\Column(type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @ORM\OneToMany(targetEntity="NewsArticle", mappedBy="news", cascade={"persist", "remove"})
     */
    protected $newsArticle;

    /**
     * @ORM\Column(type="string", length=150, unique=false, nullable=false)
     */
    private $ident;

    /**
     * @ORM\Column(type="datetime", nullable=true)
     */
    private $validFrom;    

    /**
     * @ORM\Column(type="datetime", nullable=true)
     */
    private $validTo;        

    /**
     * @ORM\OneToMany(targetEntity="NewsImage", mappedBy="news")
     */
    protected $image; 

    /**
     * @ORM\OneToMany(targetEntity="Media", mappedBy="news")
     */
    private $media;

    /**
     * @ORM\ManyToMany(targetEntity="News", inversedBy="relatedTo")
     * @ORM\JoinTable(name="news_to_news",
     *      joinColumns={@ORM\JoinColumn(name="from_news_id", referencedColumnName="id")},
     *      inverseJoinColumns={@ORM\JoinColumn(name="to_news_id", referencedColumnName="id")}
     * )
     */
    private $relatedFrom;     

    /**
     * @ORM\ManyToMany(targetEntity="News", mappedBy="relatedFrom")
     */
    private $relatedTo;           

    /**
     * @ORM\ManyToOne(targetEntity="Artist")
     * @ORM\JoinColumn(name="artist_id", referencedColumnName="id")
     */
    private $artist;

    /**
     * @ORM\Column(type="boolean")
     */
    private $public;

    /**
     * @ORM\Column(type="boolean", nullable=true)
     */
    private $deleted;    

    /**
     * Constructor
     */
    public function __construct()
    {
        $this->newsArticle = new \Doctrine\Common\Collections\ArrayCollection();
        $this->image = new \Doctrine\Common\Collections\ArrayCollection();
        $this->media = new \Doctrine\Common\Collections\ArrayCollection();
        $this->relatedFrom = new \Doctrine\Common\Collections\ArrayCollection();
        $this->relatedTo = new \Doctrine\Common\Collections\ArrayCollection();
    }

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

    /**
     * Set ident
     *
     * @param string $ident
     *
     * @return News
     */
    public function setIdent($ident)
    {
        $this->ident = $ident;

        return $this;
    }

    /**
     * Get ident
     *
     * @return string
     */
    public function getIdent()
    {
        return $this->ident;
    }

    /**
     * Set validFrom
     *
     * @param \DateTime $validFrom
     *
     * @return News
     */
    public function setValidFrom($validFrom)
    {
        $this->validFrom = $validFrom;

        return $this;
    }

    /**
     * Get validFrom
     *
     * @return \DateTime
     */
    public function getValidFrom()
    {
        return $this->validFrom;
    }

    /**
     * Set validTo
     *
     * @param \DateTime $validTo
     *
     * @return News
     */
    public function setValidTo($validTo)
    {
        $this->validTo = $validTo;

        return $this;
    }

    /**
     * Get validTo
     *
     * @return \DateTime
     */
    public function getValidTo()
    {
        return $this->validTo;
    }

    /**
     * Set public
     *
     * @param boolean $public
     *
     * @return News
     */
    public function setPublic($public)
    {
        $this->public = $public;

        return $this;
    }

    /**
     * Get public
     *
     * @return boolean
     */
    public function getPublic()
    {
        return $this->public;
    }

    /**
     * Set deleted
     *
     * @param boolean $deleted
     *
     * @return News
     */
    public function setDeleted($deleted)
    {
        $this->deleted = $deleted;

        return $this;
    }

    /**
     * Get deleted
     *
     * @return boolean
     */
    public function getDeleted()
    {
        return $this->deleted;
    }

    /**
     * Add newsArticle
     *
     * @param \Acme\Bundle\Entity\NewsArticle $newsArticle
     *
     * @return News
     */
    public function addNewsArticle(\Acme\Bundle\Entity\NewsArticle $newsArticle)
    {
        $this->newsArticle[] = $newsArticle;

        return $this;
    }

    /**
     * Remove newsArticle
     *
     * @param \Acme\Bundle\Entity\NewsArticle $newsArticle
     */
    public function removeNewsArticle(\Acme\Bundle\Entity\NewsArticle $newsArticle)
    {
        $this->newsArticle->removeElement($newsArticle);
    }

    /**
     * Get newsArticle
     *
     * @return \Doctrine\Common\Collections\Collection
     */
    public function getNewsArticle()
    {
        return $this->newsArticle;
    }

    /**
     * Add image
     *
     * @param \Acme\Bundle\Entity\NewsImage $image
     *
     * @return News
     */
    public function addImage(\Acme\Bundle\Entity\NewsImage $image)
    {
        $this->image[] = $image;

        return $this;
    }

    /**
     * Remove image
     *
     * @param \Acme\Bundle\Entity\NewsImage $image
     */
    public function removeImage(\Acme\Bundle\Entity\NewsImage $image)
    {
        $this->image->removeElement($image);
    }

    /**
     * Get image
     *
     * @return \Doctrine\Common\Collections\Collection
     */
    public function getImage()
    {
        return $this->image;
    }

    /**
     * Add medium
     *
     * @param \Acme\Bundle\Entity\Media $medium
     *
     * @return News
     */
    public function addMedia(\Acme\Bundle\Entity\Media $medium)
    {
        $this->media[] = $medium;

        return $this;
    }

    /**
     * Remove medium
     *
     * @param \Acme\Bundle\Entity\Media $medium
     */
    public function removeMedia(\Acme\Bundle\Entity\Media $medium)
    {
        $this->media->removeElement($medium);
    }

    /**
     * Get media
     *
     * @return \Doctrine\Common\Collections\Collection
     */
    public function getMedia()
    {
        return $this->media;
    }

    /**
     * Add relatedFrom
     *
     * @param \Acme\Bundle\Entity\News $relatedFrom
     *
     * @return News
     */
    public function addRelatedFrom(\Acme\Bundle\Entity\News $relatedFrom)
    {
        $this->relatedFrom[] = $relatedFrom;

        return $this;
    }

    /**
     * Remove relatedFrom
     *
     * @param \Acme\Bundle\Entity\News $relatedFrom
     */
    public function removeRelatedFrom(\Acme\Bundle\Entity\News $relatedFrom)
    {
        $this->relatedFrom->removeElement($relatedFrom);
    }

    /**
     * Get relatedFrom
     *
     * @return \Doctrine\Common\Collections\Collection
     */
    public function getRelatedFrom()
    {
        return $this->relatedFrom;
    }

    /**
     * Add relatedTo
     *
     * @param \Acme\Bundle\Entity\News $relatedTo
     *
     * @return News
     */
    public function addRelatedTo(\Acme\Bundle\Entity\News $relatedTo)
    {
        $this->relatedTo[] = $relatedTo;

        return $this;
    }

    /**
     * Remove relatedTo
     *
     * @param \Acme\Bundle\Entity\News $relatedTo
     */
    public function removeRelatedTo(\Acme\Bundle\Entity\News $relatedTo)
    {
        $this->relatedTo->removeElement($relatedTo);
    }

    /**
     * Get relatedTo
     *
     * @return \Doctrine\Common\Collections\Collection
     */
    public function getRelatedTo()
    {
        return $this->relatedTo;
    }

    /**
     * Set artist
     *
     * @param \Acme\Bundle\Entity\Artist $artist
     *
     * @return News
     */
    public function setArtist(\Acme\Bundle\Entity\Artist $artist = null)
    {
        $this->artist = $artist;

        return $this;
    }

    /**
     * Get artist
     *
     * @return \Acme\Bundle\Entity\Artist
     */
    public function getArtist()
    {
        return $this->artist;
    }
}

The NewsArticle entity: NewsArticle实体:

<?php

// src/Acme/Bundle/Entity/NewsArticle.php

namespace Acme\Bundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;

/**
 * @ORM\Entity
 * @ORM\Table(name="news_article")
 */
class NewsArticle {

    /**
     * @ORM\Column(type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @ORM\ManyToOne(targetEntity="News", inversedBy="newsArticle")
     * @ORM\JoinColumn(name="news_id", referencedColumnName="id")
     */
    private $news;

    /**
     * @ORM\Column(type="string", length=150, unique=false, nullable=false)
     * @Assert\NotBlank()
     */
    private $headline;

    /**
     * @ORM\Column(type="string", length=150, nullable=true)
     */
    private $subheadline;

    /**
     * @ORM\Column(type="string", length=65536, nullable=false)
     * @Assert\NotBlank()
     */
    private $bodytext;

    /**
     * @ORM\ManyToOne(targetEntity="Language")
     * @ORM\JoinColumn(name="language_id", referencedColumnName="id")
     */
    private $languageId;


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

    /**
     * Set headline
     *
     * @param string $headline
     *
     * @return NewsArticle
     */
    public function setHeadline($headline)
    {
        $this->headline = $headline;

        return $this;
    }

    /**
     * Get headline
     *
     * @return string
     */
    public function getHeadline()
    {
        return $this->headline;
    }

    /**
     * Set subheadline
     *
     * @param string $subheadline
     *
     * @return NewsArticle
     */
    public function setSubheadline($subheadline)
    {
        $this->subheadline = $subheadline;

        return $this;
    }

    /**
     * Get subheadline
     *
     * @return string
     */
    public function getSubheadline()
    {
        return $this->subheadline;
    }

    /**
     * Set bodytext
     *
     * @param string $bodytext
     *
     * @return NewsArticle
     */
    public function setBodytext($bodytext)
    {
        $this->bodytext = $bodytext;

        return $this;
    }

    /**
     * Get bodytext
     *
     * @return string
     */
    public function getBodytext()
    {
        return $this->bodytext;
    }

    /**
     * Set news
     *
     * @param \Acme\Bundle\Entity\News $news
     *
     * @return NewsArticle
     */
    public function setNews(\Acme\Bundle\Entity\News $news = null)
    {
        $this->news = $news;

        return $this;
    }

    /**
     * Get news
     *
     * @return \Acme\Bundle\Entity\News
     */
    public function getNews()
    {
        return $this->news;
    }

    /**
     * Set languageId
     *
     * @param \Acme\Bundle\Entity\Language $languageId
     *
     * @return NewsArticle
     */
    public function setLanguageId(\Acme\Bundle\Entity\Language $languageId = null)
    {
        $this->languageId = $languageId;

        return $this;
    }

    /**
     * Get languageId
     *
     * @return \Acme\Bundle\Entity\Language
     */
    public function getLanguageId()
    {
        return $this->languageId;
    }

    public function __toString() {
        return $this->getHeadline();
    }
}

The NewsType Class (except): NewsType类(除外):

class NewsType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options) {
        $builder
// [...]
            ->add('relatedTo', EntityType::class, array(
                'class' => 'Bundle:News',
                'choice_label' => function($news) {
                    return $news->getNewsArticle();
                },
                'multiple' => true, 
                'expanded' => false,
                'required' => false
            ))
// [...]
        ;
    }

    public function configureOptions(OptionsResolver $resolver) {
        $resolver->setDefaults(array(
            'data_class' => 'Acme\Bundle\Entity\News',
        ));
    }
}

Any hints how to accomplish the goal? 任何提示如何实现目标? I would be grateful for any help! 我将不胜感激任何帮助!


EDIT #1: 编辑#1:

Thanks to Terenoth I was able to pass the variable containing the default Language object to the NewsType class and followed his code example to filter the News entities having the default language. 感谢Terenoth,我能够将包含默认Language对象的变量传递给NewsType类,并按照他的代码示例过滤具有默认语言的News实体。 Solely returning the headline attribute ( return $newsArticle->getHeadline(); ) fails with the following error message: 仅返回headline属性( return $newsArticle->getHeadline(); )失败,并显示以下错误消息:

Attempted to call an undefined method named "getHeadline" of class "Doctrine\\Common\\Collections\\ArrayCollection". 尝试调用类“Doctrine \\ Common \\ Collections \\ ArrayCollection”的名为“getHeadline”的未定义方法。

The new NewsType Class (except): 新的NewsType类(除外):

class NewsType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options) {
        $searchedLanguage = $options['languageId'];
        $builder
            ->add('relatedTo', EntityType::class, array(
                'class' => 'Bundle:News',
                'query_builder' => function (EntityRepository $er) {
                    return $er->createQueryBuilder('a')
                        ->where('a.deleted = 0')
                        ->orderBy('a.validFrom', 'ASC');
                },
                'choice_label' => function($relatedTo, $searchedLanguage) {
                    $newsArticle = $relatedTo
                            ->getNewsArticle()
                            ->filter(
                                function(NewsArticle $newsArticle) use ($searchedLanguage) {
                                    return $newsArticle->getLanguageId() === $searchedLanguage;
                                }
                            )
                    ;
                    return $newsArticle->getHeadline();
                },
                'multiple' => true, 
                'expanded' => false,
                'required' => false
            ))
        ;
    }

    public function configureOptions(OptionsResolver $resolver) {
        $resolver->setDefaults(array(
            'data_class' => 'Acme\Bundle\Entity\News',
            'languageId' => 'Acme\Bundle\Entity\Language',
        ));
    }
}

What can I do to get the NewsArticle entity instead of the ArrayCollection? 如何获取NewsArticle实体而不是ArrayCollection?

Thank´s in advance! 提前致谢!

The way you defined your mapping, $newsArticles in News is a OneToMany relation, meaning there are several NewsArticles for each News . 你定义你的映射的方式, News中的$newsArticles是一个OneToMany关系,这意味着每个News有几个NewsArticles So obviously, getNewsArticles returns a Collection of NewsArticles . 所以很明显, getNewsArticles返回CollectionNewsArticles

Either you defined your mapping wrong, and there should be only 1 NewsArticle by News, so replace your OneToMany by a OneToOne ... Either you should select on of the several NewsArticle to display its title. 你要么定义你的映射错了,新闻应该只有1个NewsArticle,所以用OneToOne替换你的OneToMany ......你应该选择几个NewsArticle来显示它的标题。

EDIT: Following your indications in the comments, here's what you should do (assuming you have $searchedLanguage in a variable). 编辑:按照你在评论中的指示,这是你应该做的(假设你在变量中有$ searchingLanguage)。

'choice_label' => function($news) {
    $article = $news->getNewsArticle()->filter(function (NewsArticle $article) use ($searchedLanguage) {
        return $this->getLanguageId() === $searchedLanguage;
    });

    return $article->getHeadline();
},

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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