Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Phpstan Doctrine Laravel Package

phpstan/phpstan-doctrine

PHPStan extension for Doctrine ORM/ODM: validates DQL and QueryBuilder, infers repository magic methods and EntityManager return types, checks entity field/relationship type mismatches and mapping errors, improves query result typing, and flags proxy-related issues.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require --dev phpstan/phpstan-doctrine
    

    Use phpstan/extension-installer for automatic configuration, or manually include:

    includes:
        - vendor/phpstan/phpstan-doctrine/extension.neon
    
  2. First Use Case: Run PHPStan on a Doctrine-heavy project:

    vendor/bin/phpstan analyse src
    

    The extension will immediately validate:

    • Entity repository method calls (findBy*, findOneBy*, countBy*).
    • Basic DQL syntax (if objectManagerLoader is configured).

Implementation Patterns

Core Workflows

  1. Repository Method Validation:

    // Validated automatically
    $user = $userRepository->findOneBy(['email' => 'test@example.com']);
    

    PHPStan will infer $user as ?User (nullable) and validate field names (email).

  2. QueryBuilder/DQL Type Inference:

    $query = $entityManager->createQuery('SELECT u FROM App\Entity\User u');
    $users = $query->getResult(); // array<User>
    

    Requires objectManagerLoader in phpstan.neon:

    parameters:
        doctrine:
            objectManagerLoader: tests/bootstrap.php
    
  3. Custom Repository Base Class:

    parameters:
        doctrine:
            ormRepositoryClass: App\Repository\CustomRepository
    

    Extends validation to custom repository methods.

  4. Dead Code Detection: Disable false positives for Doctrine-managed fields:

    #[ORM\GeneratedValue]
    private ?int $id = null; // Won't trigger "unused property" warnings
    

Integration Tips

  • Symfony Projects: Use the provided Symfony 4/5 objectManagerLoader examples.
  • Gedmo Extensions: Enable dead-code detection for Gedmo fields (e.g., Timestampable).
  • Dynamic QueryBuilders: Avoid passing QueryBuilders to methods to enable static analysis.
  • Collection Methods: Narrow Collection::first() return types when isEmpty() is checked:
    if (!$collection->isEmpty()) {
        $item = $collection->first(); // User (not User|false)
    }
    

Gotchas and Tips

Pitfalls

  1. DQL Validation Limitations:

    • Subqueries return mixed (not statically analyzable).
    • Dynamic expressions (e.g., ->select($dynamicField)) break type inference.
    • Enable reporting with:
      parameters:
          doctrine:
              reportDynamicQueryBuilders: true
      
  2. Custom Types:

    • Missing descriptors for custom Doctrine types cause failures. Enable reporting:
      parameters:
          doctrine:
              reportUnknownTypes: true
      
    • Use ReflectionDescriptor for types with proper typehints:
      services:
          - factory: PHPStan\Type\Doctrine\Descriptors\ReflectionDescriptor('App\Type\CustomType')
            tags: [phpstan.doctrine.typeDescriptor]
      
  3. Literal Strings:

    • Enforce literal-string for SQL parameters to prevent SQL injection:
      parameters:
          doctrine:
              literalString: true
      
    • Avoid dynamic strings in Connection::executeQuery():
      // ❌ Risky
      $sql = "SELECT * FROM users WHERE email = '$userInput'";
      
      // ✅ Safe
      $sql = "SELECT * FROM users WHERE email = ?";
      
  4. Proxy Classes:

    • Direct use of Doctrine proxy class names (e.g., Proxy\__CG__\App\Entity\User) triggers warnings. Use interfaces or base classes instead.
  5. Final Classes/Constructors:

    • final entity classes/constructors may break proxy generation. Configure allowed cases:
      parameters:
          doctrine:
              allowFinalEntityClasses: true
              allowFinalConstructors: true
      
  6. Criteria Argument Fix:

    • New in 2.0.27: Previously, incorrect stubs for Criteria arguments could cause false positives. This release fixes issues with Criteria argument handling in repository methods. Ensure your custom repository methods using Criteria are now properly validated.

Debugging Tips

  • Type Inference Issues: Check objectManagerLoader returns a valid EntityManager.
  • Custom DQL Functions: Implement TypedExpression for accurate type inference.
  • Performance: Exclude slow analyses (e.g., DQL validation) in CI:
    levels:
        - 5
    parameters:
        doctrine:
            objectManagerLoader: null # Disable in CI
    

Extension Points

  1. Custom Rules: Extend DoctrineExtension to add project-specific validations.
  2. Stub Files: Override stubs in vendor/phpstan/phpstan-doctrine/stubs/ for legacy Doctrine versions.
  3. Configuration: Use parameters.doctrine to tweak behavior (e.g., allCollectionsSelectable for Collection::matching()).

Example Debugging Workflow

  1. Error: Call to undefined method App\Entity\UserRepository::customMethod().

    • Fix: Add ormRepositoryClass to phpstan.neon pointing to the base class with customMethod.
  2. Error: Type error: Return type of App\Type\CustomType::convertToPHPValue() must be string|int, mixed given.

    • Fix: Implement a DoctrineTypeDescriptor or use ReflectionDescriptor.
  3. False Positive: Unused property $createdAt (Gedmo field).

    • Fix: Ensure phpstan-doctrine is included after phpstan/extension-installer in includes.
  4. Criteria Argument Issues:

    • New in 2.0.27: If you previously encountered false positives with Criteria arguments (e.g., findBy() with custom Criteria objects), re-run PHPStan to validate the fix. If issues persist, ensure your Criteria class is properly type-hinted and annotated.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
babenkoivan/elastic-client
innmind/static-analysis
innmind/coding-standard
datacore/hub-sdk
alengo/sulu-http-cache-bundle
develia/commons
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony
develia/geo-bundle
dreamzy/livewire-charts
touchestate-sdk/php-sdk
22h/doctrine-garbage-collection-bundle
imbo/imbo-coding-standard
visualbuilder/filament-lottie
servicioslineaonce/starter-kit
atomcoder/laravel-reorderable
irajul/filament-shadcn-theme
agtp/agtp-php
agtp/mod-php
centraldesktop/protobuf-php