pitchart /
phlunit
| 1 | <?php declare(strict_types=1); |
||||
| 2 | |||||
| 3 | |||||
| 4 | namespace Pitchart\Phlunit; |
||||
| 5 | |||||
| 6 | use function Pitchart\Transformer\transform; |
||||
| 7 | |||||
| 8 | abstract class Builder |
||||
| 9 | { |
||||
| 10 | /** @var array */ |
||||
| 11 | private $arguments = []; |
||||
| 12 | |||||
| 13 | /** |
||||
| 14 | * @var array |
||||
| 15 | */ |
||||
| 16 | private $constructorArguments = []; |
||||
| 17 | |||||
| 18 | /** @var string|null */ |
||||
| 19 | private $staticFactoryMethod; |
||||
| 20 | |||||
| 21 | /** |
||||
| 22 | * @var \ReflectionClass |
||||
| 23 | */ |
||||
| 24 | private $reflection; |
||||
| 25 | |||||
| 26 | /** |
||||
| 27 | * @var bool|\ReflectionClass|string |
||||
| 28 | */ |
||||
| 29 | protected $class; |
||||
| 30 | |||||
| 31 | abstract public function build(); |
||||
| 32 | |||||
| 33 | 11 | protected function __construct(string $class, array $arguments, string $staticFactoryMethod = null) |
|||
| 34 | { |
||||
| 35 | 11 | $this->staticFactoryMethod = $staticFactoryMethod; |
|||
| 36 | 11 | $this->arguments = $arguments; |
|||
| 37 | 11 | $this->class = $class; |
|||
| 38 | 11 | $this->reflection = new \ReflectionClass($class); |
|||
| 39 | |||||
| 40 | 11 | $this->extractConstructorArguments($staticFactoryMethod); |
|||
| 41 | |||||
| 42 | 11 | $missingConstructorArguments = transform($this->constructorArguments) |
|||
| 43 | 11 | ->remove(static function(string $key) use ($arguments) { |
|||
| 44 | 11 | return \array_key_exists($key, $arguments); |
|||
| 45 | 11 | }) |
|||
| 46 | 11 | ->toArray() |
|||
| 47 | ; |
||||
| 48 | |||||
| 49 | 11 | if (\count($missingConstructorArguments) > 0) { |
|||
| 50 | 2 | throw new \InvalidArgumentException(\sprintf( |
|||
| 51 | 2 | 'The following arguments key(s) must be provided with default value : [%s]', |
|||
| 52 | 2 | \implode(', ', $missingConstructorArguments) |
|||
| 53 | )); |
||||
| 54 | } |
||||
| 55 | 9 | } |
|||
| 56 | |||||
| 57 | /** |
||||
| 58 | * Override arguments |
||||
| 59 | * |
||||
| 60 | * @param $name |
||||
| 61 | * @param $value |
||||
| 62 | * |
||||
| 63 | * @return void |
||||
| 64 | */ |
||||
| 65 | 2 | final protected function setArgument(string $name, $value): void |
|||
| 66 | { |
||||
| 67 | 2 | if (! \array_key_exists($name, $this->arguments)) { |
|||
| 68 | 1 | throw new \InvalidArgumentException("There is no argument $name"); |
|||
| 69 | } |
||||
| 70 | 1 | $this->arguments[$name] = $value; |
|||
| 71 | 1 | } |
|||
| 72 | |||||
| 73 | /** |
||||
| 74 | * Allows to call with*() and and*() for defined arguments |
||||
| 75 | * |
||||
| 76 | * @param $name |
||||
| 77 | * @param $arguments |
||||
| 78 | * |
||||
| 79 | * @return Builder |
||||
| 80 | */ |
||||
| 81 | 4 | final public function __call($name, $arguments): self |
|||
| 82 | { |
||||
| 83 | 4 | if (\strpos($name, 'with') === 0) { |
|||
| 84 | 3 | $property = \substr($name, 4); |
|||
| 85 | } |
||||
| 86 | 4 | if (\strpos($name, 'and') === 0) { |
|||
| 87 | 1 | $property = \substr($name, 3); |
|||
| 88 | } |
||||
| 89 | 4 | if (!isset($property)) { |
|||
| 90 | 1 | throw new \BadMethodCallException("Method $name is not supported. Supported methods are with*() and and*()"); |
|||
| 91 | } |
||||
| 92 | 3 | if (\count($arguments) !== 1) { |
|||
| 93 | 1 | throw new \InvalidArgumentException(\sprintf("There must be exactly one argument for method '%s', %d given", $name, \count($arguments))); |
|||
| 94 | } |
||||
| 95 | 2 | $property = \lcfirst($property); |
|||
|
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
Loading history...
|
|||||
| 96 | 2 | $this->setArgument($property, \current($arguments)); |
|||
| 97 | 1 | return $this; |
|||
| 98 | } |
||||
| 99 | |||||
| 100 | /** |
||||
| 101 | * Builds the instance using the constructor or a static factory method |
||||
| 102 | * |
||||
| 103 | * @return mixed|object |
||||
| 104 | */ |
||||
| 105 | 6 | final protected function buildInstance() |
|||
| 106 | { |
||||
| 107 | 6 | if (!$this->staticFactoryMethod) { |
|||
| 108 | 5 | $args = transform($this->constructorArguments)->map(function(string $argumentName) { |
|||
| 109 | 5 | return $this->arguments[$argumentName]; |
|||
| 110 | 5 | })->toArray(); |
|||
| 111 | |||||
| 112 | 5 | return $this->reflection->newInstanceArgs($args); |
|||
| 113 | } |
||||
| 114 | 1 | return \call_user_func_array([$this->class, $this->staticFactoryMethod], $this->arguments); |
|||
| 115 | } |
||||
| 116 | |||||
| 117 | /** |
||||
| 118 | * Extracts the names of the instanciation method arguments |
||||
| 119 | * |
||||
| 120 | * @param null|string $staticFactoryMethod |
||||
| 121 | * |
||||
| 122 | * @return void |
||||
| 123 | */ |
||||
| 124 | 11 | private function extractConstructorArguments(?string $staticFactoryMethod): void |
|||
| 125 | { |
||||
| 126 | 11 | $instanciationMethod = $staticFactoryMethod === null ? $this->reflection->getConstructor() : $this->reflection->getMethod($staticFactoryMethod); |
|||
| 127 | |||||
| 128 | 11 | $this->constructorArguments = transform($instanciationMethod->getParameters()) |
|||
|
0 ignored issues
–
show
The method
getParameters() does not exist on null.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces. This is most likely a typographical error or the method has been renamed. Loading history...
|
|||||
| 129 | 11 | ->map(static function(\ReflectionParameter $parameter) { return $parameter->getName(); }) |
|||
| 130 | 11 | ->toArray() |
|||
| 131 | ; |
||||
| 132 | 11 | } |
|||
| 133 | } |
||||
| 134 |