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
![]() |
|||||
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. ![]() |
|||||
129 | 11 | ->map(static function(\ReflectionParameter $parameter) { return $parameter->getName(); }) |
|||
130 | 11 | ->toArray() |
|||
131 | ; |
||||
132 | 11 | } |
|||
133 | } |
||||
134 |