Take this into account when using doctrine

Nacho Colomina Torregrosa - Apr 6 '23 - - Dev Community

I would like to share with you a common error which can happen when using doctrine and it can be a nightmare until you notice why it's happening.

Let's see it using an example. Imagine we are working with these entities:

#[ORM\Entity(repositoryClass: UserRepository::class)]
class User {

    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column]
    private ?int $id = null;

    #[ORM\Column(length: 150)]
    private string $name;

    #[ORM\Column(length: 255)]
    private string $pass;

    #[ORM\Column(length: 100)]
    private string $email;

    // getters & setters
}

#[ORM\Entity(repositoryClass: UserAddressRepository::class)]
class UserAddress {

    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column]
    private ?int $id = null;

    #[ORM\ManyToOne]
    private User $user;

    #[ORM\Column(length: 150)]
    private string $address;

    // getters & setters
}

Enter fullscreen mode Exit fullscreen mode

Now, when you get a request for a new register you do something like this:

$user = new User();
$user->setName('Peter');
$user->setPass('xxxxx');
$user->setEmail('peter.morris@gmail.com');

$address = new UserAddress();
$address->setUser($user);
$address->setAddress('Down street 25B');

$em->persist($user);
$em->persist($address);
$em->flush();

$eventDispatcher->dispatch(new UserRegisteredEvent($user));
Enter fullscreen mode Exit fullscreen mode

So far, this code seems right. It creates a user and an Address, persists them on the database and dispatches and event. Let's see now the subscriber:


class UserSubscriber implements EventSubscriberInterface {

    public static function getSubscribedEvents(): array
    {
        return [
            UserRegisteredEvent::class => 'onUserRegistered'
        ];
    }

    public function onUserRegistered(UserRegisteredEvent $e){
       $user = $e->getUser();
       $address = $user->getAddress();
       $addrName = $address->getAddress();
    }
}

Enter fullscreen mode Exit fullscreen mode

After executing line $addrName = $address->getAddress() you will get the following error:

  Call to a member function getAddress() on null  
Enter fullscreen mode Exit fullscreen mode

That happens because we've persisted both entities but we have not refreshed user entity.

To avoid this kind of errors, we can follow the next steps (among others of course):

Refresh user object before passing it to the event

$em->persist($user);
$em->persist($address);
$em->flush();

$em->refresh($user);

$eventDispatcher->dispatch(new UserRegisteredEvent($user))
Enter fullscreen mode Exit fullscreen mode

This allows us to having user re-hydrated before using in the subscriber.

Passing user identifier to the event

$em->persist($user);
$em->persist($address);
$em->flush();

$eventDispatcher->dispatch(new UserRegisteredEvent($user->getId()));

// -------------------------------------------------------

public function onUserRegistered(UserRegisteredEvent $e){

    $user = $em->getRepository(User::class)->find($e->getId());

    $user = $e->getUser();
    $address = $user->getAddress();
    $addrName = $address->getAddress();
}
Enter fullscreen mode Exit fullscreen mode

This way pass the user identifier to the event so it's the subscriber who gets a fresh user from the database

Conclusion

This can seem a really simple error but it can be a nightmare when you have a project working on production and you start getting this kind of errors and your code is syntactically correct but not semantically.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . .