5

I have broken FKs in my database and if I load an entity and ask for a related entity Doctrine will throw \Doctrine\ORM\EntityNotFoundException.

For the entity in question, I would prefer that where the FK is broken it would return NULL rather than throw an exception. This is because its within a Twig template that the exception occurs and I would prefer Twig to not have to have to handle the exception in this case.

The following is an example configuration.

<?xml version="1.0" encoding="utf-8"?>
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
                  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                  xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping http://doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
    <entity name="Foo\Click" table="clicks">
        <id name="id" type="bigint" column="click_id">
            <generator strategy="IDENTITY"/>
        </id>
        <!-- .. -->
        <many-to-one field="visitor" target-entity="Foo\Visitor" fetch="LAZY">
            <join-columns>
                <join-column name="visitor_id" referenced-column-name="visitor_id"/>
            </join-columns>
        </many-to-one>
    </entity>

    <entity name="Foo\Visitor" table="visitors" read-only="true">
        <id name="visitorId" type="integer" column="visitor_id">
            <generator strategy="IDENTITY"/>
        </id>
        <!-- ... -->
        <one-to-one field="firstClick" target-entity="Foo\Click" fetch="LAZY">
            <join-columns>
                <join-column name="click_id" referenced-column-name="click_id"/>
            </join-columns>
        </one-to-one>
    </entity>
</doctrine-mapping>

The following is an example of expected results where the the click as a visitor ID, but the a visitor record does not exists with that ID. In this case, I would rather not have to wrap the logic in Try/Catch and instead have Click::getVisitor() return null;

<?php
$clickOne = $entityManager()->find(Foo\Click::class, 1);
$v = $clickOne->getVisitor();

if ($v !== null) {
    echo $v->getId(); // may throw Doctrine\ORM\EntityNotFoundException
}

Is there a strategy for this with Doctrine?


Update: Added example configuration and code, and now I see the why this is not achievable with a simple Doctrine configuration.

Courtney Miles
  • 3,756
  • 3
  • 29
  • 47
  • That PR is for the `jms/serializer` bundle - are you using that in your project? – iainn Aug 17 '18 at 10:28
  • Sorry, I'm not. I realised my mistake after posting. – Courtney Miles Aug 17 '18 at 10:32
  • 1
    Ah ok, just wanted to clarify. I don't think there's a way of achieving this at the entitymanager or entity level. The `EntityNotFoundException` gets thrown from Doctrine's proxy methods, which don't appear to support any event listeners or customisation. You'd need to add `try/catch` blocks to each `getXX` relationship method. – iainn Aug 17 '18 at 10:38
  • please add entities' code. at least parts with relations – Denis Alimov Aug 17 '18 at 13:00
  • A similar question to this exists at [Twig and Symfony2 - Entity was not found](https://stackoverflow.com/q/17338105/2045006) – Courtney Miles Aug 20 '18 at 03:12

2 Answers2

6

EntityNotFoundException is thrown from Doctrine's proxy. So you can use EAGER loading method to get rid of proxies and get NULL instead of exception.

zen
  • 980
  • 6
  • 18
1

This is the strategy I have adopted based on the comment made by iainn.

<?php
class Parent
{
    protected $child;

    public function getChild()
    {
        if ($this->child instance of \Doctrine\ORM\Proxy\Proxy) {
            try {
                $this->child->__load();
            } catch (\Doctrine\ORM\EntityNotFoundException $e) {
                $this->child = null
            }
        }

        return $this->child;
    }
}

I am sure it is not recommended for your entities to interact directly with proxies. But I preferred this over calling a known method on the entity (which would also have the effect of loading it) because the intention of this code is clearer to the next developer who might read it.

I'm not sure if there are any side effects with interacting with the proxy like this.

Courtney Miles
  • 3,756
  • 3
  • 29
  • 47