Git Product home page Git Product logo

psalm-plugin-doctrine's Introduction

Build Status

doctrine-psalm-plugin

A Doctrine plugin for Psalm (requires Psalm v4|v5).

Installation:

$ composer require --dev weirdan/doctrine-psalm-plugin
$ vendor/bin/psalm-plugin enable weirdan/doctrine-psalm-plugin

Testing

composer test

psalm-plugin-doctrine's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

psalm-plugin-doctrine's Issues

PossiblyInvalidArgument false-positive for Collection methods

vimeo/psalm 4.8.1
weirdan/doctrine-psalm-plugin 1.0.0

/** @param Collection<int, A>|Collection<int, B> */
public function deleteItemById(Collection $collection, int $id): void
{
    $matchedItems = $collection->filter(
        static function ($inCollectionItem) use ($id): bool {
            return $inCollectionItem->haveId($id);
        }
    );

    if (!$matchedItems->isEmpty()) {
        $collection->removeElement($matchedItems->first()); // yields PossiblyInvalidArgument
    }
}

psalm: PossiblyInvalidArgument: Argument 1 of Doctrine\Common\Collections\Collection::removeElement expects A, possibly different type A|B provided

It looks false-positive to me, it's impossible to call here Collection<int, A>::removeElement(B).

Stubbing Expr class

We use the Doctrine\ORM\Query\Expr methods in a few places when building queries. Some of these, such as orX() and andX() accept arbitrary numbers of arguments using func_get_args(). The causes the following error when analysing with Psalm.

ERROR: TooManyArguments - src/Repository/UserJournalEntryRepository.php:41:17 - Too many arguments for method Doctrine\ORM\Query\Expr::orX - expecting 1 but saw 2
                $qb->expr()->orX(
                    $qb->expr()->gt('uje.value.amount', '0'),
                    $qb->expr()->isNotNull('t')
                )

Is it possible to stub these methods? I'm happy to create a PR but don't know how to correctly annotate methods which accept arbitrary numbers of arguments.

Undefined constant 'GLOB_BRACE'

Docker image:

php:7.4.3-fpm-alpine

How to reproduce

composer require --dev weirdan/doctrine-psalm-plugin
vendor/bin/psalm-plugin enable weirdan/doctrine-psalm-plugin

vendor/bin/psalm

Stacktrace:

ncaught Error: Undefined constant 'GLOB_BRACE' in /srv/api/vendor/weirdan/doctrine-psalm-plugin/Plugin.php:32
Stack trace:
#0 /srv/api/vendor/weirdan/doctrine-psalm-plugin/Plugin.php(22): Weirdan\DoctrinePsalmPlugin\Plugin->getStubFiles()
#1 /srv/api/vendor/vimeo/psalm/src/Psalm/Config.php(1161): Weirdan\DoctrinePsalmPlugin\Plugin->__invoke(Object(Psalm\PluginRegistrationSocket), NULL)
#2 /srv/api/vendor/vimeo/psalm/src/Psalm/Internal/Analyzer/ProjectAnalyzer.php(493): Psalm\Config->initializePlugins(Object(Psalm\Internal\Analyzer\ProjectAnalyzer))
#3 /srv/api/vendor/vimeo/psalm/src/psalm.php(594): Psalm\Internal\Analyzer\ProjectAnalyzer->check('/srv/api/', false)
#4 /srv/api/vendor/vimeo/psalm/psalm(2): require_once('/srv/api/vendor...')
#5 {main}

Issue inferring types for ArrayCollection::filter

Hi again. Sorry for the spamming πŸ˜…

Using the below snippet, I get the following error InvalidTemplateParam - ... - Extended template param TKey expects type array-key, type empty given.

<?php
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
class Test
{
    /**
     * @var Collection<int, string>
     */
    private $strings;

    public function __construct()
    {
        $this->strings = new ArrayCollection();

        $this->strings->filter(
            function (string $s):bool {
                return $s !== '';
            });
    }
}

The same error comes when using strings->map, but not when using strings->exists or strings->forAll.
I can also prevent the error by adding a type annotation to the property initialization like this:

/** @var Collection<int, string> strings */
$this->strings = new ArrayCollection();

Any ideas what might be causing this issue?

Ensure right type by configuration

This will be blocked by #10

I found the case when the property (code) has different type from config

class User
{
	/** @var string */
	private $username;

	//ctor and other stuff
}
    <field name="username" type="string" column="username" nullable="true"/>

the error is that in config it's nullable, but in the code it's not

PossiblyFalseReference | PossiblyFalseArgument false-positive for Collection interface

weirdan/doctrine-psalm-plugin 0.11.3
vimeo/psalm 3.17.2

use Doctrine\Common\Collections\Collection;

function processCollection(Collection $collection)
{
        $matched = $collection->filter(function ($collectionItem) {
            return rand(0, 1) === 1;
        });

        if (!$matched->isEmpty()) {
            $matched->first()->hi(); // PossiblyFalseReference - Cannot call method hi on possibly false value (see https://psalm.dev/105)
            $collection->removeElement($matched->first()); // PossiblyFalseArgument - Argument 1 of Doctrine\Common\Collections\Collection::removeElement cannot be false, possibly false value provided (see https://psalm.dev/104)
        }
}

Neither first() nor last() can't return false on Collection that is not empty.

Support EntityManager

If you can point me in the general direction of how to do this (e.g. an open-source codebase that would benefit from this typing) I can create a PR

Stubbing doctrine/persistence classes

This package currently has a stub for, for example Doctrine\Common\Persistence\ObjectRepository. Though there's a compatibility layer using class_alias(), this class has been moved to Doctrine\Persistence\ObjectRepository. We should ensure the stub works for both namespaces.

Development plans

TL;DR

This project is looking for maintainers.

Current state

This package is currently outdated and supports neither newer Psalm versions (starting from v4) nor newer Doctrine versions (there should be some, but I haven't checked). I don't currently use Doctrine, so it doesn't scratch my itch anymore. Rather it has become a burden. I recognize the need for this package is still there though.

Plans

I have reasonable hopes to get tests green with the next Psalm release and release a version compatible with Psalm 4. Tests are very important to me, because it's my only way to see if things work as I don't use Doctrine myself.

After that I'd like to negotiate with Psalm's author, @muglug, to get this package under Psalm's umbrella GH org, similar to how some other plugins are managed. There I'll try to get the plugin updated to support new Doctrine versions, one last time, while simultaneously looking for people willing to maintain this. Once the package is in good shape, I will likely step down as a maintainer. I haven't fully decided yet whether I stop maintenance should I fail to find a co-maintainer, but this is a possibility. If I decide to continue, my efforts will be at the level of merging occasional PRs, but not more.

UndefinedInterfaceMethod-errors for methods in repository

Hi, thanks for the great plugin!

I have a question - I'm getting UndefinedInterfaceMethod-errors in my symfony4-project like this:

ERROR: UndefinedInterfaceMethod - src\ControllerShop\IndexController.php:45:68 - Method Doctrine\Common\Persistence\ObjectRepository::createquerybuilder does not exist
$qb = $this->getDoctrine()->getRepository(Article::class)->createQueryBuilder('a');

ERROR: UndefinedInterfaceMethod - src\ControllerShop\IndexController.php:98:83 - Method Doctrine\Common\Persistence\ObjectRepository::findforcompany does not exist
$staffToken = $this->getDoctrine()->getRepository(StaffToken::class)->findForCompany($company, $token);

Problem seems to be, that the methods are not checked against the real repository, but the generic ObjectRepository. Is it right, that the plugin does not recognise these methods in the repositories? Am I doing something wrong here?
Thanks in advance!

Stubbing DBAL QueryBuilder

Just wondering if there's any reason we do have stub for ORM QueryBuilder but don't have one for DBAL?

I could create one unless I miss something, just let me know.

Support findOneByXXX

Doctrine uses __call to allow specific findOneBy* methods - you could use MethodExistenceProviderInterface, MethodParamsProviderInterface and MethodReturnTypeProviderInterface to support the functionality, I think?

Parsing of entity annotations/attributes to determine repository class

Hey there,

I have entities which have own repository implementations.
These implementations are referred to with the Entity Attribute/Annotation (using repositoryClass option).

This plugin only provides generic support as of now.
Are you interested in having this feature part of this plugin?
I think I might find some time somewhen in the near future to implement that.

Happy to get feedback on this.

Configuration loading

This plugin needs to be able to load doctrine configuration for functionality like checking entity types, findBy* methods, etc.

Requires:

  • stubbing the connection so that no database is required
  • replacing reflection service so that classes need not to be loaded
  • fixing the annotation reader (or replacing it with custom one) so that classes need not to be loaded

Uncaught Exception: InvalidArgumentException Could not get class storage for doctrine\dbal\dbalexception

psalm 4.19.0
weirdan/doctrine-psalm-plugin v2.2.0
Symfony 6.0.3
PHP 8.1

> ./vendor/bin/psalm --show-info=true
Target PHP version: 8.1 (inferred from composer.json)
Scanning files...
Analyzing files...

β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘Uncaught Exception: InvalidArgumentException Could not get class storage for doctrine\dbal\dbalexception
Emitted in /Users/dmitriyrybin/PhpstormProjects/.../app/api/vendor/vimeo/psalm/src/Psalm/Internal/Provider/ClassLikeStorageProvider.php:46
Stack trace in the forked worker:
#0 /Users/dmitriyrybin/PhpstormProjects/.../app/api/vendor/vimeo/psalm/src/Psalm/Internal/Codebase/ClassLikes.php(628): Psalm\Internal\Provider\ClassLikeStorageProvider->get('Doctrine\\DBAL\\D...')
...

If I comment <pluginClass class="Weirdan\DoctrinePsalmPlugin\Plugin"/> in psalm.xml or downgrading weirdan/doctrine-psalm-plugin to v2.0.1 everything works fine

INFO: PropertyNotSetInConstructor and INFO: MissingConstructor for all entities

Is it expected that these are reported as INFO? Or should they not appear in psalm errors at all.

I am running Symfony 6.1.6, psalm 4.30.0 and weirdan/doctrine-psalm-plugin 2.5.0


INFO: MissingConstructor - src/Entity/SupportTicketDepartment.php:17:17 - App\Entity\SupportTicketDepartment has an uninitialized property App\Entity\SupportTicketDepartment::$id, but no constructor (see https://psalm.dev/073)
    private int $id;

...

INFO: PropertyNotSetInConstructor - src/Entity/SupportTicketMailBreakLine.php:28:19 - Property App\Entity\SupportTicketMailBreakLine::$admin is not defined in constructor of App\Entity\SupportTicketMailBreakLine or in any private or final methods called in the constructor (see https://psalm.dev/074)
    private Admin $admin;

PropertyNotSetInConstructor: Property Doctrine\ORM\EntityRepository::$_entityName is not defined in constructor of Repository and in any methods called in the constructor

Thanks for this plugin. It removes a lot of false errors from my codebase ❀️

I wonder if we can also fix this error:

INFO: PropertyNotSetInConstructor - src/Infrastructure/Persistence/Doctrine/Repository/DoctrineSettlementRepository.php:15:13 - Property Doctrine\ORM\EntityRepository::$_entityName is not defined in constructor of Infrastructure\Persistence\Doctrine\Repository\DoctrineSettlementRepository and in any methods called in the constructor
final class DoctrineSettlementRepository extends AbstractServiceEntityRepository implements SettlementRepository

code:

final class DoctrineSettlementRepository extends AbstractServiceEntityRepository implements SettlementRepository
{
    public function __construct(RegistryInterface $registry)
    {
        parent::__construct($registry, Settlement::class);
    }

MethodSignatureMismatch due to EntityManager:.find() stub

We have a code where we currently extend Doctrine\ORM\EntityManger. On error level 7 the following error pops up:

ERROR: MethodSignatureMismatch - .../EntityManager.php:X:Y - Argument 1 of Doctrine\ORM\EntityManager::find has wrong type 'string', expecting '' as defined by Doctrine\Persistence\ObjectManager::find (see https://psalm.dev/042)
class EntityManager extends DoctrineEntityManager

Once I remove native type from find()'s 1st parameter in vendor/weirdan/doctrine-psalm-plugin/stubs/EntityManagerInterface.phpstub the error disappears. But that doesn't seem like a correct solution.
I am also wondering whether this could be a Psalm bug related to ParamNameMismatch because ObjectManager::find() names the parameter as $className instead of $entityName.

Support more consequences of non-empty collections

Since #94, this extension supports the scenario of checking a Collections's emptiness and then using first() and last() on that collection without worrying about the return type being false. This is great, however, a Collection being empty has more effects than this, including:

  • toArray() returning a non-empty-array
  • getKeys() returning a non-empty-list
  • getValues() returning a non-empty-list
  • code in loops iterating over a non-empty array will be executed at least once

Also, a Collection being empty could be asserted by

  • checking count() returns a value other than 0
  • calling add() at least once
  • calling set() at least once
  • calling a custom method that was annotated with @psalm-assert !$collection->isEmpty() with the collection
  • checking contains() returns true
  • checking current() doesn't return false
  • checking key() doesn't return null
  • checking next() doesn't return false
  • the Collection being created using the map() method of another non-empty Collection
  • checking indexOf() doesn't return false

LessSpecificImplementedReturnType false-positive

LessSpecificImplementedReturnType - src/Repository/SomethingRepository.php:9:12 - The inherited return type 'list<App\Entity\Something>' for Doctrine\ORM\EntityRepository::findAll is more specific than the implemented return type for Doctrine\ORM\EntityRepository::findall 'array<array-key, App\Entity\Something>'

Code in my SomethingRepository:

/**
 * @method Something[]    findAll() (this PHPDoc was auto-generated by Symfony)
 * @extends ServiceEntityRepository<Something>
 */
class SomethingRepository extends ServiceEntityRepository
{
 */

This is a snippet from Doctrine\ORM\EntityRepository

/**
 * Finds all entities in the repository.
 *
 * @return array The entities.
 */
public function findAll()
{
    return $this->findBy([]);
}

Just an array.

This is from Doctrine\Persistence\ObjectRepository that implemented by Doctrine\ORM\EntityRepository:

/**
 * Contract for a Doctrine persistence layer ObjectRepository class to implement.
 *
 * @template T
 */
interface ObjectRepository
{
.....

    /**
     * Finds all objects in the repository.
     *
     * @return array<int, object> The objects.
     *
     * @psalm-return T[]
     */
    public function findAll();
....
}

So it returns just T[], Something[] in my case.

Looks like there is a problem in the plugin's stub files.

Triple false-positive for PropertyNotSetInConstructor any class extends ServiceEntityRepository

weirdan/doctrine-psalm-plugin 1.0.0
vimeo/psalm 4.7.0

For any class that extends ServiceEntityRepository I got three false-positive PropertyNotSetInConstructor errors. These variables are properly set in EntityRepository class.

ERROR: PropertyNotSetInConstructor - src/Repository/RedBallRepository.php:20:7 - Property App\Repository\RedBallRepository::$_entityName is not defined in constructor of App\Repository\RedBallRepository and in any methods called in the constructor (see https://psalm.dev/074)
class RedBallRepository extends ServiceEntityRepository

ERROR: PropertyNotSetInConstructor - src/Repository/RedBallRepository.php:20:7 - Property App\Repository\RedBallRepository::$_em is not defined in constructor of App\Repository\RedBallRepository and in any methods called in the constructor (see https://psalm.dev/074)
class RedBallRepository extends ServiceEntityRepository

ERROR: PropertyNotSetInConstructor - src/Repository/RedBallRepository.php:20:7 - Property App\Repository\RedBallRepository::$_class is not defined in constructor of App\Repository\RedBallRepository and in any methods called in the constructor (see https://psalm.dev/074)
class RedBallRepository extends ServiceEntityRepository

Composer conflict because phpstan/phpdoc-parser is locked to ~1.5.0

When trying to update to 2.4.0, composer install fails because of a conflict. In my case its doctrine/coding-standard, but there could probably also be conflicts with other packages.

The reason is that phpstan/phpdoc-parser was locked to ~1.5.0 (which is a relatively old version, current is 1.9.0) in this commit: 16e8192

The commit message is not related to adding this requirement, so I'm not sure if this was added by accident.

Is locking the phpstan/phpdoc-parser version really necessary or can this tight version constraint be removed again?

Your requirements could not be resolved to an installable set of packages.

  Problem 1
    - Root composer.json requires doctrine/coding-standard 10.0.0 -> satisfiable by doctrine/coding-standard[10.0.0].
    - doctrine/coding-standard 10.0.0 requires slevomat/coding-standard ^8.2 -> satisfiable by slevomat/coding-standard[8.2.0, ..., 8.5.2].
    - slevomat/coding-standard[8.2.0, ..., 8.3.0] require phpstan/phpdoc-parser ^1.6.2 -> satisfiable by phpstan/phpdoc-parser[1.6.2, ..., 1.9.0].
    - slevomat/coding-standard[8.5.0, ..., 8.5.2] require phpstan/phpdoc-parser >=1.7.0 <1.9.0 -> satisfiable by phpstan/phpdoc-parser[1.7.0, 1.8.0].
    - slevomat/coding-standard 8.4.0 requires phpstan/phpdoc-parser >=1.7.0 <1.8.0 -> satisfiable by phpstan/phpdoc-parser[1.7.0].
    - You can only install one version of a package, so only one of these can be installed: phpstan/phpdoc-parser[1.5.0, ..., 1.9.0].
    - weirdan/doctrine-psalm-plugin v2.4.0 requires phpstan/phpdoc-parser ~1.5.0 -> satisfiable by phpstan/phpdoc-parser[1.5.0, 1.5.1].
    - Root composer.json requires weirdan/doctrine-psalm-plugin 2.4.0 -> satisfiable by weirdan/doctrine-psalm-plugin[v2.4.0].

Could not enable the plugin

$ composer require --dev weirdan/doctrine-psalm-plugin
    1/1:	http://repo.packagist.org/p/provider-latest$7a09c6bfb6355b10ab8adaba5751981b1496747a29a02c40c29455abac1dbb6a.json
    Finished: success: 1, skipped: 0, failure: 0, total: 1
Using version ^0.4.2 for weirdan/doctrine-psalm-plugin                                           
./composer.json has been updated
Loading composer repositories with package information
Updating dependencies (including require-dev)                                                    
Package operations: 1 install, 0 updates, 0 removals
  - Installing weirdan/doctrine-psalm-plugin (0.4.2): Loading from cache
Package weirdan/psalm-doctrine-collections is abandoned, you should avoid using it. Use weirdan/doctrine-psalm-plugin instead.
Writing lock file
Generating autoload files
ocramius/package-versions:  Generating version class...
ocramius/package-versions: ...done generating version class
phpstan/extension-installer: Extensions installed

$ vendor/bin/psalm-plugin enable weirdan/doctrine-psalm-plugin

 [ERROR] Unknown plugin class weirdan/doctrine-psalm-plugin

It worked fine with weirdan/psalm-doctrine-collections though...

$ vendor/bin/psalm-plugin show

Enabled
-------

 ------------------------------------ ------------------------------------ 
  Package                              Class                               
 ------------------------------------ ------------------------------------ 
  psalm/plugin-phpunit                 Psalm\PhpUnitPlugin\Plugin          
  weirdan/psalm-doctrine-collections   Weirdan\DoctrinePsalmPlugin\Plugin  
 ------------------------------------ ------------------------------------ 

Available
---------

 ! [NOTE] No plugins available                                                                                          

Doctrine\Common\Persistence vs Doctrine\Persistence

Doctrine is slowly phasing out Doctrine/Common and they deprecated Doctrine\Common\Persistence\ObjectRepository.

The replacement is Doctrine\Persistence\ObjectRepository which is the same class but in another namespace.

However, when we get rid of the depreciation by replacing imports, this plugin does not offer stubs for the new namespace.

How should we proceed on this issue?

Template QueryBuilder

I get this error:

ERROR: MixedReturnTypeCoercion - ProfileRepository.php:22:16 - The declared return type 'array<array-key, Profile>' for ProfileRepository::getProfiles is more specific than the inferred return type 'list<mixed>' (see https://psalm.dev/197)
     * @return array<Profile>

With this Repo (simple example of using QueryBuilder):

/**
 * @template-extends ServiceEntityRepository<Profile>
 */
class ProfileRepository extends ServiceEntityRepository
{
    public function __construct(ManagerRegistry $registry)
    {
        parent::__construct($registry, Profile::class);
    }

    /**
     * @return array<Profile>
     */
    public function getProfiles(): array
    {
        return $this->createQueryBuilder('p')->getQuery()->getResult();
    }
}

So I'm questioning myself: Should EntityRepository->createQueryBuilder() return a Query with the templated type Profile instead of mixed? Right now Query can be templated thanks to this plugin but the QueryBuilder cannot pass this information to the Query right now so it returns mixed. But if we maybe add the template annotation to the QueryBuilder we could pass it to Query. I tried to update the stubs for QueryBuilder but this was of course not sufficient. So i tried to update the plugin with an hook like the Collection hook already provided but failed to get it working. So first, i wanted to check if this route is the right before putting more work into it. So what do you think?

Stubbing Query class

I need a lot of suppressions because the methods of the Query class like getResult(), getSingleResult(), getOneOrNullResult(), etc. return mixed. I've tried to create a stub for the AbstractQuery (thats where the methods actually live), but I was only able to let it return array (in the case of getResult()) which causes other issues. I am not really familiar with the concepts of generics, but I think this would be the way to go here.

Any hints whether this is possible at all and maybe point me in the right direction?

@psalm-mutation-free & isEmpty

Any collection which extends ArrayCollection produce error:
ERROR: MissingImmutableAnnotation - src/Sales/Domain/Collection/ReturnItemCollection.php:20:7 - Doctrine\Common\Collections\Collection::isEmpty is marked @psalm-immutable, but Doctrine\Common\Collections\ArrayCollection::isEmpty is not marked @psalm-immutable (see https://psalm.dev/213) class ReturnItemCollection extends ArrayCollection implements JsonSerializable

NullArgument false-positive on ArrayCollection

Psalm 3.14.2@3538fe1955d47f6ee926c0769d71af6db08aa488 + weirdan/doctrine-psalm-plugin

ERROR: NullArgument - src/Entity/Organization.php:155:13 - Argument 1 of Doctrine\Common\Collections\ArrayCollection::offsetSet cannot be null, null value provided to parameter with type int|string (see https://psalm.dev/057)
$this->staff[] = $staff;

But offsetSet can be null:

    /**
     * Required by interface ArrayAccess.
     *
     * {@inheritDoc}
     */
    public function offsetSet($offset, $value)
    {
        if (! isset($offset)) {
            $this->add($value);

            return;
        }

        $this->set($offset, $value);
    }

If I turn off the plugin, the errors are disappeared.

The plugin breaks type check of valid extended dbal connection class

<?php
declare(strict_types=1);

namespace Repro;

class Conn extends \Doctrine\DBAL\Connection
{
}
Scanning files...
Analyzing files...



ERROR: MethodSignatureMismatch - src/Conn.php:6:7 - Argument 1 of Doctrine\DBAL\Connection::prepare has wrong type 'string', expecting '' as defined by Doctrine\DBAL\Driver\Connection::prepare (see https://psalm.dev/042)
class Conn extends \Doctrine\DBAL\Connection


------------------------------
1 errors found
------------------------------

Checks took 0.00 seconds and used 4.382MB of memory
No files analyzed
Psalm was unable to infer types in the codebase

Repro: https://github.com/zerkms/psalm-plugin-doctrine-issue-91

I cannot see anything particularly suspicious in the stub, so it also could be a psalm bug.

_WhereExpr type doesn't include all possible Expr classes

I've just updated to 0.7.0 and am getting errors reporting when passing Doctrine\ORM\Query\Expr\Comparison objects into Doctrine\ORM\QueryBuilder::andWhere().

The QueryBuilder stub defines a custom Psalm type @psalm-type _WhereExpr=Expr\Base|string. Unfortunately Doctrine's expression classes don't all extend Doctrine\ORM\Query\Expr\Base.

I believe the type needs changing to @psalm-type _WhereExpr=Expr\Base|Expr\Comparison|string.

Collection not typed when using EntityRepository::matching

TL;DR: EntityRepository<T>::matching has return type Collection, should be Collection<int, T>

How to reproduce

Code: https://psalm.dev/r/678bf40ce6
Error: The type 'Doctrine\Common\Collections\Collection' is more general than the declared return type 'Doctrine\Common\Collections\Collection<int, Entity>' for MyRepository::foo
Versions of my packages:

doctrine/collections                  1.6.6
doctrine/orm                          v2.7.3  
vimeo/psalm                           3.12.2
weirdan/doctrine-psalm-plugin         0.11.3

Is it reproducible or is it just me?

The case for adding matching to the stub

I started digging a bit and found that:

BUT:

Therefore I'd like to add matching to the EntityRepository-stub. I'm happy to provide a PR, just let me know.

Thank you for taking the time and have a nice day!

Bug: One-off declarations on @psalm-params for Connection::executeUpdate && Connection::executeStatement

@psalm-param definitions for $query and $types are off by one on executeUpdate and executeStatement.

Connection::executeUpdate

* @psalm-param scalar[] $params The query parameters.

* @psalm-param int[]|string[] $types The parameter types.

Connection::executeStatement

* @psalm-param scalar[] $params The query parameters.

* @psalm-param int[]|string[] $types The parameter types.


Proposal:

-     * @psalm-param scalar[]        $params The query parameters.
+     * @psalm-param scalar[]        $query The query parameters.
-     * @psalm-param int[]|string[]  $types  The parameter types.
+     * @psalm-param int[]|string[]  $params  The parameter types.

public function [...](string $query, array $params = [], array $types = []): int {}

Error Output:

 Argument 2 of Doctrine\DBAL\Connection::executeUpdate expects array<array-key, scalar>, array{ids: array<array-key, mixed>} provided (see https://psalm.dev/004)
            array(
                'ids' => $articleIDs
            ),

BR
Martin

Explain what the stubs do

I added this plugin to my large project using Doctrine and it only added two new issues. I am wondering how the stubs work, do i need to do something myself to benefit from the plugin?

I would appreciate some more docs on the features

InvalidArgument false-positive

InvalidArgument - src/Repository/SomethingRepository.php:20:29 - Argument 1 of Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository::__construct expects Doctrine\Common\Persistence\ManagerRegistry, Doctrine\Persistence\ManagerRegistry provided

Doctrine\Common\Persistence\ManagerRegistry has been moved to Doctrine\Persistence\ManagerRegistry namespace.

Support reduced type inferring from Collection::filter

Plugin should add capability to infer reduced type from Collection::filter based on assertions in a callback, similarly as Psalm currently does for array_filter. Here is what should be supported: https://psalm.dev/r/1b5cbdc9c0

Backstory: From conversation with @muglug:

Add that to the doctrine plugin

This is the current annotation: https://github.com/doctrine/collections/blob/a4504c79efd8847cc77d10b70209ef838b10338f/lib/Doctrine/Common/Collections/Collection.php#L214-L225

there’s basically no way to annotate that in a docblock

Improve composer dependencies

Hello,

I was looking into using this plugin, but notices it downloads ORM (while I am only using DBAL).
This is caused by these composer lines:
https://github.com/weirdan/doctrine-psalm-plugin/blob/d75579d076dd69fe5120bf8a401cea06f2e04919/composer.json#L16-L17

Since you are only providing stubs, I am not sure why you need this as a dependency.
Would it be possible to declare it as a dev dependency if you require it for this package or remove it if you don't have a hard dependency on it?

I currently solved the issue by copying the DBAL stubs locally.

ImpureMethodCall false-positive for Collection::toArray()

class Test {
    
    private Collection $collection;
    
    /**
     * @psalm-mutation-free
     */
    public function test(): array
    {
        return $this->collection->toArray();
    }
}

ImpureMethodCall: Cannot call an possibly-mutating method Doctrine\Common\Collections\Collection::toArray from a mutation-free context

doctrine/orm 2.7.4
weirdan/doctrine-psalm-plugin 0.11.3
vimeo/psalm 3.18.2

`LessSpecificReturnType` on `EntityManagerInterface::find`

Hey there,

somehow, psalm asserts that the return type of find is not nullable.
The generic is properly detected tho.

Code

use Doctrine\ORM\EntityManagerInterface;

final class Foo
{
    /**
     * @var EntityManagerInterface
     */
    private $entityManager;
    /**
     * @psalm-param positive-int $id
     */
    private function status(int $leadId): ?Entity
    {
        return $this->entityManager->find(Entity::class, $leadId);
    }
}

Psalm output

ERROR: LessSpecificReturnType - The inferred return type 'Entity' for Foo::status is more specific than the declared return type 'Entity|null' (see https://psalm.dev/088)
    private function status(int $leadId): ?Entity

Versions

Package Version
vimeo/psalmΒ  4.7.0
weirdan/doctrine-psalm-plugin 1.0.0
doctrine/ormΒ  2.7.5

I've already tried to replace ?T with T|null locally (within the stubfile, and cleared cache afterwards) but that did not work as expected.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.