يوفر هذا الامتداد الميزات التالية:
findBy* و findOneBy* و countBy* على IttityRepository.findBy ، findBy* ، findOneBy ، findOneBy* ، count و countBy* Method Method.EntityRepository<MyEntity> بشكل صحيح في PHPDOCs لمزيد من الاستدلال على النوع للطرق المسمى في المستودع.DoctrineORMEntityManager::getRepository() .DoctrineORMEntityManager::find ، getReference و getPartialReference عندما يتم توفير اسم فئة الكيانات Foo::class كوسيطة أولىmatching المفقودة على DoctrineCommonCollectionsCollection . يمكن إيقاف تشغيل ذلك عن طريق تعيين parameters.doctrine.allCollectionsSelectable إلى false .allowNullablePropertyForRequiredField: true .DoctrineORMQuery::getResult ، getOneOrNullResult ، getSingleResult ، toIterable execute في وضع HYDRATE_OBJECT (انظر أدناه). لاستخدام هذا الامتداد ، اطلبه في الملحن:
composer require --dev phpstan/phpstan-doctrineإذا قمت أيضًا بتثبيت Phpstan/Extension-instholer ، فأنت جميعًا قد تم تعيينه!
إذا كنت لا ترغب في استخدام phpstan/extension-installer ، قم بتضمين extension.neon في تكوين Phpstan لمشروعك:
includes :
- vendor/phpstan/phpstan-doctrine/extension.neon إذا كنت مهتمًا بالتحقق من صحة DQL/QueryBuilder ، فقم أيضًا بتضمين rules.neon (ستحتاج أيضًا إلى توفير كائن objectManagerLoader ، انظر أدناه):
includes :
- vendor/phpstan/phpstan-doctrine/rules.neon إذا كان للمستودعات الخاصة بك فئة أساسية مشتركة ، فيمكنك تكوينها في phpstan.neon و phpstan ستشاهد طرقًا إضافية تحددها:
parameters :
doctrine :
ormRepositoryClass : MyAppDoctrineBetterEntityRepository
odmRepositoryClass : MyAppDoctrineBetterDocumentRepositoryيمكنك اختيار تحليل أكثر تقدمًا من خلال توفير مدير الكائن من التطبيق الخاص بك. سيمكن هذا من التحقق من صحة DQL:
parameters :
doctrine :
objectManagerLoader : tests/object-manager.phpمثال على 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 ();مثال على 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 (); يمكن أن يستنتج هذا الامتداد نوع النتيجة لاستعلامات DQL عند توفير objectManagerLoader .
أمثلة:
$ 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 Parser وبيانات تعريف الكيانات.
mixed دعم معظم ميزات DQL ، بما في ذلك GROUP BY ، INDEX BY ، DISTINCT ، جميع نكهات JOIN ، التعبيرات الحسابية ، وظائف ، تجمعات ، NEW ، إلخ.
ما إذا كان EG SUM(e.column) يتم جلبه على أنه float أو numeric-string أو int يعتمد بشكل كبير على برامج التشغيل ، وإعدادها وإصدار PHP. هذا الامتداد تلقائيًا الإعداد الخاص بك ويوفر نتائج دقيقة تمامًا لـ pdo_mysql و mysqli و pdo_sqlite و sqlite3 و pdo_pgsql و pgsql .
يتم دعم طريقة getResult عند استدعاء بدون وسيطة ، أو مع تعيين وسيطة hydratemode على Query::HYDRATE_OBJECT :
$ query = $ entityManager -> createQuery ( ' SELECT u FROM AcmeUser u ' );
$ query -> getResult (); // array<User>
$ query -> getResult (Query:: HYDRATE_OBJECT ); // array<User> يتم دعم الأساليب getOneOrNullResult و getSingleResult و toIterable و execute عندما يتم تعيين وسيطة Hydratemode بشكل صريح على Query::HYDRATE_OBJECT :
$ query = $ entityManager -> createQuery ( ' SELECT u FROM AcmeUser u ' );
$ query -> getOneOrNullResult (); // mixed
$ query -> getOneOrNullResult (Query:: HYDRATE_OBJECT ); // User ويرجع ذلك إلى تصميم فئة Query التي تمنع من تحديد وضع الترطيب المستخدمة في هذه الوظائف ما لم يتم تحديده بشكل صريح أثناء المكالمة.
لا يمكن تحليل كل QueryBuilder بشكل ثابت ، فيما يلي بعض النصائح لزيادة الاستنتاج من النوع إلى الحد الأقصى:
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 الذي يمكن كتابته من حقل خاصية الكيان إلى النوع المخصص. مرة أخرى ، هو في الأساس هو النوع المسموح به للوسيطة الأولى لـ Custom Type من النوع convertToDatabaseValue() . بشكل عام ، على الأقل بالنسبة لمعظم الأنواع الأصلية للعقيدة ، ستعيد هاتان الطريقتان الأخيرتان نفس النوع ، ولكن هذا ليس هو الحال دائمًا. أحد الأمثلة على ذلك هو نوع datetime ، والذي يسمح لك بتعيين أي DateTimeInterface إلى حقل الخاصية ، ولكن سيحتوي دائمًا على نوع DateTime عند تحميله من قاعدة البيانات.
لا يتعين على واصفات الكتابة التعامل مع الأنواع الباطلة ، حيث يتم إضافتها/إزالتها بشفافية من أنواع الواصف حسب الحاجة. لذلك ، ليس عليك إرجاع نوع الاتحاد من نوعك المخصص و NullType من أساليب الواصف ، حتى لو كان نوعك المخصص يسمح null .
إذا كانت convertToPHPValue() من النوع المخصص الخاص بك () وطرق convertToDatabaseValue() لها أنواع مناسبة ، فلا يتعين عليك كتابة واصفك الخاص. يمكن لـ PHPStanTypeDoctrineDescriptorsReflectionDescriptor تحليل الأنواع والقيام بالباقي لك.
إذا كان الوالد من النوع الخاص بك هو أحد المبدأ غير المذهل ، فسيقوم 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 ; يتم فهم أي وظيفة DQL مخصصة تنفذ TypedExpression العقيدة من خلال هذا الامتداد ويتم استنتاجها مع النوع المستخدم في طريقة 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 .
مثال حيث يتم استخدام هذا النوع هو $sql المعلمة في DoctrineDbalConnection::executeQuery() .
لتمكين هذا النوع المتقدم في phpstan-doctrine ، استخدم معلمة التكوين هذه:
parameters :
doctrine :
literalString : true