OrganizationType::find()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 6
ccs 0
cts 2
cp 0
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
crap 2
1
<?php
2
3
/**
4
 * @copyright  Copyright (c) Flipbox Digital Limited
5
 * @license    https://flipboxfactory.com/software/organization/license
6
 * @link       https://www.flipboxfactory.com/software/organization/
7
 */
8
9
namespace flipbox\organizations\records;
10
11
use Craft;
12
use craft\helpers\ArrayHelper;
13
use flipbox\craft\ember\helpers\ObjectHelper;
14
use flipbox\craft\ember\models\HandleRulesTrait;
15
use flipbox\craft\ember\records\ActiveRecordWithId;
16
use flipbox\craft\ember\records\FieldLayoutAttributeTrait;
17
use flipbox\craft\ember\validators\ModelValidator;
18
use flipbox\organizations\Organizations as OrganizationPlugin;
19
use flipbox\organizations\queries\OrganizationTypeQuery;
20
use yii\base\Exception;
21
use yii\db\ActiveQueryInterface;
22
use yii\validators\UniqueValidator;
23
24
/**
25
 * @author Flipbox Factory <[email protected]>
26
 * @since 1.0.0
27
 *
28
 * @property string $name
29
 * @property OrganizationTypeSiteSettings[] $siteSettingRecords
30
 */
31
class OrganizationType extends ActiveRecordWithId
32
{
33
    use FieldLayoutAttributeTrait,
34
        HandleRulesTrait {
35
            resolveFieldLayout as traitResolveFieldLayout;
36
    }
37
38
    /**
39
     * The table name
40
     */
41
    const TABLE_ALIAS = Organization::TABLE_ALIAS . '_types';
42
43
    /**
44
     * @inheritdoc
45
     */
46
    protected $getterPriorityAttributes = ['fieldLayoutId'];
47
48
    /**
49
     * @inheritdoc
50
     */
51
    protected static function fieldLayoutType(): string
52
    {
53
        return self::class;
54
    }
55
56
    /**
57
     * @inheritdoc
58
     */
59
    protected function resolveFieldLayout()
60
    {
61
        if (null === ($fieldLayout = $this->traitResolveFieldLayout())) {
62
            $fieldLayout = OrganizationPlugin::getInstance()->getSettings()->getFieldLayout();
63
        }
64
65
        return $fieldLayout;
66
    }
67
68
69
    /**
70
     * @noinspection PhpDocMissingThrowsInspection
71
     *
72
     * @inheritdoc
73
     * @return OrganizationTypeQuery
74
     */
75
    public static function find()
76
    {
77
        /** @noinspection PhpUnhandledExceptionInspection */
78
        /** @noinspection PhpIncompatibleReturnTypeInspection */
79
        return Craft::createObject(OrganizationTypeQuery::class, [get_called_class()]);
80
    }
81
82
    /**
83
     * @inheritdoc
84
     */
85
    protected static function findByCondition($condition)
86
    {
87
        if (is_numeric($condition)) {
88
            $condition = ['id' => $condition];
89
        }
90
91
        if (is_string($condition)) {
92
            $condition = ['handle' => $condition];
93
        }
94
95
        return parent::findByCondition($condition);
96
    }
97
98
    /*******************************************
99
     * EVENTS
100
     *******************************************/
101
102
    /**
103
     * @inheritdoc
104
     * @throws Exception
105
     */
106
    public function beforeSave($insert)
107
    {
108
        if (false === parent::beforeSave($insert)) {
109
            return false;
110
        }
111
112
        $fieldLayout = $this->getFieldLayout();
113
114
        // Get old field layout (and delete it if necessary)
115
        $oldFieldLayoutId = (int)$this->getOldAttribute('fieldLayoutId');
116
        if ($oldFieldLayoutId != $fieldLayout->id &&
117
            $oldFieldLayoutId != $this->getDefaultFieldLayoutId()
118
        ) {
119
            Craft::$app->getFields()->deleteLayoutById($oldFieldLayoutId);
120
        }
121
122
        if (!Craft::$app->getFields()->saveLayout($fieldLayout)) {
123
            return false;
124
        }
125
126
        // Set the attribute (just to ensure)
127
        $this->fieldLayoutId = $fieldLayout->id;
128
129
        return true;
130
    }
131
132
    /**
133
     * @return int
134
     */
135
    protected function getDefaultFieldLayoutId(): int
136
    {
137
        return (int)OrganizationPlugin::getInstance()->getSettings()->getFieldLayout()->id;
138
    }
139
140
    /**
141
     * @inheritdoc
142
     * @throws Exception
143
     * @throws \Throwable
144
     * @throws \craft\errors\SiteNotFoundException
145
     * @throws \yii\db\StaleObjectException
146
     */
147
    public function afterSave($insert, $changedAttributes)
148
    {
149
        $successful = true;
150
151
        /** @var OrganizationTypeSiteSettings[] $allSettings */
152
        $allSettings = $this->hasMany(OrganizationTypeSiteSettings::class, ['typeId' => 'id'])
153
            ->indexBy('siteId')
154
            ->all();
155
156
        foreach ($this->getSiteSettings() as $model) {
157
            ArrayHelper::remove($allSettings, $model->siteId);
158
            $model->typeId = $this->getId();
159
160
            if (!$model->save()) {
161
                $successful = false;
162
                // Log the errors
163
                $error = Craft::t(
164
                    'organizations',
165
                    "Couldn't save site settings due to validation errors:"
166
                );
167
                foreach ($model->getFirstErrors() as $attributeError) {
168
                    $error .= "\n- " . Craft::t('organizations', $attributeError);
169
                }
170
171
                $this->addError('sites', $error);
172
            }
173
        }
174
175
        // Delete old settings records
176
        foreach ($allSettings as $settings) {
177
            $settings->delete();
178
        }
179
180
        if (!$successful) {
181
            throw new Exception("Unable to save site settings");
182
        };
183
184
        parent::afterSave($insert, $changedAttributes);
185
    }
186
187
188
189
    /*******************************************
190
     * SITE SETTINGS
191
     *******************************************/
192
193
    /**
194
     * @return OrganizationTypeSiteSettings[]
195
     * @throws \craft\errors\SiteNotFoundException
196
     */
197
    public function getSiteSettings(): array
198
    {
199
        if (empty($this->siteSettingRecords)) {
200
            $this->addPrimarySiteSettings();
201
        }
202
203
        return $this->siteSettingRecords;
204
    }
205
206
    /**
207
     * @param array $siteSettings
208
     * @return $this
209
     */
210
    public function setSiteSettings(array $siteSettings = [])
211
    {
212
        foreach ($siteSettings as $siteId => &$site) {
213
            $site = $this->resolveSiteSettings($siteId, $site);
214
        }
215
216
        $this->populateRelation('siteSettingRecords', $siteSettings);
217
        return $this;
218
    }
219
220
    /**
221
     * @return $this
222
     * @throws \craft\errors\SiteNotFoundException
223
     */
224
    protected function addPrimarySiteSettings()
225
    {
226
        $primarySite = Craft::$app->getSites()->getPrimarySite();
227
228
        if ($primarySite->id !== null) {
229
            $this->addSiteSettings($primarySite->id, ['site' => $primarySite]);
230
        }
231
232
        return $this;
233
    }
234
235
    /**
236
     * @param int $siteId
237
     * @param $site
238
     * @return OrganizationTypeSiteSettings
239
     */
240
    protected function resolveSiteSettings(int $siteId, $site): OrganizationTypeSiteSettings
241
    {
242
        if (!$record = $this->siteSettingRecords[$siteId] ?? null) {
243
            $record = new OrganizationTypeSiteSettings();
244
        }
245
246
        /** @noinspection PhpIncompatibleReturnTypeInspection */
247
        return ObjectHelper::populate(
248
            $record,
249
            $site
250
        );
251
    }
252
253
    /**
254
     * @param int $siteId
255
     * @param $site
256
     * @return $this
257
     */
258
    protected function addSiteSettings(int $siteId, $site)
259
    {
260
        $site = $this->resolveSiteSettings($siteId, $site);
261
        $this->populateRelation('siteSettingRecords', (
262
            $this->siteSettingRecords +
263
            [
264
                $site->getSiteId() => $site
265
            ]
266
        ));
267
268
        return $this;
269
    }
270
271
272
    /**
273
     * @inheritdoc
274
     */
275
    public function rules()
276
    {
277
        return array_merge(
278
            parent::rules(),
279
            $this->handleRules(),
280
            $this->fieldLayoutRules(),
281
            [
282
                [
283
                    [
284
                        'name'
285
                    ],
286
                    'required'
287
                ],
288
                [
289
                    [
290
                        'siteSettings'
291
                    ],
292
                    ModelValidator::class
293
                ],
294
                [
295
                    [
296
                        'name',
297
                    ],
298
                    'string',
299
                    'max' => 255
300
                ],
301
                [
302
                    [
303
                        'handle'
304
                    ],
305
                    UniqueValidator::class
306
                ]
307
            ]
308
        );
309
    }
310
311
    /**
312
     * @return array
313
     */
314
    public function attributeLabels()
315
    {
316
        return array_merge(
317
            parent::attributeLabels(),
318
            $this->fieldLayoutAttributeLabels()
319
        );
320
    }
321
322
    /**
323
     * @return ActiveQueryInterface
324
     * @throws \craft\errors\SiteNotFoundException
325
     */
326
    protected function getSiteSettingRecords(): ActiveQueryInterface
327
    {
328
        return $this->hasMany(OrganizationTypeSiteSettings::class, ['typeId' => 'id'])
329
            ->where([
330
                'siteId' => OrganizationPlugin::getInstance()->getSettings()->getEnabledSiteIds()
331
            ])
332
            ->indexBy('siteId');
333
    }
334
335
    /**
336
     * @inheritdoc
337
     */
338
    public function __toString()
339
    {
340
        return (string)$this->getAttribute('name');
341
    }
342
343
    /*******************************************
344
     * PROJECT CONFIG
345
     *******************************************/
346
347
    /**
348
     * Return an array suitable for Craft's Project config
349
     */
350
    public function toProjectConfig(): array
351
    {
352
        $siteSettings = [];
353
354
        foreach ($this->getSiteSettings() as $record) {
355
            $siteSettings[$record->getSite()->uid] = $record->toProjectConfig();
356
        }
357
358
        return array_merge(
359
            $this->toArray([
360
                'handle',
361
                'name'
362
            ]),
363
            [
364
                'fieldLayout' => array_merge(
365
                    ['uid' => $this->getFieldLayout()->uid],
366
                    $this->getFieldLayout()->getConfig()
367
                ),
368
                'siteSettings' => $siteSettings
369
            ]
370
        );
371
    }
372
}
373