Completed
Push — master ( 4fa9cb...c3dd31 )
by Nathan
02:40
created

BranchValidator::validateBranch()   B

Complexity

Conditions 5
Paths 4

Size

Total Lines 24
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 24
rs 8.5125
c 0
b 0
f 0
cc 5
eloc 14
nc 4
nop 2
1
<?php
2
3
namespace NatePage\EasyHtmlElement;
4
5
use NatePage\EasyHtmlElement\Exception\InvalidElementException;
6
7
class BranchValidator implements BranchValidatorInterface
8
{
9
    /** @var HtmlElementInterface */
10
    private $htmlElement;
11
12
    /**
13
     * @var array The options to check to valid a branch. The bool determine if the option can
14
     *            define more than one value. True = unique value, False = multiple values
15
     */
16
    private $checks = array(
17
        'parent' => true,
18
        'extends' => false,
19
        'children' => false
20
    );
21
22
    public function __construct(HtmlElementInterface $htmlElement)
23
    {
24
        $this->htmlElement = $htmlElement;
25
    }
26
27
    /**
28
     * {@inheritdoc}
29
     */
30
    public function validateBranch($name, array $circular = array())
31
    {
32
        $current = $this->htmlElement->getCurrentElement($name);
33
34
        $circular[] = $current['name'];
35
36
        $this->validateClass($current);
37
38
        foreach ($this->checks as $check => $unique) {
39
            if (isset($current[$check])) {
40
                $this->validateDefineHimself($current['name'], $current[$check], $check);
41
42
                if ($unique) {
43
                    $this->validateCircularReferences($current['name'], $current[$check], $check, $circular);
44
                    $this->validateBranch($current[$check], $circular);
45
                } else {
46
                    foreach ((array) $current[$check] as $cc) {
47
                        $this->validateCircularReferences($current['name'], $cc, $check, $circular);
48
                        $this->validateBranch($cc, $circular);
49
                    }
50
                }
51
            }
52
        }
53
    }
54
55
    /**
56
     * Validate the current element class.
57
     *
58
     * @param array $current The current element
59
     *
60
     * @throws InvalidElementException If the current element defines a class which doesn't exist
61
     */
62
    private function validateClass(array $current)
63
    {
64
        if (isset($current['class']) && !class_exists($current['class'])) {
65
            throw new InvalidElementException(sprintf(
66
                'The element "%s" define a class which doesn\'t exist.',
67
                $current['name']
68
            ));
69
        }
70
    }
71
72
    /**
73
     * Validate himself references.
74
     *
75
     * @param string $name         The current element name
76
     * @param array  $currentCheck The current check context
77
     * @param string $check        The current check name
78
     *
79
     * @throws InvalidElementException If the current element defines himself as parent, children or extends
80
     */
81
    private function validateDefineHimself(string $name, $currentCheck, string $check)
82
    {
83
        if (in_array($name, (array) $currentCheck)) {
84
            throw new InvalidElementException(sprintf(
85
                'Element "%s" cannot define himself as %s.',
86
                $name,
87
                $check
88
            ));
89
        }
90
    }
91
92
    /**
93
     * Validate circular references.
94
     *
95
     * @param string       $name         The current element name
96
     * @param string|array $currentCheck The current check context
97
     * @param string       $check        The current check name
98
     * @param array        $circular     The names of the previous elements called
99
     *
100
     * @throws InvalidElementException If the current element defines a parent, child or extends which creates circular
101
     *                                 reference
102
     */
103
    private function validateCircularReferences(string $name, $currentCheck, string $check, array $circular)
104
    {
105
        if (!is_array($currentCheck) && in_array($currentCheck, $circular)) {
106
            $circular[] = $currentCheck;
107
108
            throw new InvalidElementException(sprintf(
109
                'Element "%s" cannot define "%s" as %s. It\'s a circular reference. [%s]',
110
                $name,
111
                $currentCheck,
112
                $check,
113
                implode(' -> ', $circular)
114
            ));
115
        }
116
    }
117
}
118