Completed
Push — master ( a7fed8...afc97a )
by Nate
13:05
created

ElementMetricCollection::setMetrics()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 14
rs 9.7998
c 0
b 0
f 0
nc 3
cc 3
nop 1
1
<?php
2
3
/**
4
 * @copyright  Copyright (c) Flipbox Digital Limited
5
 * @license    https://flipboxfactory.com/software/scorecard/license
6
 * @link       https://www.flipboxfactory.com/software/scorecard/
7
 */
8
9
namespace flipbox\scorecard\records;
10
11
use flipbox\ember\helpers\ArrayHelper;
12
use flipbox\scorecard\db\ElementMetricQuery;
13
use flipbox\scorecard\helpers\MetricHelper;
14
use flipbox\scorecard\metrics\MetricInterface;
15
16
/**
17
 * @author Flipbox Factory <[email protected]>
18
 * @since 1.0.0
19
 *
20
 * @property ElementMetric[] $children
21
 */
22
abstract class ElementMetricCollection extends ElementMetric
23
{
24
    /**
25
     * @return array
26
     */
27
    const METRICS = [];
28
29
    /**
30
     * @var MetricInterface[]
31
     */
32
    private $metrics;
33
34
35
    /*******************************************
36
     * METRIC INTERFACE
37
     *******************************************/
38
39
    /**
40
     * @return float
41
     */
42
    protected function calculateScore(): float
43
    {
44
        // Sum of total/weight
45
        $total = $weights = 0;
46
47
        foreach ($this->getMetrics() as $metric) {
48
            $total += $metric->getScore();
49
            $weights += $metric->getWeight();
50
        }
51
52
        return (float)($total / $weights);
53
    }
54
55
56
    /*******************************************
57
     * METRICS (CHILDREN)
58
     *******************************************/
59
60
    /**
61
     * @return MetricInterface[]
62
     */
63
    public function getMetrics(): array
64
    {
65
        if ($this->metrics === null) {
66
            $this->setMetrics(
67
                $this->loadMetrics()
68
            );
69
        }
70
71
        return $this->metrics;
72
    }
73
74
    /**
75
     * @return array
76
     */
77
    protected function loadMetrics(): array
78
    {
79
        if ($this->getIsNewRecord()) {
80
            return (array)static::METRICS;
81
        }
82
83
        return array_filter(array_merge(
84
            $this->children,
85
            (array)ArrayHelper::getValue($this->settings, 'metrics', [])
86
        ));
87
    }
88
89
    /**
90
     * @param array $metrics
91
     * @return $this
92
     */
93
    public function setMetrics(array $metrics = [])
94
    {
95
        $this->metrics = [];
96
97
        foreach ($metrics as $metric) {
98
            if (!$metric instanceof MetricInterface) {
99
                $metric = $this->createMetric($metric);
100
            }
101
102
            $this->metrics[] = $metric;
103
        }
104
105
        return $this;
106
    }
107
108
    /**
109
     * @noinspection PhpDocMissingThrowsInspection
110
     *
111
     * @param $metric
112
     * @return MetricInterface
113
     */
114
    protected function createMetric($metric): MetricInterface
115
    {
116
        if (is_string($metric)) {
117
            $metric = ['class' => $metric];
118
        }
119
120
        /** Pass along the element */
121
        if (is_array($metric) && !isset($metric['elementId'])) {
122
            $metric['element'] = $metric['element'] ?? $this->getElement();
123
        }
124
125
        /** @noinspection PhpUnhandledExceptionInspection */
126
        /** @noinspection PhpIncompatibleReturnTypeInspection */
127
        return MetricHelper::create($metric);
128
    }
129
130
    /*******************************************
131
     * CHILDREN (RECORDS)
132
     *******************************************/
133
134
    /**
135
     * @return ElementMetricQuery
136
     */
137
    public function getChildren(): ElementMetricQuery
138
    {
139
        /** @var ElementMetricQuery $query */
140
        $query = $this->hasMany(
141
            static::class,
142
            ['parentId' => 'id']
143
        );
144
145
        // Children have parents
146
        $query->parentId(':notempty:');
147
148
        return $query;
149
    }
150
151
    /*******************************************
152
     * VALIDATE (CHILD RECORDS)
153
     *******************************************/
154
155
    /**
156
     * @inheritdoc
157
     */
158
    public function beforeValidate()
159
    {
160
        $success = true;
161
        foreach ($this->getMetrics() as $metric) {
162
            if ($metric instanceof ElementMetric) {
163
                if (!$metric->validate()) {
164
                    $success = false;
165
                }
166
            }
167
        }
168
169
        return $success ? parent::beforeValidate() : false;
170
    }
171
172
    /*******************************************
173
     * SAVE (CHILD RECORDS)
174
     *******************************************/
175
176
    /**
177
     * @inheritdoc
178
     */
179
    public function beforeSave($insert)
180
    {
181
        /** @var array $metrics */
182
        $metrics = [];
183
184
        foreach ($this->getMetrics() as $metric) {
185
            if (!$metric instanceof ElementMetric) {
186
                $metrics[] = $metric->toConfig();
187
            }
188
        }
189
190
        // Merge into settings
191
        if (!empty($metrics)) {
192
            $this->settings = array_filter(array_merge(
193
                (array)$this->settings,
194
                [
195
                    'metrics' => $metrics
196
                ]
197
            ));
198
        }
199
200
        return parent::beforeSave($insert);
201
    }
202
203
    /**
204
     * @inheritdoc
205
     */
206
    public function afterSave($insert, $changedAttributes)
207
    {
208
        /** @var ElementMetric[] $metrics */
209
        $children = [];
210
211
        foreach ($this->getMetrics() as $metric) {
212
            if ($metric instanceof ElementMetric) {
213
                $children[] = $metric;
214
            }
215
        }
216
217
        if (!empty($children)) {
218
            $success = true;
219
            foreach ($children as $child) {
220
                $child->parentId = $this->id;
221
222
                if (!$child->save()) {
223
                    $success = false;
224
                }
225
            }
226
227
            if (!$success) {
228
                $this->addError('children', 'Unable to save children');
229
            }
230
        }
231
232
        return parent::afterSave($insert, $changedAttributes);
233
    }
234
}
235