phpstan-doctrine
phpstan-doctrine copied to clipboard
Call to an undefined method Sylius\Component\Core\Repository\*::findOneBy*() and other magic methods
On any released version of Sylius-Standard, I couldn't get phpstan-doctrine to work.
Full error :
Call to an undefined method Sylius\Component\Core\Repository\OrderRepositoryInterface::findOneByThing().
Here's a minimal reproducer :
<?php
namespace App\Controller;
use Sylius\Component\Core\Repository\OrderRepositoryInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
class GrumpyGnomeController extends AbstractController
{
public function __construct(
private readonly OrderRepositoryInterface $orderRepository,
)
{
}
#[Route('/grumpy/gnome', name: 'app_grumpy_gnome')]
public function index(): Response
{
$a = $this->orderRepository->findOneByThing();
return $this->render('grumpy_gnome/index.html.twig', [
'controller_name' => 'GrumpyGnomeController',
]);
}
}
use Sylius\Component\Order\Repository\OrderRepositoryInterface as BaseOrderRepositoryInterface;
/**
* @template T of OrderInterface
*
* @extends BaseOrderRepositoryInterface<T>
*/
interface OrderRepositoryInterface extends BaseOrderRepositoryInterface
use Sylius\Component\Resource\Repository\RepositoryInterface;
/**
* @template T of OrderInterface
*
* @extends RepositoryInterface<T>
*/
interface OrderRepositoryInterface extends RepositoryInterface
use Doctrine\Persistence\ObjectRepository;
/**
* @template T of ResourceInterface
*
* @extends ObjectRepository<T>
*/
interface RepositoryInterface extends ObjectRepository
/**
* Contract for a Doctrine persistence layer ObjectRepository class to implement.
*
* @template-covariant T of object
*/
interface ObjectRepository
phpstan.neon
includes:
- vendor/phpstan/phpstan-doctrine/extension.neon
parameters:
level: 4
paths:
- src
doctrine:
ormRepositoryClass: Sylius\Component\Resource\Repository\RepositoryInterface
objectManagerLoader: tests/object-manager.php
I've configured an object-manager.php test just in case and it doesn't improve the detection.
Sylius do not use ServerEntityManager
You can check this by running PHPStan with Xdebug and seeing where it ends in EntityRepositoryClassReflectionExtension but in my opinion this can only work if OrderInterface is an entity and has a field named $thing. Which it probably isn't because interfaces can't declare properties.
foreach ($entityClassNames as $entityClassName) {
In this line, entityClassNames is empty.
Here's the value of $templateTypeMap :
PHPStan\Type\Generic\TemplateTypeMap {#22787
-types: array:1 [
"TEntityClass" => PHPStan\Type\ObjectWithoutClassType {#13595
-subtractedType: null
}
]
-lowerBoundTypes: []
-resolvedToBounds: null
}
$entityClassType :
PHPStan\Type\ObjectWithoutClassType {#13595
-subtractedType: null
}
$entityClassNames is an empty array and field name is fine. (I've changed to "name" because name exists on the order entity).
I've changed the repository to use my entity instead of the interface, the error and data previously shared is the same.
/**
* @template T of Order
*
* @extends BaseOrderRepositoryInterface<T>
*/
interface OrderRepositoryInterface extends BaseOrderRepositoryInterface
I got it to work by modifying these.
Whatever I change in phpdoc of Sylius\Component\Core\Repository\OrderRepositoryInterface has no effect.
/**
* @template T of OrderInterface
*
* @extends BaseOrderRepositoryInterface<T>
*/
interface OrderRepositoryInterface extends BaseOrderRepositoryInterface
Modifying type in @template had no effect Sylius\Component\Order\Repository\OrderRepositoryInterface
/**
* @template T of Order
*
* @extends RepositoryInterface<T>
*/
interface OrderRepositoryInterface extends RepositoryInterface
Dropping @template and using my own entity works here Sylius\Component\Order\Repository\OrderRepositoryInterface
use App\Entity\Order\Order;
/**
* @extends RepositoryInterface<Order>
*/
interface OrderRepositoryInterface extends RepositoryInterface
And finally for a clean solution :
Following this tutorial : https://docs.sylius.com/en/1.12/customization/repository.html
App\Repository\OrderRepositoryInterface
<?php
declare(strict_types=1);
namespace App\Repository;
use App\Entity\Order\Order;
use Sylius\Component\Core\Repository\OrderRepositoryInterface as BaseOrderRepositoryInterface;
/**
* @extends BaseOrderRepositoryInterface<Order>
*/
interface OrderRepositoryInterface extends \Sylius\Component\Core\Repository\OrderRepositoryInterface
{
}
The doctrine configuration is required :
parameters:
doctrine:
objectManagerLoader: tests/object-manager.php
This only work for Sylius 1.13+. There was no template phpdoc before. Maybe the @extends with ObjectManager would work