Doctrine return null in place of EntityNotFoundException
Asked Answered
P

2

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.

Pemphigus answered 17/8, 2018 at 10:25 Comment(5)
That PR is for the jms/serializer bundle - are you using that in your project?Peen
Sorry, I'm not. I realised my mistake after posting.Pemphigus
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.Peen
please add entities' code. at least parts with relationsAgora
A similar question to this exists at Twig and Symfony2 - Entity was not foundPemphigus
P
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.

Pemphigus answered 21/8, 2018 at 5:31 Comment(1)
I feel as this should be a Doctrine/Symfony configuration optionRess
M
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.

Mill answered 17/8, 2018 at 18:32 Comment(0)
P
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.

Pemphigus answered 21/8, 2018 at 5:31 Comment(1)
I feel as this should be a Doctrine/Symfony configuration optionRess

© 2022 - 2024 — McMap. All rights reserved.