Completed
Push — develop ( 55c38a...c1b735 )
by Nate
12:53
created

Provider   A

Complexity

Total Complexity 38

Size/Duplication

Total Lines 421
Duplicated Lines 0 %

Coupling/Cohesion

Components 3
Dependencies 14

Test Coverage

Coverage 0%

Importance

Changes 0
Metric Value
wmc 38
lcom 3
cbo 14
dl 0
loc 421
ccs 0
cts 137
cp 0
rs 9.36
c 0
b 0
f 0

16 Methods

Rating   Name   Duplication   Size   Complexity  
A findByCondition() 0 9 3
A getIcon() 0 10 2
A getSettings() 0 14 2
A populateRecord() 0 12 2
B rules() 0 55 1
A getTokens() 0 16 2
A getLocks() 0 16 2
A saveAndLock() 0 8 2
A addLock() 0 24 3
A removeLock() 0 15 4
A isLocked() 0 4 1
A getPluginId() 0 14 2
A getPluginName() 0 14 2
A delete() 0 4 2
A canDelete() 0 44 4
A toProjectConfig() 0 11 1
1
<?php
2
3
/**
4
 * @copyright  Copyright (c) Flipbox Digital Limited
5
 * @license    https://flipboxfactory.com/software/patron/license
6
 * @link       https://www.flipboxfactory.com/software/patron/
7
 */
8
9
namespace flipbox\patron\records;
10
11
use Craft;
12
use craft\base\PluginInterface;
13
use craft\db\Query;
14
use craft\helpers\Json;
15
use craft\helpers\StringHelper;
16
use flipbox\craft\ember\helpers\ObjectHelper;
17
use flipbox\craft\ember\helpers\QueryHelper;
18
use flipbox\craft\ember\models\HandleRulesTrait;
19
use flipbox\craft\ember\records\ActiveRecordWithId;
20
use flipbox\craft\ember\records\StateAttributeTrait;
21
use flipbox\patron\events\RegisterProviderSettings;
22
use flipbox\patron\helpers\ProviderHelper;
23
use flipbox\patron\Patron;
24
use flipbox\patron\queries\ProviderActiveQuery;
25
use flipbox\patron\settings\BaseSettings;
26
use flipbox\patron\settings\SettingsInterface;
27
use flipbox\patron\validators\ProviderSettings as ProviderSettingsValidator;
28
use flipbox\patron\validators\ProviderValidator;
29
use yii\helpers\ArrayHelper;
30
31
/**
32
 * @author Flipbox Factory <[email protected]>
33
 * @since 1.0.0
34
 *
35
 * @property string $clientId
36
 * @property string $clientSecret
37
 * @property string $class
38
 * @property ProviderLock[] $locks
39
 * @property Token[] $tokens
40
 * @property SettingsInterface $settings
41
 */
42
class Provider extends ActiveRecordWithId
43
{
44
    use HandleRulesTrait,
45
        StateAttributeTrait;
46
47
    /**
48
     * The table alias
49
     */
50
    const TABLE_ALIAS = 'patron_providers';
51
52
    const CLIENT_ID_LENGTH = 100;
53
    const CLIENT_SECRET_LENGTH = 255;
54
55
    protected $getterPriorityAttributes = ['settings'];
56
57
    /**
58
     * @inheritdoc
59
     * @return ProviderActiveQuery
60
     * @throws \yii\base\InvalidConfigException
61
     */
62
    public static function find()
63
    {
64
        /** @noinspection PhpIncompatibleReturnTypeInspection */
65
        return Craft::createObject(ProviderActiveQuery::class, [get_called_class()]);
66
    }
67
68
    /**
69
     * @inheritdoc
70
     */
71
    protected static function findByCondition($condition)
72
    {
73
        if (!is_numeric($condition) && is_string($condition)) {
74
            $condition = ['handle' => $condition];
75
        }
76
77
        /** @noinspection PhpInternalEntityUsedInspection */
78
        return parent::findByCondition($condition);
79
    }
80
81
    /**
82
     * @return string|null
83
     */
84
    public function getIcon()
85
    {
86
        if ($this->class === null) {
87
            return null;
88
        }
89
90
        $icons = Patron::getInstance()->getCp()->getProviderIcons();
91
92
        return $icons[$this->class] ?? null;
93
    }
94
95
    /**
96
     * @return SettingsInterface
97
     * @throws \yii\base\InvalidConfigException
98
     */
99
    public function getSettings(): SettingsInterface
100
    {
101
        $settings = $this->getAttribute('settings');
102
        if (!$settings instanceof SettingsInterface) {
103
            $settings = Patron::getInstance()->providerSettings(
104
                $this->class,
105
                $this->getAttribute('settings')
106
            );
107
108
            $this->setAttribute('settings', $settings);
109
        }
110
111
        return $settings;
112
    }
113
114
115
    /**
116
     * @param $record
117
     * @param $row
118
     */
119
    public static function populateRecord($record, $row)
120
    {
121
        // Apply override settings
122
        if (null !== ($handle = $row['handle'] ?? null)) {
123
            $row = array_merge(
124
                $row,
125
                Patron::getInstance()->getSettings()->getProvider($handle)
126
            );
127
        }
128
129
        parent::populateRecord($record, $row);
130
    }
131
132
    /**
133
     * @inheritdoc
134
     */
135
    public function rules()
136
    {
137
        return array_merge(
138
            parent::rules(),
139
            $this->handleRules(),
140
            $this->stateRules(),
141
            [
142
                [
143
                    [
144
                        'clientId'
145
                    ],
146
                    'string',
147
                    'max' => static::CLIENT_ID_LENGTH
148
                ],
149
                [
150
                    [
151
                        'clientSecret'
152
                    ],
153
                    'string',
154
                    'max' => static::CLIENT_SECRET_LENGTH
155
                ],
156
                [
157
                    [
158
                        'class'
159
                    ],
160
                    ProviderValidator::class
161
                ],
162
                [
163
                    [
164
                        'settings'
165
                    ],
166
                    ProviderSettingsValidator::class
167
                ],
168
                [
169
                    [
170
                        'class',
171
                        'clientId'
172
                    ],
173
                    'required'
174
                ],
175
                [
176
                    [
177
                        'class',
178
                        'clientId',
179
                        'clientSecret',
180
                        'settings',
181
                    ],
182
                    'safe',
183
                    'on' => [
184
                        self::SCENARIO_DEFAULT
185
                    ]
186
                ]
187
            ]
188
        );
189
    }
190
191
192
    /*******************************************
193
     * RELATIONS
194
     *******************************************/
195
196
    /**
197
     * Get all of the associated tokens.
198
     *
199
     * @param array $config
200
     * @return \yii\db\ActiveQuery
201
     */
202
    public function getTokens(array $config = [])
203
    {
204
        $query = $this->hasMany(
205
            Token::class,
206
            ['providerId' => 'id']
207
        );
208
209
        if (!empty($config)) {
210
            QueryHelper::configure(
211
                $query,
212
                $config
213
            );
214
        }
215
216
        return $query;
217
    }
218
219
    /**
220
     * Get all of the associated tokens.
221
     *
222
     * @param array $config
223
     * @return \yii\db\ActiveQuery
224
     */
225
    public function getLocks(array $config = [])
226
    {
227
        $query = $this->hasMany(
228
            ProviderLock::class,
229
            ['providerId' => 'id']
230
        );
231
232
        if (!empty($config)) {
233
            QueryHelper::configure(
234
                $query,
235
                $config
236
            );
237
        }
238
239
        return $query;
240
    }
241
242
    /*******************************************
243
     * SAVE
244
     *******************************************/
245
246
    /**
247
     * @param PluginInterface $plugin
248
     * @param bool $runValidation
249
     * @param null $attributeNames
250
     * @return bool
251
     */
252
    public function saveAndLock(PluginInterface $plugin, $runValidation = true, $attributeNames = null): bool
253
    {
254
        if (!$this->save($runValidation, $attributeNames)) {
255
            return false;
256
        }
257
258
        return $this->addLock($plugin);
259
    }
260
261
262
    /*******************************************
263
     * LOCK
264
     *******************************************/
265
266
    /**
267
     * @param PluginInterface $plugin
268
     * @return bool
269
     */
270
    public function addLock(PluginInterface $plugin): bool
271
    {
272
        if (null === ($pluginId = $this->getPluginId($plugin))) {
273
            return false;
274
        }
275
276
        $record = ProviderLock::findOne([
277
            'providerId' => $this->getId(),
278
            'pluginId' => $pluginId
279
        ]);
280
281
        if (!empty($record)) {
282
            return true;
283
        }
284
285
        $record = new ProviderLock();
286
287
        $record->setAttributes([
288
            'providerId' => $this->getId(),
289
            'pluginId' => $pluginId
290
        ]);
291
292
        return (bool)$record->save();
293
    }
294
295
    /**
296
     * @param PluginInterface $plugin
297
     * @return bool
298
     * @throws \Throwable
299
     */
300
    public function removeLock(PluginInterface $plugin): bool
301
    {
302
        if (null === ($pluginId = $this->getPluginId($plugin))) {
303
            return false;
304
        }
305
306
        if (null === ($record = ProviderLock::findOne([
307
                'providerId' => $this->getId() ?: 0,
308
                'pluginId' => $pluginId
309
            ]))) {
310
            return true;
311
        }
312
313
        return (bool)$record->delete();
314
    }
315
316
    /**
317
     * @return bool
318
     */
319
    public function isLocked(): bool
320
    {
321
        return !empty($this->locks);
322
    }
323
324
    /**
325
     * @param PluginInterface $plugin
326
     * @return int|null
327
     */
328
    protected function getPluginId(PluginInterface $plugin)
329
    {
330
        $id = (new Query())
331
            ->select([
332
                'id',
333
            ])
334
            ->from(['{{%plugins}}'])
335
            ->where([
336
                'handle' => $plugin->getHandle()
337
            ])
338
            ->scalar();
339
340
        return $id ? (int)$id : null;
341
    }
342
343
    /**
344
     * @param PluginInterface $plugin
345
     * @return int|null
346
     */
347
    protected function getPluginName(PluginInterface $plugin)
348
    {
349
        $id = (new Query())
350
            ->select([
351
                'id',
352
            ])
353
            ->from(['{{%plugins}}'])
354
            ->where([
355
                'handle' => $plugin->getHandle()
356
            ])
357
            ->scalar();
358
359
        return $id ? (int)$id : null;
360
    }
361
362
363
    /*******************************************
364
     * DELETE
365
     *******************************************/
366
367
    /**
368
     * @param PluginInterface|null $plugin
369
     * @return bool|false|int
370
     * @throws \Throwable
371
     * @throws \yii\db\StaleObjectException
372
     */
373
    public function delete(PluginInterface $plugin = null)
374
    {
375
        return $this->canDelete($plugin) ? parent::delete() : false;
376
    }
377
378
    /**
379
     * @param PluginInterface|null $plugin
380
     * @return bool
381
     * @throws \craft\errors\InvalidPluginException
382
     */
383
    protected function canDelete(PluginInterface $plugin = null)
384
    {
385
        // If a plugin is locking this, prevent deletion
386
        $lockQuery = $this->getLocks();
387
        if (null !== $plugin) {
388
            $lockQuery->andWhere(
389
                ['<>', 'pluginId', $this->getPluginId($plugin)]
390
            );
391
        }
392
393
        $locks = $lockQuery->all();
394
395
        if (count($locks) > 0) {
396
            $handles = (new Query())
397
                ->select([
398
                    'handle',
399
                ])
400
                ->from(['{{%plugins}}'])
401
                ->where([
402
                    'id' => ArrayHelper::getColumn($locks, 'pluginId'),
403
                ])
404
                ->column();
405
406
            $names = [];
407
            foreach ($handles as $handle) {
408
                $plugin = Craft::$app->getPlugins()->getPluginInfo($handle);
409
                $names[] = $plugin['name'] ?? 'Unknown Plugin';
410
            }
411
412
            $this->addError(
413
                'locks',
414
                Craft::t(
415
                    'patron',
416
                    'The provider is locked by the following plugins: {plugins}',
417
                    [
418
                        'plugins' => StringHelper::toString($names, ', ')
419
                    ]
420
                )
421
            );
422
            return false;
423
        }
424
425
        return true;
426
    }
427
428
    /**
429
     * @return string
430
     * @throws \ReflectionException
431
     */
432
    public function getDisplayName(): string
433
    {
434
        if (empty($this->class)) {
435
            return 'Unknown';
436
        }
437
438
        return ProviderHelper::displayName(
439
            $this->class
440
        );
441
    }
442
443
444
    /*******************************************
445
     * PROJECT CONFIG
446
     *******************************************/
447
448
    /**
449
     * Return an array suitable for Craft's Project config
450
     */
451
    public function toProjectConfig(): array
452
    {
453
        return $this->toArray([
454
            'handle',
455
            'clientId',
456
            'clientSecret',
457
            'class',
458
            'scopes',
459
            'enabled'
460
        ]);
461
    }
462
}
463