Passed
Push — master ( 0e1b55...4f9081 )
by Julien
01:38 queued 10s
created

Builder   A

Complexity

Total Complexity 13

Size/Duplication

Total Lines 116
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 1
Bugs 0 Features 1
Metric Value
wmc 13
eloc 42
c 1
b 0
f 1
dl 0
loc 116
ccs 45
cts 45
cp 1
rs 10

5 Methods

Rating   Name   Duplication   Size   Complexity  
A buildInstance() 0 10 2
A extractConstructorArguments() 0 7 2
A __construct() 0 20 2
A setArgument() 0 6 2
A __call() 0 17 5
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
    private $constructorArguments = [];
14
15
    /** @var string|null */
16
    private $staticFactoryMethod;
17
18
    /**
19
     * @var \ReflectionClass
20
     */
21
    private $reflection;
22
23
    /**
24
     * @var bool|\ReflectionClass|string
25
     */
26
    protected $class;
27
28
    abstract public function build();
29
30 11
    protected function __construct(string $class, array $arguments, string $staticFactoryMethod = null)
31
    {
32 11
        $this->staticFactoryMethod = $staticFactoryMethod;
33 11
        $this->arguments = $arguments;
34 11
        $this->class = $class;
35 11
        $this->reflection = new \ReflectionClass($class);
36
37 11
        $this->extractConstructorArguments($staticFactoryMethod);
38
39 11
        $missingConstructorArguments = transform($this->constructorArguments)
40 11
            ->remove(static function (string $key) use ($arguments) {
41 11
                return \array_key_exists($key, $arguments);
42 11
            })
43 11
            ->toArray()
44
        ;
45
46 11
        if (\count($missingConstructorArguments) > 0) {
47 2
            throw new \InvalidArgumentException(\sprintf(
48 2
                'The following arguments key(s) must be provided with default value : [%s]',
49 2
                \implode(', ', $missingConstructorArguments)
50
            ));
51
        }
52 9
    }
53
54
    /**
55
     * Override arguments
56
     *
57
     * @param $name
58
     * @param $value
59
     */
60 2
    final protected function setArgument($name, $value)
61
    {
62 2
        if (! \array_key_exists($name, $this->arguments)) {
63 1
            throw new \InvalidArgumentException("There is no argument $name");
64
        }
65 1
        $this->arguments[$name] = $value;
66 1
    }
67
68
    /**
69
     * Allows to call with*() and and*() for defined arguments
70
     *
71
     * @param $name
72
     * @param $arguments
73
     *
74
     * @return Builder
75
     */
76 4
    final public function __call($name, $arguments): self
77
    {
78 4
        if (\strpos($name, 'with') === 0) {
79 3
            $property = \substr($name, 4);
80
        }
81 4
        if (\strpos($name, 'and') === 0) {
82 1
            $property = \substr($name, 3);
83
        }
84 4
        if (!isset($property)) {
85 1
            throw new \BadMethodCallException("Method $name is not supported. Supported methods are with*() and and*()");
86
        }
87 3
        if (\count($arguments) !== 1) {
88 1
            throw new \InvalidArgumentException(\sprintf("There must be exactly one argument for method '%s', %d given", $name, \count($arguments)));
89
        }
90 2
        $property = \lcfirst($property);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $property does not seem to be defined for all execution paths leading up to this point.
Loading history...
91 2
        $this->setArgument($property, \current($arguments));
92 1
        return $this;
93
    }
94
95
    /**
96
     * Builds the instance using the constructor or a static factory method
97
     *
98
     * @return mixed|object
99
     */
100 6
    final protected function buildInstance()
101
    {
102 6
        if (!$this->staticFactoryMethod) {
103 5
            $args = transform($this->constructorArguments)->map(function(string $argumentName) {
104 5
                return $this->arguments[$argumentName];
105 5
            })->toArray();
106
107 5
            return $this->reflection->newInstanceArgs($args);
108
        }
109 1
        return \call_user_func_array([$this->class, $this->staticFactoryMethod], $this->arguments);
110
    }
111
112
    /**
113
     * Extracts the names of the instanciation method arguments
114
     *
115
     * @param null|string $staticFactoryMethod
116
     */
117 11
    private function extractConstructorArguments(?string $staticFactoryMethod)
118
    {
119 11
        $instanciationMethod = $staticFactoryMethod === null ? $this->reflection->getConstructor() : $this->reflection->getMethod($staticFactoryMethod);
120
121 11
        $this->constructorArguments = transform($instanciationMethod->getParameters())
0 ignored issues
show
Bug introduced by
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 ignore-call  annotation

121
        $this->constructorArguments = transform($instanciationMethod->/** @scrutinizer ignore-call */ getParameters())

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...
122 11
            ->map(static function(\ReflectionParameter $parameter) { return $parameter->getName(); })
123 11
            ->toArray()
124
        ;
125 11
    }
126
}
127