Ekstensi ini memberikan fitur berikut:
findBy* , findOneBy* dan countBy* Metode pada EntityRepository.findBy , findBy* , findOneBy , findOneBy* , count dan countBy* metode panggilan.EntityRepository<MyEntity> Dengan benar di PHPDOCS untuk inferensi jenis lebih lanjut dari metode yang disebut repositori.DoctrineORMEntityManager::getRepository() .DoctrineORMEntityManager::find , getReference dan getPartialReference saat Foo::class disediakan sebagai argumen pertamamatching yang hilang pada DoctrineCommonCollectionsCollection . Ini dapat dimatikan dengan mengatur parameters.doctrine.allCollectionsSelectable to false .allowNullablePropertyForRequiredField: true .DoctrineORMQuery::getResult , getOneOrNullResult , getSingleResult , toIterable dan execute dalam mode HYDRATE_OBJECT (lihat di bawah). Untuk menggunakan ekstensi ini, memerlukannya di komposer:
composer require --dev phpstan/phpstan-doctrineJika Anda juga menginstal phpstan/extension-installer maka Anda sudah siap!
Jika Anda tidak ingin menggunakan phpstan/extension-installer , sertakan extension.neon dalam konfigurasi phpstan proyek Anda:
includes :
- vendor/phpstan/phpstan-doctrine/extension.neon Jika Anda tertarik objectManagerLoader validasi DQL/QueryBuilder, sertakan juga rules.neon .
includes :
- vendor/phpstan/phpstan-doctrine/rules.neon Jika repositori Anda memiliki kelas dasar yang umum, Anda dapat mengonfigurasinya di phpstan.neon dan phpstan Anda akan melihat metode tambahan yang Anda tentukan di dalamnya:
parameters :
doctrine :
ormRepositoryClass : MyAppDoctrineBetterEntityRepository
odmRepositoryClass : MyAppDoctrineBetterDocumentRepositoryAnda dapat memilih untuk analisis yang lebih lanjut dengan memberikan manajer objek dari aplikasi Anda sendiri. Ini akan memungkinkan validasi DQL:
parameters :
doctrine :
objectManagerLoader : tests/object-manager.phpContoh untuk 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 ();Contoh untuk 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 (); Ekstensi ini dapat menyimpulkan jenis hasil kueri DQL ketika objectManagerLoader disediakan.
Contoh:
$ 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>Kueri dianalisis secara statis dan tidak memerlukan server database yang sedang berjalan. Ini memanfaatkan doktrin parser DQL dan entitas metadata.
Sebagian besar fitur DQL didukung, termasuk GROUP BY , INDEX BY , DISTINCT , semua rasa JOIN , ekspresi aritmatika, fungsi, agregasi, NEW , dll. Sub kueri belum didukung (jenis yang disimpulkan akan mixed ).
Apakah misalnya SUM(e.column) diambil sebagai float , numeric-string atau int sangat tergantung pada driver, pengaturan mereka dan versi PHP. Ekstensi ini secara otomatis mengatur pengaturan Anda dan memberikan hasil yang cukup akurat untuk pdo_mysql , mysqli , pdo_sqlite , sqlite3 , pdo_pgsql dan pgsql .
Metode getResult didukung ketika dipanggil tanpa argumen, atau dengan argumen hydratemode yang diatur ke Query::HYDRATE_OBJECT :
$ query = $ entityManager -> createQuery ( ' SELECT u FROM AcmeUser u ' );
$ query -> getResult (); // array<User>
$ query -> getResult (Query:: HYDRATE_OBJECT ); // array<User> Metode getOneOrNullResult , getSingleResult , toIterable , dan execute didukung ketika argumen hydratemode secara eksplisit diatur ke Query::HYDRATE_OBJECT :
$ query = $ entityManager -> createQuery ( ' SELECT u FROM AcmeUser u ' );
$ query -> getOneOrNullResult (); // mixed
$ query -> getOneOrNullResult (Query:: HYDRATE_OBJECT ); // User Hal ini disebabkan oleh desain kelas Query yang mencegah menentukan mode hidrasi yang digunakan oleh fungsi -fungsi ini kecuali jika ditentukan secara eksplisit selama panggilan.
Tidak setiap querybuilder dapat dianalisis secara statis, berikut adalah beberapa saran untuk memaksimalkan jenis menyimpulkan:
select / join / from / set )Anda dapat mengaktifkan pelaporan tempat -tempat di mana menyimpulkan tidak tersedia oleh:
parameters :
doctrine :
reportDynamicQueryBuilders : true Jika aplikasi Anda menggunakan jenis doktrin khusus, Anda dapat menulis deskriptor tipe Anda sendiri untuk menganalisisnya dengan benar. Ketik deskriptor mengimplementasikan antarmuka PHPStanTypeDoctrineDescriptorsDoctrineTypeDescriptor yang terlihat seperti ini:
<?php
public function getType(): string ;
public function getWritableToPropertyType(): Type ;
public function getWritableToDatabaseType(): Type ;getType() hanya mengembalikan nama kelas jenis kustom.getWritableToPropertyType() mengembalikan tipe phpstan yang tipe kustom akan menulis ke bidang properti entitas. Pada dasarnya itu adalah tipe pengembalian metode convertToPHPValue() tipe kustom.getWritableToDatabaseType() mengembalikan tipe phpstan yang dapat ditulis dari bidang properti entitas ke dalam jenis kustom. Sekali lagi, pada dasarnya itu adalah tipe yang diizinkan untuk argumen pertama convertToDatabaseValue() tipe khusus. Secara umum, setidaknya untuk sebagian besar tipe asli Doktrin, dua metode terakhir ini akan mengembalikan tipe yang sama, tetapi tidak selalu terjadi. Salah satu contohnya adalah tipe datetime , yang memungkinkan Anda untuk mengatur DateTimeInterface ke bidang properti, tetapi akan selalu berisi tipe DateTime saat dimuat dari database.
Ketik deskriptor tidak harus berurusan dengan tipe yang dapat dibatalkan, karena ini ditambahkan/dihapus secara transparan dari jenis deskriptor sesuai kebutuhan. Oleh karena itu Anda tidak perlu mengembalikan jenis serikat jenis kustom dan NullType dari metode deskriptor, bahkan jika jenis kustom Anda memungkinkan null .
Jika metode convertToPHPValue() dan convertToDatabaseValue() Anda memiliki cints tipe yang tepat, Anda tidak perlu menulis deskriptor Anda sendiri untuk itu. PHPStanTypeDoctrineDescriptorsReflectionDescriptor dapat menganalisis tipeHints dan melakukan sisanya untuk Anda.
Jika orang tua dari tipe Anda adalah salah satu yang tidak berabat doktrin, ReflectionDescriptor akan menggunakan kembali deskriptornya bahkan untuk resolusi ekspresi (misalnya AVG(t.cost) ). Misalnya, jika Anda memperluas DoctrineDBALTypesDecimalType , ia akan tahu bahwa sqlite mengambil bahwa sebagai float|int dan driver lainnya sebagai numeric-string . Jika Anda hanya memperluas DoctrineDBALTypesType , Anda harus menggunakan deskriptor khusus dan secara opsional mengimplementasikan bahkan DoctrineTypeDriverAwareDescriptor untuk memberikan resolusi khusus driver.
Saat Anda menulis deskriptor tipe khusus, Anda harus memberi tahu Phpstan tentang hal itu. Tambahkan sesuatu seperti ini ke phpstan.neon Anda.
services :
-
class : MyCustomTypeDescriptor
tags : [ phpstan.doctrine.typeDescriptor ]
# in case you are using the ReflectionDescriptor
-
factory : PHPStanTypeDoctrineDescriptorsReflectionDescriptor ( ' MyAppMyCustomTypeName ' )
tags : [ phpstan.doctrine.typeDescriptor ]Jika Anda ingin memastikan bahwa Anda tidak pernah melupakan deskriptor untuk beberapa jenis khusus, Anda dapat mengaktifkan:
parameters :
doctrine :
reportUnknownTypes : trueIni menyebabkan kegagalan ketika entitas Anda menggunakan tipe kustom tanpa deskriptor:
#[Entity]
abstract class Uuid7Entity
{
#[Id]
#[Column(type: Uuid7Type:: NAME )] // reported when descriptor for such type is missing
private Uuid7 $ hsCode ; Setiap fungsi DQL khusus yang mengimplementasikan TypedExpression Doctrine dipahami oleh ekstensi ini dan disimpulkan dengan jenis yang digunakan dalam metode getReturnType() . Semua fungsi DQL khusus lainnya disimpulkan sebagai mixed . Harap dicatat bahwa Anda tidak dapat menggunakan StringType asli untuk mencetak (dan menyimpulkan) hasil string (lihat edisi 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 );
}
} File rintisan dalam phpstan-doctrine hadir dengan banyak parameter yang ditandai dengan literal-string . Ini adalah tipe yang berfokus pada keamanan yang hanya memungkinkan string literal yang ditulis dalam kode untuk diteruskan ke dalam parameter ini.
Ini mengurangi risiko injeksi SQL karena string dinamis dari input pengguna tidak diterima sebagai pengganti literal-string .
Contoh di mana jenis ini digunakan adalah parameter $sql di DoctrineDbalConnection::executeQuery() .
Untuk mengaktifkan tipe canggih ini dalam phpstan-doctrine, gunakan parameter konfigurasi ini:
parameters :
doctrine :
literalString : true