ส่วนขยายนี้มีคุณสมบัติต่อไปนี้:
findBy* , findOneBy* และ countBy* วิธีการใน EntityRepositoryfindBy , findBy* , findOneBy , findOneBy* , count และ countBy* การโทรEntityRepository<MyEntity> อย่างถูกต้องใน PHPDOCs สำหรับการอนุมานประเภทต่อไปของวิธีการที่เรียกว่าที่เก็บDoctrineORMEntityManager::getRepository()DoctrineORMEntityManager::find , getReference และ getPartialReference เมื่อชื่อคลาสเอนทิตี Foo::class เป็นอาร์กิวเมนต์แรกmatching ที่ขาดหายไปใน DoctrineCommonCollectionsCollection สิ่งนี้สามารถปิดได้โดยการตั้งค่า parameters.doctrine.allCollectionsSelectable เป็น falseallowNullablePropertyForRequiredField: trueDoctrineORMQuery::getResult , getOneOrNullResult , getSingleResult , toIterable และ execute ในโหมด HYDRATE_OBJECT (ดูด้านล่าง) ในการใช้ส่วนขยายนี้ต้องใช้ในนักแต่งเพลง:
composer require --dev phpstan/phpstan-doctrineหากคุณติดตั้ง PHPSTAN/EXTENSION-INSTALLER คุณก็พร้อมแล้ว!
หากคุณไม่ต้องการใช้ phpstan/extension-installer ให้รวมส่วนขยาย 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 หลักคำสอนและเมตาดาต้าเอนทิตี
คุณสมบัติ DQL ส่วนใหญ่ได้รับการสนับสนุนรวมถึง GROUP BY INDEX BY DISTINCT รสชาติทั้งหมดของ JOIN นิพจน์เลขคณิตฟังก์ชั่นการรวม NEW ฯลฯ การสืบค้นย่อยยังไม่ได้รับการสนับสนุน (ประเภทที่อนุมานจะ mixed )
ไม่ว่าจะเป็นผล 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 หากแอปพลิเคชันของคุณใช้ประเภทหลักคำสอนที่กำหนดเองคุณสามารถเขียนคำอธิบายประเภทของคุณเองเพื่อวิเคราะห์ได้อย่างถูกต้อง พิมพ์ descriptors ใช้อินเตอร์เฟส PHPStanTypeDoctrineDescriptorsDoctrineTypeDescriptor ซึ่งมีลักษณะเช่นนี้:
<?php
public function getType(): string ;
public function getWritableToPropertyType(): Type ;
public function getWritableToDatabaseType(): Type ;getType() เพียงส่งคืนชื่อคลาสของประเภทที่กำหนดเองgetWritableToPropertyType() ส่งคืนประเภท phpstan ที่ประเภทที่กำหนดเองจะเขียนลงในฟิลด์คุณสมบัติของเอนทิตี โดยพื้นฐานแล้วมันเป็นประเภทการส่งคืนของวิธี convertToPHPValue() ประเภทที่กำหนดเองgetWritableToDatabaseType() ส่งคืนประเภท phpstan ที่สามารถเขียนได้จากฟิลด์คุณสมบัติของเอนทิตีลงในประเภทที่กำหนดเอง อีกครั้งโดยทั่วไปเป็นประเภทที่อนุญาตสำหรับอาร์กิวเมนต์แรกของ convertToDatabaseValue() โดยทั่วไปอย่างน้อยสำหรับประเภทดั้งเดิมของหลักคำสอนส่วนใหญ่สองวิธีสุดท้ายเหล่านี้จะส่งคืนประเภทเดียวกัน แต่ก็ไม่ได้เป็นเช่นนั้นเสมอไป ตัวอย่างหนึ่งคือประเภท datetime ซึ่งช่วยให้คุณสามารถตั้งค่า DateTimeInterface ใด ๆ เป็นฟิลด์คุณสมบัติ แต่จะมีประเภท DateTime เสมอเมื่อโหลดจากฐานข้อมูล
Type descriptors ไม่จำเป็นต้องจัดการกับประเภทที่ไม่มีค่าใช้จ่ายเนื่องจากสิ่งเหล่านี้จะถูกเพิ่ม/ลบออกจากประเภทของตัวอธิบายอย่างโปร่งใสตามต้องการ ดังนั้นคุณไม่จำเป็นต้องส่งคืนประเภทสหภาพของประเภทที่กำหนดเองและ NullType จากวิธีการของ descriptor แม้ว่าประเภทที่กำหนดเองของคุณจะอนุญาตให้ null
หาก convertToPHPValue() และวิธีการ convertToDatabaseValue() ของคุณมีวิธีการพิมพ์ที่เหมาะสมคุณไม่จำเป็นต้องเขียนคำอธิบายของคุณเอง PHPStanTypeDoctrineDescriptorsReflectionDescriptor สามารถวิเคราะห์ตัวพิมพ์ใหญ่และทำส่วนที่เหลือให้คุณ
หากผู้ปกครองของประเภทของคุณเป็นหนึ่งในคนที่ไม่ใช่ของหลักคำสอน ReflectionDescriptor จะนำคำอธิบายซ้ำกลับมาใช้ซ้ำแม้กระทั่งความละเอียดของนิพจน์ (เช่น AVG(t.cost) ) ตัวอย่างเช่นหากคุณขยาย DoctrineDBALTypesDecimalType มันจะรู้ว่า sqlite ดึงข้อมูลที่เป็น float|int และไดรเวอร์อื่น ๆ เป็น numeric-string หากคุณขยายเฉพาะ DoctrineDBALTypesType คุณควรใช้ descriptor ที่กำหนดเองและเลือกใช้แม้กระทั่ง 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 ]หากคุณต้องการให้แน่ใจว่าคุณไม่เคยลืม descriptor สำหรับประเภทที่กำหนดเองบางอย่างคุณสามารถเปิดใช้งาน:
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 ของ Doctrine นั้นเป็นที่เข้าใจกันโดยส่วนขยายนี้และอนุมานกับประเภทที่ใช้ในวิธี 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 );
}
} ไฟล์ Stub ใน phpstan-doctrine มาพร้อมกับพารามิเตอร์จำนวนมากที่ทำเครื่องหมายด้วย literal-string นี่เป็นประเภทที่เน้นความปลอดภัยซึ่งอนุญาตเฉพาะสตริงตัวอักษรที่เขียนในรหัสที่จะส่งผ่านไปยังพารามิเตอร์เหล่านี้
สิ่งนี้จะช่วยลดความเสี่ยงของการฉีด SQL เนื่องจากสตริงแบบไดนามิกจากการป้อนข้อมูลผู้ใช้ไม่ได้รับการยอมรับแทน literal-string
ตัวอย่างที่ใช้ประเภทนี้คือพารามิเตอร์ $sql ใน DoctrineDbalConnection::executeQuery()
ในการเปิดใช้งานประเภทขั้นสูงนี้ใน phpstan-doctrine ให้ใช้พารามิเตอร์การกำหนดค่านี้:
parameters :
doctrine :
literalString : true