natitech / builder-generator
PHP 独立库,用于从一个类生成构建器(模式)
Requires
- php: ^7.4|^8.0
- nette/php-generator: ^3.2
- nikic/php-parser: ^4.2
- phpstan/phpdoc-parser: ^1.0
- psr/log: ^1.0 || ^2.0 || ^3.0
- symfony/console: ^6.1
Requires (Dev)
- fakerphp/faker: ^1.8
- phpunit/phpunit: ^9.0
Suggests
- fakerphp/faker: To initialize properties with more relevant random data
- monolog/monolog: To display or log more infos on what is done
README
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
- 参数
- 工作目录