Reputation: 361
I´ve got an entity News
and a related entity NewsArticle
which holds the translations of some News
attributes (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. The label of each selectable News
record should display the headline of the NewsArticle
record with a specific field value (the default language). But how can I realise this?
Even my first attempt by using the __toString()
method failed with this error message:
Catchable Fatal Error: Object of class Doctrine\ORM\PersistentCollection could not be converted to string
The News
entity:
<?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:
<?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):
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.
Solely returning the headline
attribute (return $newsArticle->getHeadline();
) fails with the following error message:
Attempted to call an undefined method named "getHeadline" of class "Doctrine\Common\Collections\ArrayCollection".
The new NewsType Class (except):
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?
Thank´s in advance!
Upvotes: 2
Views: 5123
Reputation: 2598
The way you defined your mapping, $newsArticles
in News
is a OneToMany relation, meaning there are several NewsArticles
for each News
. So obviously, getNewsArticles
returns a Collection
of 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.
EDIT: Following your indications in the comments, here's what you should do (assuming you have $searchedLanguage in a variable).
'choice_label' => function($news) {
$article = $news->getNewsArticle()->filter(function (NewsArticle $article) use ($searchedLanguage) {
return $this->getLanguageId() === $searchedLanguage;
});
return $article->getHeadline();
},
Upvotes: 1