natitech/builder-generator

PHP 独立库,用于从一个类生成构建器(模式)

2.2.0 2022-09-16 22:57 UTC

This package is auto-updated.

Last update: 2024-09-17 03:33:34 UTC


README

License

PHP 独立库,可以从类生成 构建器模式

安装

通过在你的项目或全局范围内使用 composer

composer require natitech/builder-generator
composer global require natitech/builder-generator

用法

您可以使用二进制文件在类附近生成构建器

/path/to/vendor/bin/generate-builder /path/to/class

或者您可以在另一个 PHP 脚本中使用它

\Nati\BuilderGenerator\FileBuilderGenerator::create()->generateFrom('/path/to/class');

将生成什么

这将生成一个与构建类并排的构建器类。

示例

//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());
}

构建器类可能需要接收关于编码风格、Faker 使用、推断类型、命名空间等的更新。此外,为了避免生成未使用的代码,构建器属性没有设置器。您的 IDE 应该能够轻松修复所有这些问题。

生成器将尝试检测属性类型(PHP 类型、PHPdoc 类型、Doctrine ORM 属性或注解)并根据属性的类型和名称尝试检测适当的 Faker 方法。

Faker

您可以使用 --faker 选项尝试设置最相关的值。在这种情况下,Faker 将作为构建器类的依赖项使用。

构建策略

有许多构建类的策略:公共属性、设置器(流畅或非流畅)、构造函数。下面简要说明了每个策略,但您可能更愿意阅读单元测试以全面理解它们。

默认情况下,生成器将尝试检测构建类中最常用的策略,并将其用于整个构建器类。如果您使用所有属性(除了一个)的设置器,生成器将使用支持设置器的属性,并忽略不支持设置的属性。

但您也可以显式使用 '--strategy' 选项传递策略。

公共策略

当属性是公共的。参见上面的示例。

构造函数策略

当属性是受保护的/私有的,并在 __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
        );
    }
}

设置器策略

当属性是受保护的/私有的,但可以使用公共设置器设置时。设置器可以是流畅的或非流畅的。

//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);
    }
}

构建方法策略

这是一种不太规范的构建类的方法。在这种情况下,属性是受保护的/私有的,并由公共域方法设置。因此,没有简单的方法可以设置构建类的状态。如果出于测试目的,您希望能够快速通过属性逐个设置对象的状态,则解决方案是在构建类中添加一个静态 build() 方法。

//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
        );
    }
}

自定义策略/贡献

要创建自定义策略

  • 您需要实现 Nati\BuilderGenerator\Property\PropertyBuildStrategy 并将其添加到 Nati\BuilderGenerator\Property\PropertyBuildStrategyCollection。这将决定属性是如何构建的。
  • 您还需要完成 \Nati\BuilderGenerator\Analyzer\BuildableClassAnalyzer::getWriteStrategies()。这将决定何时可以使用此策略构建属性。

IDE / PHPStorm

您可以将此工具用作 IDE 中的外部工具。

对于 PHPStorm 用户,请参阅 https://www.jetbrains.com/help/phpstorm/configuring-third-party-tools.html。示例配置

  • 名称:生成构建器
  • 描述:从PHP类生成构建器类
  • 程序:/path/to/your/home/.composer/vendor/bin/generate-builder
  • 参数
  • 工作目录