Biblioteca independiente de PHP para generar un patrón de construcción a partir de una clase.
Usando Composer en su proyecto o globalmente
composer require natitech/builder-generator
composer global require natitech/builder-generator
Puedes usar el binario para generar un constructor cerca de una clase:
/path/to/vendor/bin/generate-builder /path/to/class
O puedes usarlo dentro de otro script PHP:
Nati BuilderGenerator FileBuilderGenerator:: create ()-> generateFrom ( ' /path/to/class ' );
Esto generará una clase constructora aparte de la clase construida.
Ejemplo :
//From /path/to/MyClass.php file = the built class
class MyClass {
public int $ id ;
public string $ label ;
}
//This new file /path/to/MyClassBuilder.php will be generated = the builder class
class MyClassBuilder {
private int $ id ;
private string $ label ;
public function __construct ( Faker $ faker )
{
$ this -> id = $ faker -> number ();
$ this -> label = $ faker -> word ;
}
public function build (): MyClass
{
$ myClass = new MyClass ();
$ myClass -> id = $ this -> id ;
$ myClass -> label = $ this -> label ;
return $ myClass ;
}
//this will have to be generated by your IDE
public function withLabel ( string $ label ): self
{
$ this -> label = $ label ;
return $ this ;
}
}
//The ultimate goal is to use this in tests
/** @test */
public function canTestSomething ()
{
$ this -> assertEquals (
' test ' ,
$ this -> service -> something ( $ this -> myClass ()-> withLabel ( ' used in test ' )-> build ())
);
}
private function myClass (): MyClassBuilder
{
return new MyClassBuilder ( Faker Factory:: create ());
}
Es posible que la clase constructora necesite recibir actualizaciones sobre estilo de código, usos falsos, tipos inferidos, espacio de nombres, etc. Además, para evitar producir código no utilizado, no existen definidores para las propiedades del constructor. Su IDE debería poder solucionar todo eso fácilmente.
El generador intentará detectar tipos de propiedades (tipos de php, tipos de phpdoc, atributos de doctrina o anotaciones) e intentará detectar el método falso apropiado según el tipo y el nombre de las propiedades.
Puede utilizar la opción --faker para intentar establecer los valores más relevantes. En ese caso, Faker se utilizará como una dependencia de la clase constructora.
Hay muchas estrategias para construir una clase: propiedades públicas, definidor (fluido o no), constructor. A continuación se proporciona una breve explicación de cada estrategia, pero es posible que prefiera leer las pruebas unitarias para comprenderlas completamente.
De forma predeterminada, el generador intentará detectar la estrategia más utilizada dentro de la clase construida y la usará para toda la clase constructora. Si está utilizando definidores en todas las propiedades menos una, el generador usará definidores en las propiedades que lo admitan e ignorará la propiedad que no lo admita.
Pero también puedes pasar explícitamente una estrategia usando la opción '--strategy'.
Cuando las propiedades son públicas. Vea el ejemplo anterior.
Cuando las propiedades están protegidas/privadas y configuradas dentro del método __construct.
//Built class
class MyClass {
private int $ id ;
public function __construct ( int $ id , private string $ label )
{
$ this -> id = $ id ;
}
}
//Builder class
class MyClassBuilder {
private int $ id ;
private string $ label ;
public function __construct ( Faker $ faker )
{
$ this -> id = $ faker -> number ();
$ this -> label = $ faker -> word ;
}
public function build (): MyClass
{
return new MyClass (
$ this -> id ,
$ this -> label
);
}
}
Cuando las propiedades están protegidas/privadas pero se pueden configurar mediante configuradores públicos. Los armadores pueden tener fluidez o no.
//Built class
class MyClass {
protected int $ id ;
protected string $ label ;
public function setId ( int $ id )
{
$ this -> id = $ id ;
return $ this ;
}
public function setLabel ( string $ label )
{
$ this -> label = $ label ;
return $ this ;
}
}
//Builder class
class MyClassBuilder {
private int $ id ;
private string $ label ;
public function __construct ( Faker $ faker )
{
$ this -> id = $ faker -> number ();
$ this -> label = $ faker -> word ;
}
public function build (): MyClass
{
return ( new MyClass ())
-> setId ( $ this -> id )
-> setLabel ( $ this -> label );
}
}
Esta es una forma menos convencional de crear una clase. En ese caso, las propiedades están protegidas/privadas y configuradas mediante métodos de dominio público. Por lo tanto, no existe una manera fácil de establecer la clase construida en un estado determinado. Si, para fines de prueba, desea poder establecer rápidamente el estado de las propiedades de ese objeto por propiedades, una solución es agregar un método build() estático en la clase construida.
//Built class
class MyClass {
private int $ id ;
private ? string $ label = null ;
public static function create ( int $ id ): self
{
$ myClass = new self ();
$ myClass -> id = $ id ;
return $ myClass ;
}
public function updateLabel ( string $ label ): self
{
$ this -> label = $ label ;
return $ this ;
}
//This method will have to be generated by you IDE from the builder class
//It allows you to hack the state of this object without relying on its public interface
public static function build ( int $ id , string $ label ): self
{
$ myClass = new self ();
$ myClass -> id = $ this -> id ;
$ myClass -> label = $ this -> label ;
return $ myClass ;
}
}
//Builder class
class MyClassBuilder {
private int $ id ;
private string $ label ;
public function __construct ( Faker $ faker )
{
$ this -> id = $ faker -> number ();
$ this -> label = $ faker -> word ;
}
public function build (): MyClass
{
return MyClass:: build (
$ this -> id ,
$ this -> label
);
}
}
Para crear una estrategia personalizada:
NatiBuilderGeneratorPropertyPropertyBuildStrategy
y agregarlo a NatiBuilderGeneratorPropertyPropertyBuildStrategyCollection
. Esto decidirá CÓMO se construyen las propiedades.NatiBuilderGeneratorAnalyzerBuildableClassAnalyzer::getWriteStrategies()
. Esto decidirá CUÁNDO se podrán construir propiedades con esta estrategia. Puede utilizar esta herramienta como herramienta externa en su IDE.
Para usuarios de PHPStorm, consulte https://www.jetbrains.com/help/phpstorm/configuring-third-party-tools.html. Configuración de ejemplo: