Composite   A
last analyzed

Complexity

Total Complexity 11

Size/Duplication

Total Lines 105
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 2

Importance

Changes 0
Metric Value
wmc 11
lcom 1
cbo 2
dl 0
loc 105
rs 10
c 0
b 0
f 0

5 Methods

Rating   Name   Duplication   Size   Complexity  
A searchOverridenParameters() 0 20 4
A __construct() 0 12 3
A addSpecification() 0 4 1
A getRule() 0 6 1
A getParameters() 0 29 2
1
<?php
2
3
declare(strict_types=1);
4
5
namespace RulerZ\Spec;
6
7
use RulerZ\Exception\ParameterOverridenException;
8
9
/**
10
 * @internal
11
 */
12
class Composite implements Specification
13
{
14
    /**
15
     * @var string
16
     */
17
    private $operator;
18
19
    /**
20
     * @var array
21
     */
22
    private $specifications = [];
23
24
    /**
25
     * Builds a composite specification.
26
     *
27
     * @param string $operator The operator used to join the specifications.
28
     * @param array $specifications A list specifications to combine.
29
     */
30
    public function __construct($operator, array $specifications = [])
31
    {
32
        $this->operator = $operator;
33
34
        if (empty($specifications)) {
35
            throw new \LogicException('No specifications given.');
36
        }
37
38
        foreach ($specifications as $specification) {
39
            $this->addSpecification($specification);
40
        }
41
    }
42
43
    private function addSpecification(Specification $specification): void
44
    {
45
        $this->specifications[] = $specification;
46
    }
47
48
    /**
49
     * {@inheritdoc}
50
     */
51
    public function getRule(): string
52
    {
53
        return implode(sprintf(' %s ', $this->operator), array_map(function (Specification $specification) {
54
            return sprintf('(%s)', $specification->getRule());
55
        }, $this->specifications));
56
    }
57
58
    /**
59
     * {@inheritdoc}
60
     */
61
    public function getParameters(): array
62
    {
63
        $parametersCount = 0;
64
65
        $parametersList = array_map(function (Specification $specification) use (&$parametersCount) {
66
            $parametersCount += count($specification->getParameters());
67
68
            return $specification->getParameters();
69
        }, $this->specifications);
70
71
        $mergedParameters = array_merge([], ...$parametersList);
72
73
        // error handling in case of overriden parameters
74
        if ($parametersCount !== count($mergedParameters)) {
75
            $overridenParameters = $this->searchOverridenParameters($parametersList);
76
            $specificationsTypes = array_map(function (Specification $spec) {
77
                return get_class($spec);
78
            }, $this->specifications);
79
80
            throw new ParameterOverridenException(sprintf(
81
                'Looks like some parameters were overriden (%s) while combining specifications of types %s'."\n".
82
                'More information on how to solve this can be found here: https://github.com/K-Phoen/rulerz/issues/3',
83
                implode(', ', $overridenParameters),
84
                implode(', ', $specificationsTypes)
85
            ));
86
        }
87
88
        return $mergedParameters;
89
    }
90
91
    /**
92
     * Search the parameters that were overridden during the parameters-merge phase.
93
     *
94
     * @return array Names of the overridden parameters.
95
     */
96
    private function searchOverridenParameters(array $parametersList): array
97
    {
98
        $parametersUsageCount = [];
99
100
        foreach ($parametersList as $list) {
101
            foreach ($list as $parameter => $_value) {
102
                if (!isset($parametersUsageCount[$parameter])) {
103
                    $parametersUsageCount[$parameter] = 0;
104
                }
105
106
                $parametersUsageCount[$parameter] += 1;
107
            }
108
        }
109
110
        $overriddenParameters = array_filter($parametersUsageCount, function ($count) {
111
            return $count > 1;
112
        });
113
114
        return array_keys($overriddenParameters);
115
    }
116
}
117