Completed
Push — master ( 65a2b8...ac4e51 )
by Nate
25:58 queued 10:57
created

ElementMetric::init()   A

Complexity

Conditions 4
Paths 5

Size

Total Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 13
rs 9.8333
c 0
b 0
f 0
cc 4
nc 5
nop 0
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\craft\scorecard\records;
10
11
use Craft;
12
use craft\helpers\DateTimeHelper;
13
use DateTime;
14
use flipbox\ember\helpers\ModelHelper;
15
use flipbox\ember\records\ActiveRecordWithId;
16
use flipbox\ember\records\traits\ElementAttribute;
17
use flipbox\craft\scorecard\queries\ElementMetricQuery;
18
use flipbox\craft\scorecard\helpers\MetricHelper;
19
use flipbox\craft\scorecard\metrics\SavableMetricInterface;
20
use flipbox\craft\scorecard\validators\ElementMetricValidator;
21
22
/**
23
 * @author Flipbox Factory <[email protected]>
24
 * @since 1.0.0
25
 *
26
 * @property int $parentId
27
 * @property string $class
28
 * @property float $score
29
 * @property float $weight
30
 * @property string $version
31
 * @property array|null $settings
32
 * @property DateTime $dateCalculated
33
 */
34
abstract class ElementMetric extends ActiveRecordWithId implements SavableMetricInterface
35
{
36
    use ElementAttribute;
37
38
    /**
39
     * The default score weight
40
     */
41
    const WEIGHT = 1;
42
43
    /**
44
     * The default metric version
45
     */
46
    const VERSION = '1.0';
47
48
    /**
49
     * The table alias
50
     */
51
    const TABLE_ALIAS = 'scorecard_element_metrics';
52
53
    /**
54
     * The Active Query class
55
     */
56
    const ACTIVE_QUERY_CLASS = ElementMetricQuery::class;
57
58
    /**
59
     * @inheritdoc
60
     */
61
    protected $getterPriorityAttributes = ['elementId', 'score', 'dateCalculated'];
62
63
    /**
64
     * @return float
65
     */
66
    abstract protected function calculateScore(): float;
67
68
    /**
69
     * @inheritdoc
70
     */
71
    public function init()
72
    {
73
        parent::init();
74
75
        // Always this class
76
        $this->class = static::class;
77
78
        // Defaults
79
        if ($this->getIsNewRecord()) {
80
            $this->weight = $this->weight ?: static::WEIGHT;
81
            $this->version = $this->version ?: static::VERSION;
82
        }
83
    }
84
85
    /**
86
     * @inheritdoc
87
     */
88
    public static function populateRecord($record, $row)
89
    {
90
        parent::populateRecord($record, $row);
91
92
        $record->version = static::VERSION;
93
        $record->weight = static::WEIGHT;
94
        $record->class = static::class;
95
    }
96
97
    /**
98
     * @inheritdoc
99
     * @throws \yii\base\InvalidConfigException
100
     * @return ElementMetricQuery
101
     */
102
    public static function find()
103
    {
104
        /** @noinspection PhpUnhandledExceptionInspection */
105
        /** @noinspection PhpIncompatibleReturnTypeInspection */
106
        return Craft::createObject(
107
            static::ACTIVE_QUERY_CLASS,
108
            [
109
                get_called_class(),
110
                [
111
                    'class' => static::class
112
                ]
113
            ]
114
        );
115
    }
116
117
    /**
118
     * @inheritdoc
119
     */
120
    public function resetScore()
121
    {
122
        $this->setAttribute('score', null);
123
        return $this;
124
    }
125
126
    /**
127
     * @inheritdoc
128
     */
129
    public function beforeSave($insert)
130
    {
131
        // Make sure score is calculated
132
        $this->getScore();
133
134
        return parent::beforeSave($insert);
135
    }
136
137
    /**
138
     * @inheritdoc
139
     */
140
    public static function instantiate($row)
141
    {
142
        $class = $row['class'] ?? static::class;
143
        return new $class;
144
    }
145
146
    /**
147
     * @inheritdoc
148
     */
149
    public function rules()
150
    {
151
        return array_merge(
152
            parent::rules(),
153
            $this->elementRules(),
154
            [
155
                [
156
                    [
157
                        'class'
158
                    ],
159
                    ElementMetricValidator::class
160
                ],
161
                [
162
                    [
163
                        'parentId',
164
                    ],
165
                    'number',
166
                    'integerOnly' => true
167
                ],
168
                [
169
                    [
170
                        'score',
171
                        'weight',
172
                    ],
173
                    'number'
174
                ],
175
                [
176
                    [
177
                        'elementId',
178
                        'class',
179
                        'weight',
180
                        'version',
181
                    ],
182
                    'required'
183
                ],
184
                [
185
                    [
186
                        'class',
187
                        'settings',
188
                        'score',
189
                        'weight',
190
                        'version',
191
                        'dateCalculated'
192
                    ],
193
                    'safe',
194
                    'on' => [
195
                        ModelHelper::SCENARIO_DEFAULT
196
                    ]
197
                ]
198
            ]
199
        );
200
    }
201
202
203
    /*******************************************
204
     * METRIC INTERFACE
205
     *******************************************/
206
207
    /**
208
     * @inheritdoc
209
     * @throws \ReflectionException
210
     */
211
    public static function displayName(): string
212
    {
213
        return preg_replace(
214
            '/(?<!^)([A-Z])/',
215
            ' $0',
216
            (new \ReflectionClass(static::class))
217
                ->getShortName()
218
        );
219
    }
220
221
    /**
222
     * @inheritdoc
223
     */
224
    public function getWeight(): float
225
    {
226
        return (float)$this->getAttribute('weight');
227
    }
228
229
    /**
230
     * @inheritdoc
231
     */
232
    public function getVersion(): string
233
    {
234
        return (string)$this->getAttribute('version');
235
    }
236
237
    /**
238
     * @inheritdoc
239
     */
240
    public function getScore(): float
241
    {
242
        if ($this->getAttribute('score') === null) {
243
            $this->setAttribute('score', $this->calculateScore() * $this->getWeight());
244
        }
245
246
        return (float)$this->getAttribute('score');
247
    }
248
249
    /**
250
     * @return DateTime
251
     */
252
    public function getDateCalculated(): DateTime
253
    {
254
        if (null === ($dateCalculated = $this->getAttribute('dateCalculated'))) {
255
            $dateCalculated = $this->defaultDateCalculated();
256
            $this->setAttribute('dateCalculated', $dateCalculated);
257
        }
258
259
        if (!$dateCalculated instanceof DateTime) {
260
            if (is_array($dateCalculated)) {
261
                $dateCalculated = $dateCalculated['date'] ?? $dateCalculated;
262
            }
263
264
            $dateCalculated = DateTimeHelper::toDateTime($dateCalculated);
265
            $this->setAttribute('dateCalculated', $dateCalculated);
266
        }
267
268
        return $dateCalculated;
269
    }
270
271
    /**
272
     * @return DateTime
273
     */
274
    protected function defaultDateCalculated(): DateTime
275
    {
276
        return DateTimeHelper::toDateTime(
277
            DateTimeHelper::currentUTCDateTime()->format('Y-m-d')
278
        );
279
    }
280
281
282
    /*******************************************
283
     * SETTINGS
284
     *******************************************/
285
286
    /**
287
     * @param string $attribute
288
     * @return mixed
289
     */
290
    public function getSettingsValue(string $attribute)
291
    {
292
        $settings = MetricHelper::resolveSettings(
293
            $this->getAttribute('settings')
294
        );
295
296
        return $settings[$attribute] ?? null;
297
    }
298
299
    /**
300
     * @param string $attribute
301
     * @param $value
302
     * @return $this
303
     */
304
    public function setSettingsValue(string $attribute, $value)
305
    {
306
        $settings = MetricHelper::resolveSettings(
307
            $this->getAttribute('settings')
308
        );
309
        $settings[$attribute] = $value;
310
        $this->setAttribute('settings', $settings);
311
312
        return $this;
313
    }
314
315
316
    /*******************************************
317
     * CONFIGURATION
318
     *******************************************/
319
320
    /**
321
     * @return array
322
     */
323
    public function toConfig(): array
324
    {
325
        return $this->toArray();
326
    }
327
}
328