Computing of a virtual Doctrine entity's property after its loading

Published on 2021-05-15 • Modified on 2021-05-15

In this snippet, we see how to compute a virtual Doctrine entity's property after its loading. We use the postLoad Doctrine event. Of course, a simple getter could do the job, but if you need a service, the listener would be mandatory to inject the service into it as I did in the example (even I don't use the injected service). The virtual property is declared like this:

/**
 * Virtual property for snippet 147.
 *
 * @var ?string the API Platform IRI of the resource (dummy example)
 */
 protected ?string $iri = null;
Check out a complete Doctrine listener example in this snippet.


<?php

/** @noinspection PhpPropertyOnlyWrittenInspection */

// src/Doctrine/Listener/ArticleListener.php

declare(strict_types=1);

namespace App\Doctrine\Listener;

use App\Entity\Article;
use App\Repository\ArticleRepository;

class ArticleListener
{
    private ArticleRepository $articleRepository;

    public function __construct(ArticleRepository $articleRepository)
    {
        $this->articleRepository = $articleRepository;
    }

    /**
     * This is a dummy example.
     */
    public function postLoad(Article $article): void
    {
        $article->setIri('/articles/'.$article->getId());
    }
}
Bonus, the snippet to run this code: 🎉
<?php

declare(strict_types=1);

// src/Controller/Snippet/Snippet147Trait.php

namespace App\Controller\Snippet;

use App\Repository\ArticleRepository;

/**
 * I am using a PHP trait to isolate each snippet in a file.
 * This code should be called from a Symfony controller extending AbstractController (as of Symfony 4.2)
 * or Symfony\Bundle\FrameworkBundle\Controller\Controller (Symfony <= 4.1).
 * Services are injected in the main controller constructor.
 *
 * @property ArticleRepository $articleRepo
 */
trait Snippet147Trait
{
    /**
     * @noinspection OneTimeUseVariablesInspection
     */
    public function snippet147(): void
    {
        $article = $this->articleRepo->findById(147);

        echo $article->getIri(); // The IRI is computed in the Article listener

        // That's it! 😁
    }
}

 Run this snippet  ≪ this.showUnitTest ? this.trans.hide_unit_test : this.trans.show_unit_test ≫  More on Stackoverflow   Read the doc  More on the web

<?php

declare(strict_types=1);

namespace App\Tests\Controller\Snippets;

use App\Repository\ArticleRepository;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;

/**
 * @covers Snippet147Trait
 */
final class Snippet147Test extends KernelTestCase
{
    private ArticleRepository $articleRepo;

    protected function setUp(): void
    {
        self::bootKernel();
        $this->articleRepo = self::getContainer()->get(ArticleRepository::class);
    }

    /**
     * @covers ArticleListener::postLoad
     */
    public function testSnippet147(): void
    {
        $article = $this->articleRepo->findById(147);
        self::assertSame('/articles/147', $article->getIri());
    }
}