Esta extensión proporciona las siguientes características:
findBy* , findOneBy* y countBy* en EntityRepository.findBy , findBy* , findOneBy , findOneBy* , count y countBy* llamadas del método.EntityRepository<MyEntity> correctamente en PHPDOCS para una inferencia de tipo adicional de métodos llamados en el repositorio.DoctrineORMEntityManager::getRepository() .DoctrineORMEntityManager::find , getReference y getPartialReference cuando el nombre de clase de la entidad Foo::class se proporciona como el primer argumentomatching faltante en DoctrineCommonCollectionsCollection . Esto se puede desactivar configurando parameters.doctrine.allCollectionsSelectable a false .allowNullablePropertyForRequiredField: true .DoctrineORMQuery::getResult , getOneOrNullResult , getSingleResult , toIterable y execute en modo HYDRATE_OBJECT (ver más abajo). Para usar esta extensión, requiere en compositor:
composer require --dev phpstan/phpstan-doctrineSi también instala PHPSTAN/Extension-Installer, ¡está listo!
Si no desea utilizar phpstan/extension-installer , incluya Extension.neon en la configuración PHPSTAN de su proyecto:
includes :
- vendor/phpstan/phpstan-doctrine/extension.neon Si está interesado en la validación de DQL/QueryBuilder, incluya también rules.neon (también necesitará proporcionar el objectManagerLoader , ver más abajo):
includes :
- vendor/phpstan/phpstan-doctrine/rules.neon Si sus repositorios tienen una clase base común, puede configurarla en su phpstan.neon y Phpstan verán métodos adicionales que defina:
parameters :
doctrine :
ormRepositoryClass : MyAppDoctrineBetterEntityRepository
odmRepositoryClass : MyAppDoctrineBetterDocumentRepositoryPuede optar por un análisis más avanzado proporcionando al Administrador de objetos desde su propia aplicación. Esto habilitará la validación de DQL:
parameters :
doctrine :
objectManagerLoader : tests/object-manager.phpEjemplo de Symfony 4:
// tests/object-manager.php
use App Kernel ;
require __DIR__ . ' /../config/bootstrap.php ' ;
$ kernel = new Kernel ( $ _SERVER [ ' APP_ENV ' ], ( bool ) $ _SERVER [ ' APP_DEBUG ' ]);
$ kernel -> boot ();
return $ kernel -> getContainer ()-> get ( ' doctrine ' )-> getManager ();Ejemplo de Symfony 5:
// tests/object-manager.php
use App Kernel ;
use Symfony Component Dotenv Dotenv ;
require __DIR__ . ' /../vendor/autoload.php ' ;
( new Dotenv ())-> bootEnv ( __DIR__ . ' /../.env ' );
$ kernel = new Kernel ( $ _SERVER [ ' APP_ENV ' ], ( bool ) $ _SERVER [ ' APP_DEBUG ' ]);
$ kernel -> boot ();
return $ kernel -> getContainer ()-> get ( ' doctrine ' )-> getManager (); Esta extensión puede inferir el tipo de resultado de consultas DQL cuando se proporciona un objectManagerLoader .
Ejemplos:
$ query = $ entityManager -> createQuery ( ' SELECT u FROM AcmeUser u ' );
$ query -> getResult (); // array<AcmeUser>
$ query = $ entityManager -> createQuery ( ' SELECT u.id, u.email, u.name FROM AcmeUser u ' );
$ query -> getResult (); // array<array{id: int, email: string, name: string|null}>
$ query = $ entityManager -> createQuery ( '
SELECT u.id, u.email, COALESCE(u.name, "Anonymous") AS name
FROM AcmeUser u
' );
$ query -> getSingleResult (Query:: HYDRATE_OBJECT ); // array{id: int, email: string, name: string}>
$ query = $ entityManager -> createQueryBuilder ()
-> select ( ' u ' )
-> from (User::class, ' u ' )
-> getQuery ();
$ query -> getResult (); // array<AcmeUser>Las consultas se analizan estáticamente y no requieren un servidor de base de datos en ejecución. Esto hace uso de los metadatos de la doctrina DQL y las entidades.
La mayoría de las características de DQL son compatibles, incluidos GROUP BY , INDEX BY , DISTINCT , todos los sabores de JOIN , expresiones aritméticas, funciones, agregaciones, NEW , etc. Las subconscientes aún no se admiten (el tipo inferido se mixed ).
Si SUM(e.column) se obtiene como float , numeric-string o int altamente depende de los controladores, su configuración y la versión PHP. Esta extensión automáticamente su configuración y proporciona resultados bastante precisos para pdo_mysql , mysqli , pdo_sqlite , sqlite3 , pdo_pgsql y pgsql .
El método getResult se admite cuando se llama sin argumento, o con el argumento Hydratemode establecido en Query::HYDRATE_OBJECT :
$ query = $ entityManager -> createQuery ( ' SELECT u FROM AcmeUser u ' );
$ query -> getResult (); // array<User>
$ query -> getResult (Query:: HYDRATE_OBJECT ); // array<User> Los métodos getOneOrNullResult , getSingleResult , toIterable y execute son compatibles cuando el argumento Hydratemode se establece explícitamente para Query::HYDRATE_OBJECT :
$ query = $ entityManager -> createQuery ( ' SELECT u FROM AcmeUser u ' );
$ query -> getOneOrNullResult (); // mixed
$ query -> getOneOrNullResult (Query:: HYDRATE_OBJECT ); // User Esto se debe al diseño de la clase Query que evita determinar el modo de hidratación utilizado por estas funciones a menos que se especifique explícitamente durante la llamada.
No todos los consultores pueden analizarse estáticamente, aquí hay pocos consejos para maximizar la infección de tipo:
select / join / from / set )Puede habilitar informes de lugares donde la infección no está disponible por:
parameters :
doctrine :
reportDynamicQueryBuilders : true Si su aplicación utiliza tipos de doctrina personalizados, puede escribir su propio tipo de descriptores para analizarlos correctamente. Tipo descriptores Implemente la interfaz PHPStanTypeDoctrineDescriptorsDoctrineTypeDescriptor que se ve así:
<?php
public function getType(): string ;
public function getWritableToPropertyType(): Type ;
public function getWritableToDatabaseType(): Type ;getType() simplemente devuelve el nombre de clase del tipo personalizado.getWritableToPropertyType() devuelve el tipo PHPSTAN que el tipo personalizado escribirá en el campo de propiedad de la entidad. Básicamente es el tipo de retorno del método convertToPHPValue() del tipo personalizado.getWritableToDatabaseType() devuelve el tipo PhpStan que se puede escribir desde el campo de propiedad de la entidad al tipo personalizado. Una vez más, básicamente es el tipo permitido para el primer argumento convertToDatabaseValue() del tipo personalizado. En general, al menos para la mayoría de los tipos nativos de doctrina, estos dos últimos métodos devolverán el mismo tipo, pero no siempre es el caso. Un ejemplo sería el tipo datetime , que le permite establecer cualquier DateTimeInterface en el campo de propiedades, pero siempre contendrá el tipo DateTime cuando se carga desde la base de datos.
Los descriptores de tipo no tienen que lidiar con tipos anulables, ya que estos se agregan/eliminan transparentemente de los tipos del descriptor según sea necesario. Por lo tanto, no tiene que devolver el tipo de sindicato de su tipo personalizado y NullType de los métodos del descriptor, incluso si su tipo personalizado permite que null .
Si los métodos convertToPHPValue() y convertToDatabaseValue() de su tipo personalizado tienen los tipos de tipo adecuados, no tiene que escribir su propio descriptor para ello. El PHPStanTypeDoctrineDescriptorsReflectionDescriptor puede analizar los typehints y hacer el resto por usted.
Si el padre de su tipo es uno de los no abstractos de la doctrina, ReflectionDescriptor reutilizará su descriptor incluso para la resolución de expresión (por ejemplo, AVG(t.cost) ). Por ejemplo, si extiende DoctrineDBALTypesDecimalType , sabrá que Sqlite obtiene eso como float|int y otros controladores como numeric-string . Si solo extiende DoctrineDBALTypesType , debe usar un descriptor personalizado y opcionalmente implementar incluso DoctrineTypeDriverAwareDescriptor para proporcionar una resolución específica del controlador.
Cuando escribe un descriptor de tipo personalizado, debe informar a Phpstan al respecto. Agregue algo como esto a su phpstan.neon :
services :
-
class : MyCustomTypeDescriptor
tags : [ phpstan.doctrine.typeDescriptor ]
# in case you are using the ReflectionDescriptor
-
factory : PHPStanTypeDoctrineDescriptorsReflectionDescriptor ( ' MyAppMyCustomTypeName ' )
tags : [ phpstan.doctrine.typeDescriptor ]Si desea asegurarse de que nunca olvide el descriptor para algún tipo personalizado, puede habilitar:
parameters :
doctrine :
reportUnknownTypes : trueEsto causa fallas cuando su entidad usa el tipo personalizado sin descriptor:
#[Entity]
abstract class Uuid7Entity
{
#[Id]
#[Column(type: Uuid7Type:: NAME )] // reported when descriptor for such type is missing
private Uuid7 $ hsCode ; Esta extensión comprende cualquier función DQL personalizada que implementa TypedExpression de doctrina y se infiere con el tipo utilizado en su método getReturnType() . Todas las demás funciones DQL personalizadas se infieren como mixed . Tenga en cuenta que no puede usar StringType nativo para emitir (e inferir) los resultados de la cadena (consulte el problema de ORM).
use Doctrine DBAL Types Type ;
use Doctrine DBAL Types Types ;
use Doctrine ORM Query AST TypedExpression ;
use Doctrine ORM Query AST Functions FunctionNode ;
use Doctrine ORM Query Parser ;
use Doctrine ORM Query SqlWalker ;
use Doctrine ORM Query TokenType ;
class Floor extends FunctionNode implements TypedExpression
{
private AST Node | string $ arithmeticExpression ;
public function getSql ( SqlWalker $ sqlWalker ): string
{
return ' FLOOR( ' . $ sqlWalker -> walkSimpleArithmeticExpression ( $ this -> arithmeticExpression ) . ' ) ' ;
}
public function parse ( Parser $ parser ): void
{
$ parser -> match (TokenType:: T_IDENTIFIER );
$ parser -> match (TokenType:: T_OPEN_PARENTHESIS );
$ this -> arithmeticExpression = $ parser -> SimpleArithmeticExpression ();
$ parser -> match (TokenType:: T_CLOSE_PARENTHESIS );
}
public function getReturnType (): Type
{
return Type:: getType (Types:: INTEGER );
}
} Los archivos Stub en Phpstan-Doctrine vienen con muchos parámetros marcados con literal-string . Este es un tipo centrado en la seguridad que solo permite que las cadenas literales escritas en el código se pasen a estos parámetros.
Esto reduce el riesgo de inyección SQL porque las cadenas dinámicas de la entrada del usuario no se aceptan en lugar de literal-string .
Un ejemplo en el que se usa este tipo es un parámetro $sql en DoctrineDbalConnection::executeQuery() .
Para habilitar este tipo avanzado en phpstan-doctrine, use este parámetro de configuración:
parameters :
doctrine :
literalString : true