Reputation: 683
I have relation for instance:
/**
* @ORM\OneToOne(targetEntity="Model\Entity\Image")
* @ORM\JoinColumn(name="image_id", referencedColumnName="id")
*/
protected $image;
And ordinary getter:
public function getImage()
{
return $this->image;
}
In my twig code I call it:
model.image.getImageURL()
But if there are no relation in database, like missing image_id, so getImage method will return null, and Exception on method getImageURL. How can I avoid it clear.
My solution is:
protected function exist($model, $modelName) {
if(isset($model)) {
return $model;
} else {
$modelName = 'Model\Entity\\' . $modelName;
return new $modelName();
}
}
And getter like:
public function getImage()
{
return $this->exist($this->image, 'Image');
}
But I don't like it, seem as not good solution for me. Can I do it more Symfony way, I assume that I am missing something?
Upvotes: 0
Views: 3070
Reputation: 2436
You're not really missing anything.
You have an optional relation in your entity which means the value can be null. so the "right" way to work with this situation is to check if the property is set before you access any methods on it.
Which means in a twig case:
{% if model.image is not null %}
{{ model.image.getimageUrl() %}
{% endif %}
and in the php case:
if($model->getImage() !== null) {
$url = $model->getImage()->getImageUrl();
}
Other options would be changing the implementation of getImage:
public function getImage() {
return $this->image === null ? new Image() : $this->image;
}
or create a dedicated getImageUrl method directly in your model entity:
public function getImageUrl() {
return $this->image !== null ? $this->image->getImageUrl() : '';
}
Upvotes: 2
Reputation: 2559
The only reason why it won't be filled is if it failed or couldn't find a relation. In this scenario, your workaround would return null
too, because it does not exist.
What you can do is to check via:
{% if model.image %}
{{ model.image.imageUrl }}
{% endif %}
It searches for a get
method so you can just use imageUrl
and it will search for getImageUrl
.
There is also a thing when using relations, that Symfony won't do a reverse relation. I couldn't find the problem by myself, but a mate who struggled with it (he got my full trust in development decisions) told me that you have to manually add it and that it's a known and intentional thing in Symfony/Doctrine.
Let me give you a example with a OneToMany
example:
[Entity\Human.php]
class Human
{
/**
* @ORM\ManyToOne(targetEntity="Race", inversedBy="race")
* @JoinColumn
*
* A human can have one race, but a race can belong to many human
*/
private $race;
// using optional parameter so I can demonstrate it on one way..
// If you want it to be required, remove " = null"
// and also remove "if ($race && ..)"
public function setRace(Race $race = null)
{
$this->race = $race; // default from bin/console doctrine:generate:entities
// Reverse check and add if not automatically done
if ($race && ! $race->getHumans()->contains($this)) {
$race->addHuman($this);
}
return $this; // default from bin/console doctrine:generate:entities
}
}
and also the opposite site:
[Entity\Race.php]
class Race
{
/**
* @ORM\OneToMany(targetEntity="Human", mappedBy="race")
*/
private $humans;
public function __construct()
{
$this->humans = new ArrayCollection;
}
public function addHuman(Human $human)
{
$this->humans[] = $human; // default from bin/console doctrine:generate:entities
// Custom reverse check and add
if ($human->getRace() !== $this) {
$human->setRace($this);
}
return $this; // default from bin/console doctrine:generate:entities
}
// also important for remove!
public function removeHuman(Human $human)
{
$this->humans->removeElement($human);
if ($human->getRace() !== null) {
$human->setRace(null);
}
return $this;
}
}
Upvotes: 0