AbstractField::configure()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 3

Importance

Changes 6
Bugs 1 Features 2
Metric Value
c 6
b 1
f 2
dl 0
loc 9
ccs 8
cts 8
cp 1
rs 9.6666
cc 3
eloc 5
nc 3
nop 1
crap 3
1
<?php
2
3
namespace Zerg\Field;
4
5
use Zerg\DataSet;
6
use Zerg\Stream\AbstractStream;
7
8
/**
9
 * This abstract class represents any type of field - an entity that takes, processes and
10
 * returns some data from Stream. Also field has access
11
 * to DataSet from which it takes config values by given paths.
12
 *
13
 * @since 0.1
14
 * @package Zerg\Field
15
 */
16
abstract class AbstractField
17
{
18
    /**
19
     * @var DataSet The DataSet from which this field take values by path.
20
     */
21
    protected $dataSet;
22
23
    /**
24
     * @var mixed Value to compare parse result.
25
     */
26
    protected $assert;
27
28
    /**
29
     * @var array Cache to found values.
30
     */
31
    protected $propertyCache = [];
32
33
    /**
34
     * Read and process data from Stream.
35
     *
36
     * @api
37
     * @param AbstractStream $stream Stream from which field should read.
38
     * @return mixed Processed value.
39
     */
40
    abstract public function parse(AbstractStream $stream);
41
42
    /**
43
     * Associate given values to appropriate class properties.
44
     *
45
     * @param array $properties Associative array of properties values.
46
     */
47 54
    public function configure(array $properties)
48
    {
49 54
        foreach ($properties as $name => $value) {
50 32
            $methodName = 'set' . ucfirst(strtolower($name));
51 32
            if (method_exists($this, $methodName)) {
52 32
                $this->$methodName($value);
53 31
            }
54 53
        }
55 53
    }
56
57
    /**
58
     * Return DataSet instance from which this field take back linked values.
59
     *
60
     * @return DataSet DataSet corresponding this field.
61
     */
62 6
    public function getDataSet()
63
    {
64 6
        return $this->dataSet;
65
    }
66
67
    /**
68
     * Set to field DataSet instance for back links.
69
     *
70
     * @param DataSet $dataSet DataSet ro correspond to this field.
71
     * @return self For chaining.
72
     */
73 9
    public function setDataSet(DataSet $dataSet)
74
    {
75 9
        $this->dataSet = $dataSet;
76 9
        return $this;
77
    }
78
79
    /**
80
     * @return mixed
81
     */
82 19
    public function getAssert()
83
    {
84 19
        return $this->assert;
85
    }
86
87
    /**
88
     * @param mixed $assert
89
     * @return $this
90
     */
91 14
    public function setAssert($assert)
92
    {
93 14
        $this->assert = $assert;
94 14
        return $this;
95
    }
96
97
    /**
98
     * Check that given value is valid.
99
     *
100
     * @param $value mixed Checked value.
101
     * @return true On success validation.
0 ignored issues
show
Documentation introduced by
Should the return type not be boolean?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
102
     * @throws AssertException On assertion fail.
103
     */
104 19
    public function validate($value)
105
    {
106 19
        $assert = $this->getAssert();
107 19
        if ($assert !== null) {
108 8
            if (is_callable($assert)) {
109 2
                if (!call_user_func($assert, $value, $this)) {
110 1
                    throw new AssertException(
111 1
                        sprintf('Custom validation fail with value (%s) "%s"', gettype($value), print_r($value, true))
112 1
                    );
113
                }
114 1
            } else {
115 7
                if ($value !== $assert) {
116 3
                    throw new AssertException(
117 3
                        sprintf(
118 3
                            'Failed asserting that actual value (%s) "%s" matches expected value (%s) "%s".',
119 3
                            gettype($value),
120 3
                            print_r($value, true),
121 3
                            gettype($assert),
122 3
                            print_r($assert, true)
123 3
                        )
124 3
                    );
125
                }
126
            }
127 4
        }
128
129 15
        return true;
130
    }
131
132
    /**
133
     * Process, set and return given property.
134
     *
135
     * Find given property in DataSet if it was set as path string and return it.
136
     * Otherwise already set value will be returned.
137
     *
138
     * @param string $name Property name.
139
     * @return int|string|array|null Found or already set property value.
140
     */
141 32
    protected function resolveProperty($name)
142
    {
143 32
        $value = $this->$name;
144 32
        if (is_callable($value)) {
145 2
            return call_user_func($value, $this);
146
        }
147
148 31
        return $this->resolveValue($value);
149
    }
150
151
    /**
152
     * Find value in DataSet by given value if it is a path string.
153
     * Otherwise given value will be returned.
154
     *
155
     * @param $value
156
     * @return array|int|null|string
157
     * @since 0.2
158
     */
159 31
    private function resolveValue($value)
160
    {
161 31
        if (DataSet::isPath($value)) {
162 6
            if (empty($this->dataSet)) {
163 1
                throw new ConfigurationException('DataSet is required to resole value by path.');
164
            }
165 5
            $value = $this->dataSet->resolvePath($value);
166 5
        }
167
168 30
        if (is_array($value)) {
169 1
            foreach ($value as $key => $subValue) {
170 1
                $value[$key] = $this->resolveValue($subValue);
171 1
            }
172 1
        }
173
174 30
        return $value;
175
    }
176
}