Viktor Sydorenko
Viktor Sydorenko

Reputation: 683

Check if Entity relation does exist. (Doctrine)

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

Answers (2)

Joe
Joe

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

Cagatay Ulubay
Cagatay Ulubay

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

Related Questions