[英]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
属性( Headline
, Subheader
, Bodytext
)的翻译。 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!
我将不胜感激任何帮助!
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
返回Collection
的NewsArticles
。
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.