Completed
Push — master ( b27204...a2c64d )
by Nate
05:15 queued 02:48
created

OrganizationType::afterSave()   B

Complexity

Conditions 6
Paths 16

Size

Total Lines 39

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 42

Importance

Changes 0
Metric Value
dl 0
loc 39
ccs 0
cts 29
cp 0
rs 8.6737
c 0
b 0
f 0
cc 6
nc 16
nop 2
crap 42
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 parentResolveFieldLayout;
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->parentResolveFieldLayout())) {
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
     * EVENTS
84
     *******************************************/
85
86
    /**
87
     * @inheritdoc
88
     * @throws Exception
89
     */
90
    public function beforeSave($insert)
91
    {
92
        if (false === parent::beforeSave($insert)) {
93
            return false;
94
        }
95
96
        $fieldLayout = $this->getFieldLayout();
97
98
        // Get old field layout (and delete it if necessary)
99
        $oldFieldLayoutId = (int)$this->getOldAttribute('fieldLayoutId');
100
        if ($oldFieldLayoutId != $fieldLayout->id &&
101
            $oldFieldLayoutId != $this->getDefaultFieldLayoutId()
102
        ) {
103
            Craft::$app->getFields()->deleteLayoutById($oldFieldLayoutId);
104
        }
105
106
        if (!Craft::$app->getFields()->saveLayout($fieldLayout)) {
107
            return false;
108
        }
109
110
        // Set the attribute (just to ensure)
111
        $this->fieldLayoutId = $fieldLayout->id;
112
113
        return true;
114
    }
115
116
    /**
117
     * @return int
118
     */
119
    protected function getDefaultFieldLayoutId(): int
120
    {
121
        return (int)OrganizationPlugin::getInstance()->getSettings()->getFieldLayout()->id;
122
    }
123
124
    /**
125
     * @inheritdoc
126
     * @throws Exception
127
     * @throws \Throwable
128
     * @throws \craft\errors\SiteNotFoundException
129
     * @throws \yii\db\StaleObjectException
130
     */
131
    public function afterSave($insert, $changedAttributes)
132
    {
133
        $successful = true;
134
135
        /** @var OrganizationTypeSiteSettings[] $allSettings */
136
        $allSettings = $this->hasMany(OrganizationTypeSiteSettings::class, ['typeId' => 'id'])
137
            ->indexBy('siteId')
138
            ->all();
139
140
        foreach ($this->getSiteSettings() as $model) {
141
            ArrayHelper::remove($allSettings, $model->siteId);
142
            $model->typeId = $this->getId();
143
144
            if (!$model->save()) {
145
                $successful = false;
146
                // Log the errors
147
                $error = Craft::t(
148
                    'organizations',
149
                    "Couldn't save site settings due to validation errors:"
150
                );
151
                foreach ($model->getFirstErrors() as $attributeError) {
152
                    $error .= "\n- " . Craft::t('organizations', $attributeError);
153
                }
154
155
                $this->addError('sites', $error);
156
            }
157
        }
158
159
        // Delete old settings records
160
        foreach ($allSettings as $settings) {
161
            $settings->delete();
162
        }
163
164
        if (!$successful) {
165
            throw new Exception("Unable to save site settings");
166
        };
167
168
        parent::afterSave($insert, $changedAttributes);
169
    }
170
171
172
173
    /*******************************************
174
     * SITE SETTINGS
175
     *******************************************/
176
177
    /**
178
     * @return OrganizationTypeSiteSettings[]
179
     * @throws \craft\errors\SiteNotFoundException
180
     */
181
    public function getSiteSettings(): array
182
    {
183
        if (empty($this->siteSettingRecords)) {
184
            $this->addPrimarySiteSettings();
185
        }
186
187
        return $this->siteSettingRecords;
188
    }
189
190
    /**
191
     * @param array $siteSettings
192
     * @return $this
193
     */
194
    public function setSiteSettings(array $siteSettings = [])
195
    {
196
        foreach ($siteSettings as $siteId => &$site) {
197
            $site = $this->resolveSiteSettings($siteId, $site);
198
        }
199
200
        $this->populateRelation('siteSettingRecords', $siteSettings);
201
        return $this;
202
    }
203
204
    /**
205
     * @return $this
206
     * @throws \craft\errors\SiteNotFoundException
207
     */
208
    protected function addPrimarySiteSettings()
209
    {
210
        $primarySite = Craft::$app->getSites()->getPrimarySite();
211
212
        if ($primarySite->id !== null) {
213
            $this->addSiteSettings($primarySite->id, ['site' => $primarySite]);
214
        }
215
216
        return $this;
217
    }
218
219
    /**
220
     * @param int $siteId
221
     * @param $site
222
     * @return OrganizationTypeSiteSettings
223
     */
224
    protected function resolveSiteSettings(int $siteId, $site): OrganizationTypeSiteSettings
225
    {
226
        if (!$record = $this->siteSettingRecords[$siteId] ?? null) {
227
            $record = new OrganizationTypeSiteSettings();
228
        }
229
230
        /** @noinspection PhpIncompatibleReturnTypeInspection */
231
        return ObjectHelper::populate(
232
            $record,
233
            $site
234
        );
235
    }
236
237
    /**
238
     * @param int $siteId
239
     * @param $site
240
     * @return $this
241
     */
242
    protected function addSiteSettings(int $siteId, $site)
243
    {
244
        $site = $this->resolveSiteSettings($siteId, $site);
245
        $this->populateRelation('siteSettingRecords', (
246
            $this->siteSettingRecords +
247
            [
248
                $site->getSiteId() => $site
249
            ]
250
        ));
251
252
        return $this;
253
    }
254
255
256
    /**
257
     * @inheritdoc
258
     */
259
    public function rules()
260
    {
261
        return array_merge(
262
            parent::rules(),
263
            $this->handleRules(),
264
            $this->fieldLayoutRules(),
265
            [
266
                [
267
                    [
268
                        'name'
269
                    ],
270
                    'required'
271
                ],
272
                [
273
                    [
274
                        'siteSettings'
275
                    ],
276
                    ModelValidator::class
277
                ],
278
                [
279
                    [
280
                        'name',
281
                    ],
282
                    'string',
283
                    'max' => 255
284
                ],
285
                [
286
                    [
287
                        'handle'
288
                    ],
289
                    UniqueValidator::class
290
                ]
291
            ]
292
        );
293
    }
294
295
    /**
296
     * @return array
297
     */
298
    public function attributeLabels()
299
    {
300
        return array_merge(
301
            parent::attributeLabels(),
302
            $this->fieldLayoutAttributeLabels()
303
        );
304
    }
305
306
    /**
307
     * @return ActiveQueryInterface
308
     * @throws \craft\errors\SiteNotFoundException
309
     */
310
    protected function getSiteSettingRecords(): ActiveQueryInterface
311
    {
312
        return $this->hasMany(OrganizationTypeSiteSettings::class, ['typeId' => 'id'])
313
            ->where([
314
                'siteId' => OrganizationPlugin::getInstance()->getSettings()->getEnabledSiteIds()
315
            ])
316
            ->indexBy('siteId');
317
    }
318
319
    /**
320
     * @inheritdoc
321
     */
322
    public function __toString()
323
    {
324
        return (string)$this->getAttribute('name');
325
    }
326
}
327