Search code examples
doctrine-odmpsalm-php

Psalm error when extending a class with template


I have a PHP 8.1 application with Symfony 5.4 and Doctrine 2.17. We use psalm 5.18. With Doctrine ODM bundle (v4.7) there is a ServiceDocumentRepository class:

<?php

declare(strict_types=1);

namespace Doctrine\Bundle\MongoDBBundle\Repository;

use Doctrine\ODM\MongoDB\Repository\DocumentRepository;

/**
 * Optional DocumentRepository base class with a simplified constructor (for autowiring).
 *
 * To use in your class, inject the "registry" service and call
 * the parent constructor. For example:
 *
 * namespace AppBundle\Repository;
 *
 * use AppBundle\Document\YourDocument;
 * use Doctrine\Bundle\MongoDBBundle\ManagerRegistry;
 * use Doctrine\Bundle\MongoDBBundle\Repository\ServiceDocumentRepository;
 *
 * class YourDocumentRepository extends ServiceDocumentRepository
 * {
 *     public function __construct(ManagerRegistry $registry)
 *     {
 *         parent::__construct($registry, YourDocument::class);
 *     }
 * }
 *
 * @template T of object
 * @template-extends DocumentRepository<T>
 */
class ServiceDocumentRepository extends DocumentRepository implements ServiceDocumentRepositoryInterface
{
    /** @use ServiceRepositoryTrait<T> */
    use ServiceRepositoryTrait;
}

Now, I have my class that extends it:

<?php

declare(strict_types=1);

namespace App\Infrastructure\Persistence\Doctrine\Repository;

use Doctrine\Bundle\MongoDBBundle\Repository\ServiceDocumentRepository;

/**
 * @implements DocumentRepository<Trip>
 */
class TripRepository extends ServiceDocumentRepository {/** some code here **/}

Psalm gives me this error when inspecting:

ERROR: MissingTemplateParam - src/Infrastructure/Persistence/Doctrine/Repository/TripRepository.php:27:7 - App\Infrastructure\Persistence\Doctrine\Repository\TripRepository has missing template params when extending Doctrine\Bundle\MongoDBBundle\Repository\ServiceDocumentRepository, expecting 1 (see https://psalm.dev/182)

I tried changing @implements to @extends or @template-extends. I added @template T of Trip, but nothing seems to be working...


Solution

    1. You need to use the classnames referenced in docblocks
    2. extends ... should be used with @extends, and implements ... with @implements

    So the following should work:

    <?php
    
    declare(strict_types=1);
    
    namespace App\Infrastructure\Persistence\Doctrine\Repository;
    
    use Doctrine\Bundle\MongoDBBundle\Repository\ServiceDocumentRepository;
    
    /**
     * @extends ServiceDocumentRepository<Trip>
     * NOTE: use extends and match the class name you're extending
     */
    class TripRepository extends ServiceDocumentRepository {/** some code here **/}