該擴展名提供以下功能:
findBy* , findOneBy*和countBy*方法。findBy findBy* , findOneBy , findOneBy* , count countBy*方法調用。EntityRepository<MyEntity>以進一步推斷存儲庫中調用的方法。DoctrineORMEntityManager::getRepository()提供了正確的回報。DoctrineORMEntityManager::find , getReference和getPartialReference當Foo::class entity class名稱作為第一個參數時DoctrineCommonCollectionsCollection上添加了缺少matching方法。可以通過設置parameters.doctrine.allCollectionsSelectable將其false 。allowNullablePropertyForRequiredField: true設置來放鬆這一點。DoctrineORMQuery::getResult , getOneOrNullResult ,getingleresult, getSingleResult , toIterable和在HYDRATE_OBJECT模式下execute返回類型(請參見下文)。 要使用此擴展名,請在作曲家中需要它:
composer require --dev phpstan/phpstan-doctrine如果您還安裝了phpstan/Extension-installer,那麼您將全部設置!
如果您不想使用phpstan/extension-installer ,請在項目的PHPSTAN配置中包含Extension.Neon:
includes :
- vendor/phpstan/phpstan-doctrine/extension.neon objectManagerLoader您對DQL/QueryBuilder驗證感興趣,請還包括rules.neon 。
includes :
- vendor/phpstan/phpstan-doctrine/rules.neon 如果您的存儲庫有一個公共基類,則可以在phpstan.neon和Phpstan將看到您在其中定義的其他方法:
parameters :
doctrine :
ormRepositoryClass : MyAppDoctrineBetterEntityRepository
odmRepositoryClass : MyAppDoctrineBetterDocumentRepository您可以通過從您自己的應用程序提供對像管理器來選擇更高級的分析。這將啟用DQL驗證:
parameters :
doctrine :
objectManagerLoader : tests/object-manager.phpSymfony 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 ();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 ();當提供objectManagerLoader時,該擴展可以推斷DQL查詢的結果類型。
示例:
$ 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>查詢在靜態分析,不需要運行的數據庫服務器。這利用了DQL解析器和實體元數據。
支持大多數DQL特徵,包括GROUP BY , INDEX BY ,不同JOIN DISTINCT算術表達式mixed函數,聚合, NEW等。
EG SUM(e.column)是以float而獲取, numeric-string還是int高度取決於驅動程序,其設置和PHP版本。此擴展可以自動檢測您的設置,並為pdo_mysql , mysqli , pdo_sqlite , sqlite3 , pdo_pgsql和pgsql提供了非常準確的結果。
當無參數調用時,支持getResult方法,或將設置為Query::HYDRATE_OBJECT :
$ query = $ entityManager -> createQuery ( ' SELECT u FROM AcmeUser u ' );
$ query -> getResult (); // array<User>
$ query -> getResult (Query:: HYDRATE_OBJECT ); // array<User>當hydrateMode參數明確toIterable getSingleResult Query::HYDRATE_OBJECT getOneOrNullResult hydrate_object execute
$ query = $ entityManager -> createQuery ( ' SELECT u FROM AcmeUser u ' );
$ query -> getOneOrNullResult (); // mixed
$ query -> getOneOrNullResult (Query:: HYDRATE_OBJECT ); // User這是由於Query類的設計,除非在呼叫過程中明確指定這些功能,否則無法確定這些功能使用的水合模式。
並非每個查詢構造器都可以靜態分析,以下是最大化類型推斷的建議:
select / join / from / set中)您可以通過以下方式報告不可用的地方。
parameters :
doctrine :
reportDynamicQueryBuilders : true 如果您的應用程序使用自定義類型,則可以編寫自己的類型描述符以正確分析它們。類型描述符實現接口PHPStanTypeDoctrineDescriptorsDoctrineTypeDescriptor該詞看起來像這樣:
<?php
public function getType(): string ;
public function getWritableToPropertyType(): Type ;
public function getWritableToDatabaseType(): Type ;getType()方法只需返回自定義類型的類名。getWritableToPropertyType()方法返回自定義類型將寫入實體屬性字段的phpstan類型。基本上,這是自定義類型的convertToPHPValue()方法的返回類型。getWritableToDatabaseType()方法將可以從實體的屬性字段寫入自定義類型的PHPSTAN類型。同樣,基本上,這是自定義類型的convertToDatabaseValue()的第一個參數的允許類型。通常,至少對於大多數學說的本地類型,這些最後兩種方法將返回相同的類型,但並非總是如此。一個示例是datetime類型,它允許您將任何DateTimeInterface設置為屬性字段,但是從數據庫加載時始終包含DateTime類型。
類型的描述符不必處理無效的類型,因為根據需要,這些類型可以從描述符類型中透明/刪除。因此,即使您的自定義類型允許null ,您也不必從描述符的方法返回自定義類型的聯合類型和NullType 。
如果您的自定義類型的convertToPHPValue()和convertToDatabaseValue()方法具有適當的typeHints,則不必為此編寫自己的描述符。 PHPStanTypeDoctrineDescriptorsReflectionDescriptor可以分析typehints並為您完成其餘部分。
如果您的類型的父級是該學說的非提取者之一,那麼ReflectionDescriptor即使將其描述符重複使用以表達式解決方案(例如AVG(t.cost) )。例如,如果您擴展了DoctrineDBALTypesDecimalType ,它將知道SQLite將其作為float|int和其他驅動程序作為numeric-string 。如果僅擴展了DoctrineDBALTypesType ,則應使用自定義描述符,並選擇實現DoctrineTypeDriverAwareDescriptor以提供特定於驅動程序的分辨率。
當您編寫自定義類型描述符時,您必須讓Phpstan知道。將類似的東西添加到您的phpstan.neon中:
services :
-
class : MyCustomTypeDescriptor
tags : [ phpstan.doctrine.typeDescriptor ]
# in case you are using the ReflectionDescriptor
-
factory : PHPStanTypeDoctrineDescriptorsReflectionDescriptor ( ' MyAppMyCustomTypeName ' )
tags : [ phpstan.doctrine.typeDescriptor ]如果您想確保永遠不會忘記某種自定義類型的描述符,則可以啟用:
parameters :
doctrine :
reportUnknownTypes : true當您的實體使用無描述符的自定義類型時,這會導致失敗:
#[Entity]
abstract class Uuid7Entity
{
#[Id]
#[Column(type: Uuid7Type:: NAME )] // reported when descriptor for such type is missing
private Uuid7 $ hsCode ;實現學說的TypedExpression表達的任何自定義DQL函數都可以通過此擴展來理解,並使用其getReturnType()方法中使用的類型來推斷。所有其他自定義DQL功能都被推斷為mixed 。請注意,您不能使用本機StringType來鑄造(和推斷)字符串結果(請參見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 );
}
}phpstan-doctrine中的存根文件帶有許多參數,上面標有literal-string 。這是一種以安全性為中心的類型,僅允許用代碼編寫的文字字符串傳遞到這些參數中。
這降低了SQL注入的風險,因為從用戶輸入的動態字符串不被代替literal-string 。
使用此類型的一個示例是DoctrineDbalConnection::executeQuery()中的$sql參數。
要啟用Phpstan-Doctrine中的高級類型,請使用此配置參數:
parameters :
doctrine :
literalString : true