Organization::recordClass()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 0
cts 4
cp 0
rs 10
c 0
b 0
f 0
cc 1
eloc 2
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\organization\services;
10
11
use Craft;
12
use craft\db\Query;
13
use craft\elements\db\ElementQueryInterface;
14
use craft\elements\db\UserQuery;
15
use craft\elements\User as UserElement;
16
use craft\helpers\DateTimeHelper;
17
use craft\models\FieldLayout as FieldLayoutModel;
18
use craft\records\Element as ElementRecord;
19
use flipbox\organization\elements\db\Organization as OrganizationQuery;
20
use flipbox\organization\elements\Organization as OrganizationElement;
21
use flipbox\organization\events\ChangeOwner as ChangeOwnerEvent;
22
use flipbox\organization\events\ChangeStatus as ChangeStatusEvent;
23
use flipbox\organization\Organization as OrganizationPlugin;
24
use flipbox\organization\records\Organization as OrganizationRecord;
25
use flipbox\spark\helpers\ArrayHelper;
26
use flipbox\spark\helpers\RecordHelper;
27
use flipbox\spark\helpers\SiteHelper;
28
use flipbox\spark\services\Element as ElementService;
29
use flipbox\spark\services\traits\Element;
30
use yii\base\Exception;
31
32
/**
33
 * @author Flipbox Factory <[email protected]>
34
 * @since 1.0.0
35
 *
36
 * @method OrganizationElement|null find($identifier, int $siteId = null)
37
 * @method OrganizationElement get($identifier, int $siteId = null)
38
 * @method OrganizationElement|null findById(int $id, int $siteId = null)
39
 * @method OrganizationElement getById(int $id, int $siteId = null)
40
 */
41
class Organization extends ElementService
42
{
43
44
    use Element;
45
46
    /**
47
     * @inheritdoc
48
     */
49
    public static function elementClass(): string
50
    {
51
        return OrganizationElement::class;
52
    }
53
54
    /**
55
     * @inheritdoc
56
     */
57
    public static function recordClass(): string
58
    {
59
        return OrganizationRecord::class;
60
    }
61
62
    /**
63
     * @event ChangeStatusEvent The event that is triggered before a organization has a custom status change.
64
     *
65
     * You may set [[ChangeStatusEvent::isValid]] to `false` to prevent the organization changing the status.
66
     */
67
    const EVENT_BEFORE_STATUS_CHANGE = 'beforeStatusChange';
68
69
    /**
70
     * @event ChangeStatusEvent The event that is triggered after a organization has a custom status change.
71
     *
72
     * You may set [[ChangeStatusEvent::isValid]] to `false` to prevent the organization changing the status.
73
     */
74
    const EVENT_AFTER_STATUS_CHANGE = 'afterStatusChange';
75
76
    /**
77
     * @event ChangeOwnerEvent The event that is triggered before an organization ownership is transferred.
78
     *
79
     * You may set [[ChangeOwnerEvent::isValid]] to `false` to prevent the organization ownership
80
     * from getting transferred.
81
     */
82
    const EVENT_BEFORE_TRANSFER_OWNERSHIP = 'beforeOwnerChange';
83
84
    /**
85
     * @event ChangeOwnerEvent The event that is triggered after an organization ownership is transferred.
86
     *
87
     * You may set [[ChangeOwnerEvent::isValid]] to `false` to prevent the organization ownership
88
     * from getting transferred.
89
     */
90
    const EVENT_AFTER_TRANSFER_OWNERSHIP = 'afterOwnerChange';
91
92
    /**
93
     * @var array
94
     */
95
    private $statusesByOrganization = [];
96
97
98
    /*******************************************
99
     * STATUS
100
     *******************************************/
101
102
    /**
103
     * @return array
104
     */
105
    public function getStatuses(): array
106
    {
107
        return array_merge(
108
            [
109
                OrganizationElement::STATUS_ENABLED => Craft::t('organization', 'Active')
110
            ],
111
            OrganizationPlugin::getInstance()->getSettings()->getStatuses(),
112
            [
113
                OrganizationElement::STATUS_DISABLED => Craft::t('organization', 'Disabled')
114
            ]
115
        );
116
    }
117
    /**
118
     * @param $status
119
     * @return bool
120
     */
121
    public function isCustomStatus($status)
122
    {
123
124
        if (!is_string($status) || empty($status)) {
125
            return false;
126
        }
127
128
        return array_key_exists($status, OrganizationPlugin::getInstance()->getSettings()->getStatuses());
129
    }
130
131
132
    /*******************************************
133
     * SAVE
134
     *******************************************/
135
136
    /**
137
     * @param OrganizationElement $organization
138
     * @param bool $isNew
139
     * @throws Exception
140
     * @throws \Exception
141
     */
142
    public function beforeSave(OrganizationElement $organization, bool $isNew)
143
    {
144
145
        // Join Date
146
        if (empty($organization->dateJoined)) {
147
            $organization->dateJoined = DateTimeHelper::currentUTCDateTime();
148
        }
149
150
        if (!$isNew) {
151
152
            /** @var OrganizationRecord $recordClass */
153
            $recordClass = static::recordClass();
154
155
            $query = (new Query())
156
                ->select(['enabled', 'archived', 'status'])
157
                ->from([$recordClass::tableName() . ' ' . $recordClass::tableAlias()])
158
                ->innerJoin(
159
                    ElementRecord::tableName() . ' elements',
160
                    'elements.id = ' . $recordClass::tableAlias() . '.id'
161
                )
162
                ->andWhere(
163
                    [
164
                        'elements.id' => $organization->getId()
165
                    ]
166
                )->one();
167
168
            $currentStatus = $organization->getStatus();
169
            $existingStatus = $query['status'];
170
171
            // Quick logic to determine the status
172
            if (empty($existingStatus)) {
173
                $existingStatus = (!empty($query['archived']) ?
174
                    OrganizationElement::STATUS_ARCHIVED :
175
                    ($query['enabled'] ?
176
                        OrganizationElement::STATUS_ENABLED :
177
                        OrganizationElement::STATUS_DISABLED
178
                    )
179
                );
180
            }
181
182
            // If they don't match, store it and set the original.
183
            //  We'll handle changing the status on the after event.
184
            if ($currentStatus !== $existingStatus) {
185
                $this->statusesByOrganization[$organization->getId()] = $currentStatus;
186
                $organization->setStatus($existingStatus);
187
            }
188
        }
189
    }
190
191
    /**
192
     * @param OrganizationElement $organization
193
     * @param bool $isNew
194
     * @throws Exception
195
     * @throws \Exception
196
     */
197
    public function afterSave(OrganizationElement $organization, bool $isNew)
198
    {
199
200
        // Get the category record
201
        if (!$isNew) {
202
            $record = OrganizationRecord::findOne($organization->id);
203
204
            if (!$record) {
205
                throw new Exception('Invalid organization Id: ' . $organization->id);
206
            }
207
        } else {
208
            $record = new OrganizationRecord();
209
            $record->id = $organization->id;
210
        }
211
212
        $record->dateJoined = $organization->dateJoined;
213
214
        if ($isNew) {
215
            // Transfer element attribute(s) to record
216
            $record->status = $organization->getStatus();
217
218
            if (!$this->isCustomStatus(
219
                $record->status
220
            )
221
            ) {
222
                $record->status = null;
223
            }
224
225
            $record->ownerId = $organization->ownerId;
226
        }
227
228
        // Save the record
229
        if (!$record->save()) {
230
            $organization->addErrors($record->getErrors());
231
232
            Craft::error(
233
                $organization->getErrors(),
234
                __CLASS__
235
            );
236
237
            throw new Exception('Unable to save record');
238
        }
239
240
        // Transfer id to the new records
241
        if ($isNew) {
242
            $organization->id = $record->id;
243
            $organization->dateCreated = DateTimeHelper::toDateTime($record->dateCreated);
0 ignored issues
show
Documentation Bug introduced by
It seems like \craft\helpers\DateTimeH...e($record->dateCreated) can also be of type false. However, the property $dateCreated is declared as type object<DateTime>|null. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
244
        }
245
        $organization->dateUpdated = DateTimeHelper::toDateTime($record->dateUpdated);
0 ignored issues
show
Documentation Bug introduced by
It seems like \craft\helpers\DateTimeH...e($record->dateUpdated) can also be of type false. However, the property $dateUpdated is declared as type object<DateTime>|null. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
246
247
        if (!$isNew) {
248
            // Change status
249
            $status = $organization->getStatus();
250
251
            $toStatus = ArrayHelper::remove(
252
                $this->statusesByOrganization,
253
                $organization->getId(),
254
                $status
255
            );
256
257
            if ($status !== $toStatus) {
258
                // Change status
259
                if (!$this->changeStatus($organization, $toStatus)) {
260
                    // Add error
261
                    $organization->addError(
262
                        'status',
263
                        Craft::t('organization', 'Unable to change status.')
264
                    );
265
266
                    throw new Exception("Unable to change status.");
267
                }
268
            }
269
270
            // The owner we're changing to
271
            $toOwner = $organization->ownerId;
272
            if ($record->ownerId !== $toOwner) {
273
                // Revert element to old owner
274
                $organization->ownerId = $record->ownerId;
275
276
                // Change owner
277
                if (!$this->transferOwner($organization, $toOwner)) {
278
                    // Add error
279
                    $organization->addError(
280
                        'ownerId',
281
                        Craft::t('organization', 'Unable to change owner.')
282
                    );
283
284
                    throw new Exception("Unable to change owner.");
285
                }
286
            }
287
        }
288
289
        // Save organization types
290
        if (!$this->associateTypes($organization)) {
291
            // Add error
292
            $organization->addError(
293
                'types',
294
                Craft::t('organization', 'Unable to save types.')
295
            );
296
297
            throw new Exception("Unable to save types.");
298
        }
299
300
        // Save organization users
301
        if (!$this->associateUsers($organization)) {
302
            // Add error
303
            $organization->addError(
304
                'users',
305
                Craft::t('organization', 'Unable to save users.')
306
            );
307
308
            throw new Exception("Unable to save users.");
309
        }
310
    }
311
312
313
    /*******************************************
314
     * USER QUERY
315
     *******************************************/
316
317
    /**
318
     * @param OrganizationElement $organization
319
     * @param array $criteria
320
     * @param bool $match
321
     * @return UserQuery
322
     */
323
    public function getMemberQuery(OrganizationElement $organization, $criteria = [], bool $match = true)
324
    {
325
        return OrganizationPlugin::getInstance()->getUser()->getMemberQuery(
326
            ($match ? '' : 'not ') .
327
            $organization->id ?: 'x',
328
            $criteria
329
        );
330
    }
331
332
    /**
333
     * @param OrganizationElement $organization
334
     * @param array $criteria
335
     * @param bool $match
336
     * @return UserQuery
337
     */
338
    public function getUserQuery(OrganizationElement $organization, $criteria = [], bool $match = true)
339
    {
340
        return OrganizationPlugin::getInstance()->getUser()->getUserQuery(
341
            ($match ? '' : 'not ') .
342
            $organization->id ?: 'x',
343
            $criteria
344
        );
345
    }
346
347
    /**
348
     * @param OrganizationElement $organization
349
     * @param array $criteria
350
     * @param bool $match
351
     * @return UserQuery
352
     */
353
    public function getOwnerQuery(OrganizationElement $organization, $criteria = [], bool $match = true)
354
    {
355
        return OrganizationPlugin::getInstance()->getUser()->getOwnerQuery(
356
            ($match ? '' : 'not ') .
357
            $organization->id ?: 'x',
358
            $criteria
359
        );
360
    }
361
362
363
    /*******************************************
364
     * UTILITY
365
     *******************************************/
366
367
    /**
368
     * @param UserElement $user
369
     * @param OrganizationElement $organization
370
     * @param array $criteria
371
     * @param bool $match
372
     * @return bool
373
     */
374
    public function isUser(UserElement $user, OrganizationElement $organization, $criteria = [], bool $match = true)
375
    {
376
377
        // User query
378
        $emails = $this->getUserQuery($organization, $criteria, $match)
379
            ->select(['users.email'])
380
            ->column();
381
382
        return in_array($user->email, $emails);
383
    }
384
385
    /**
386
     * @param UserElement $user
387
     * @param OrganizationElement $organization
388
     * @param array $criteria
389
     * @param bool $match
390
     * @return bool
391
     */
392
    public function isOwner(UserElement $user, OrganizationElement $organization, $criteria = [], bool $match = true)
393
    {
394
395
        // User query
396
        $emails = $this->getOwnerQuery($organization, $criteria, $match)
397
            ->select(['users.email'])
398
            ->column();
399
400
        return in_array($user->email, $emails);
401
    }
402
403
    /**
404
     * @param UserElement $user
405
     * @param OrganizationElement $organization
406
     * @param array $criteria
407
     * @param bool $match
408
     * @return bool
409
     */
410
    public function isMember(UserElement $user, OrganizationElement $organization, $criteria = [], bool $match = true)
411
    {
412
413
        // User query
414
        $emails = $this->getMemberQuery($organization, $criteria, $match)
415
            ->select(['users.email'])
416
            ->column();
417
418
        return in_array($user->email, $emails);
419
    }
420
421
422
    /*******************************************
423
     * QUERY
424
     *******************************************/
425
426
    /**
427
     * @inheritdoc
428
     * @return ElementQueryInterface|OrganizationQuery
429
     */
430
    public function getQuery($criteria = [])
431
    {
432
        return parent::getQuery($criteria);
433
    }
434
435
436
    /*******************************************
437
     * POPULATE (from Request)
438
     *******************************************/
439
440
    /**
441
     * @param OrganizationElement $organization
442
     */
443
    public function populateFromRequest(OrganizationElement $organization)
444
    {
445
446
        $request = Craft::$app->getRequest();
447
448
        // Set the entry attributes, defaulting to the existing values for whatever is missing from the post data
449
        $organization->slug = $request->getBodyParam('slug', $organization->slug);
450
451
        // Enabled
452
        $organization->enabledForSite = (bool)$request->getBodyParam(
453
            'enabledForSite',
454
            $organization->enabledForSite
455
        );
456
        $organization->title = $request->getBodyParam('title', $organization->title);
457
458
        // Status
459
        $organization->setStatus(
460
            $request->getBodyParam('status', $organization->getStatus())
461
        );
462
463
        // Join date
464
        $this->populateDateFromRequest($organization, 'dateJoined');
465
466
        // Active type
467
        $this->populateActiveTypeFromRequest($organization);
468
469
        // Owner
470
        $this->populateOwnerFromRequest($organization);
471
472
        // Set types
473
        $organization->setTypesFromRequest(
474
            $request->getParam('typesLocation', 'types')
475
        );
476
477
        // Set users
478
        $organization->setUsersFromRequest(
479
            $request->getParam('usersLocation', 'users')
480
        );
481
482
        // Set content
483
        $organization->setFieldValuesFromRequest(
484
            $request->getParam('fieldsLocation', 'fields')
485
        );
486
    }
487
488
    /**
489
     * @param OrganizationElement $organization
490
     * @param string $dateProperty
491
     */
492
    private function populateDateFromRequest(OrganizationElement $organization, string $dateProperty)
493
    {
494
        $dateTime = DateTimeHelper::toDateTime(
495
            Craft::$app->getRequest()->getBodyParam($dateProperty, $organization->{$dateProperty})
496
        );
497
        $organization->{$dateProperty} = $dateTime === false ? null : $dateTime;
498
    }
499
500
    /**
501
     * @param OrganizationElement $organization
502
     */
503
    private function populateActiveTypeFromRequest(OrganizationElement $organization)
504
    {
505
506
        $type = null;
507
        if ($typeId = Craft::$app->getRequest()->getBodyParam('type', null)) {
508
            $type = OrganizationPlugin::getInstance()->getType()->get($typeId);
509
        }
510
        $organization->setActiveType($type);
511
    }
512
513
    /**
514
     * @param OrganizationElement $organization
515
     */
516
    private function populateOwnerFromRequest(OrganizationElement $organization)
517
    {
518
519
        $ownerId = Craft::$app->getRequest()->getBodyParam(
520
            'owner',
521
            $organization->ownerId
522
        );
523
        if (is_array($ownerId)) {
524
            $ownerId = ArrayHelper::firstValue($ownerId);
525
        }
526
        $organization->ownerId = $ownerId;
527
    }
528
529
530
    /*******************************************
531
     * TYPES - ASSOCIATE and/or DISASSOCIATE
532
     *******************************************/
533
534
    /**
535
     * @param OrganizationElement $organizationElement
536
     * @return bool
537
     * @throws \Exception
538
     */
539
    protected function associateTypes(OrganizationElement $organizationElement)
540
    {
541
542
        // Db transaction
543
        $transaction = RecordHelper::beginTransaction();
544
545
        try {
546
            // Primary type (previously saved?)
547
            $primaryType = $organizationElement->getPrimaryType();
548
549
            // All types
550
            $currentTypes = $organizationElement->getTypes();
551
552
            // Existing types
553
            $existingTypes = ArrayHelper::index(
554
                OrganizationPlugin::getInstance()->getType()->findAllByOrganization($organizationElement),
555
                'id'
556
            );
557
558
            // Verify primary type is still valid
559
            if ($primaryType) {
560
                if (!array_key_exists($primaryType->id, $currentTypes)) {
561
                    $primaryType = null;
562
                }
563
            }
564
565
            $count = 0;
566
            foreach ($currentTypes as $currentType) {
567
                if (null !== ArrayHelper::remove($existingTypes, $currentType->id)) {
568
                    continue;
569
                }
570
571
                // If primary isn't already set, and it's the first one
572
                $isPrimary = (0 === $count++ && empty($primaryType));
573
574
                // Associate
575
                if (!OrganizationPlugin::getInstance()->getType()->associate(
576
                    $currentType,
577
                    $organizationElement,
578
                    $isPrimary
579
                )
580
                ) {
581
                    // Roll back on failures
582
                    $transaction->rollBack();
583
584
                    return false;
585
                }
586
            }
587
588
            foreach ($existingTypes as $currentType) {
589
                // Dissociate
590
                if (!OrganizationPlugin::getInstance()->getType()->dissociate(
591
                    $currentType,
592
                    $organizationElement
593
                )
594
                ) {
595
                    // Roll back on failures
596
                    $transaction->rollBack();
597
598
                    return false;
599
                }
600
            }
601
        } catch (\Exception $e) {
602
            // Roll back on failures
603
            $transaction->rollBack();
604
605
            throw $e;
606
        }
607
608
        // commit db actions (success)
609
        $transaction->commit();
610
611
        return true;
612
    }
613
614
    /*******************************************
615
     * USERS - ASSOCIATE and/or DISASSOCIATE
616
     *******************************************/
617
618
    /**
619
     * @param OrganizationElement $organizationElement
620
     * @param int|null $siteId
621
     * @return bool
622
     * @throws \Exception
623
     */
624
    protected function associateUsers(OrganizationElement $organizationElement, int $siteId = null)
625
    {
626
627
        /** @var UserQuery $query */
628
        $query = $organizationElement->getUsers();
629
630
        // Only perform save if we have cached result (meaning it was may have changed)
631
        if ($query->getCachedResult() === null) {
632
            return true;
633
        }
634
635
        // Db transaction
636
        $transaction = Craft::$app->getDb()->beginTransaction();
637
638
        try {
639
            // Find all currently associated and index by userId
640
            $existingUsers = $this->getUserQuery(
641
                $organizationElement,
642
                [
643
                    'status' => null,
644
                    'indexBy' => 'id'
645
                ]
646
            )->all();
647
648
            // Get array of associated users (index by email -> so we don't have dupes)
649
            $currentUsers = ArrayHelper::index(
650
                $query->getCachedResult(),
651
                'email'
652
            );
653
654
            // Exclude owner
655
            if ($organizationElement->hasOwner()) {
656
                ArrayHelper::remove($currentUsers, $organizationElement->getOwner()->email);
657
            }
658
659
            /**
660
             * @var string $key
661
             * @var UserElement $currentUser
662
             */
663
            foreach ($currentUsers as $key => $currentUser) {
664
                if (!$currentUser->getId() &&
665
                    !Craft::$app->getElements()->saveElement($currentUser)
666
                ) {
667
                    // Roll back on failures
668
                    $transaction->rollBack();
669
670
                    return false;
671
                }
672
673
                // Only associate if they are new
674
                if (null !== ArrayHelper::remove($existingUsers, $currentUser->getId())) {
675
                    continue;
676
                }
677
678
                // Otherwise, associate
679
                if (!OrganizationPlugin::getInstance()->getUser()->associate(
680
                    $currentUser,
681
                    $organizationElement,
682
                    $siteId
683
                )
684
                ) {
685
                    // Roll back on failures
686
                    $transaction->rollBack();
687
688
                    return false;
689
                }
690
            }
691
692
            foreach ($existingUsers as $key => $existingUser) {
693
                // Dissociate
694
                if (!OrganizationPlugin::getInstance()->getUser()->dissociate(
695
                    $existingUser,
696
                    $organizationElement
697
                )
698
                ) {
699
                    // Roll back on failures
700
                    $transaction->rollBack();
701
702
                    return false;
703
                }
704
            }
705
        } catch (\Exception $e) {
706
            // Roll back on failures
707
            $transaction->rollBack();
708
709
            throw $e;
710
        }
711
712
        // commit db actions (success)
713
        $transaction->commit();
714
715
        return true;
716
    }
717
718
719
    /*******************************************
720
     * STATUS
721
     *******************************************/
722
723
    /**
724
     * @param OrganizationElement $element
725
     * @param $status
726
     * @return bool
727
     * @throws \Exception
728
     * @throws \yii\db\Exception
729
     */
730
    public function changeStatus(
731
        OrganizationElement $element,
732
        $status
733
    ) {
734
    
735
736
        // The before event
737
        $event = new ChangeStatusEvent([
738
            'organization' => $element,
739
            'fromStatus' => $element->getStatus(),
740
            'toStatus' => $status
741
        ]);
742
743
        // Trigger event
744
        $this->trigger(
745
            static::EVENT_BEFORE_STATUS_CHANGE,
746
            $event
747
        );
748
749
        // Green light?
750
        if (!$event->isValid) {
751
            return false;
752
        }
753
754
        // Db transaction
755
        $transaction = RecordHelper::beginTransaction();
756
757
        try {
758
759
            /** @var OrganizationRecord $record */
760
            $record = $this->getRecordByCondition([
761
                'id' => $element->id
762
            ]);
763
764
            // Set status
765
            $record->status = $this->isCustomStatus($status) ? $status : null;
766
767
            // Validate record (status only)
768
            if (!$record->validate('status')) {
0 ignored issues
show
Documentation introduced by
'status' is of type string, but the function expects a array|null.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
769
                // Transfer errors
770
                $element->addErrors($record->getErrors());
771
772
                // Roll back on failures
773
                $transaction->rollBack();
774
775
                return false;
776
            }
777
778
            // Organization status
779
            Craft::$app->getDb()->createCommand()->update(
780
                $record::tableName(),
781
                ['status' => $record->status],
782
                ['id' => $element->id]
783
            )->execute();
784
785
            // Element status
786
            switch ($status) {
787
                case OrganizationElement::STATUS_ARCHIVED:
788
                    $condition = [
789
                        'enabled' => 0,
790
                        'archived' => 1,
791
                    ];
792
                    break;
793
794
                case OrganizationElement::STATUS_DISABLED:
795
                    $condition = [
796
                        'enabled' => 0,
797
                        'archived' => 0,
798
                    ];
799
                    break;
800
801
                default:
802
                    $condition = [
803
                        'enabled' => 1,
804
                        'archived' => 0,
805
                    ];
806
                    break;
807
            }
808
809
            Craft::$app->getDb()->createCommand()->update(
810
                ElementRecord::tableName(),
811
                $condition,
812
                ['id' => $element->id]
813
            )->execute();
814
815
            // Transfer record attribute(s) to element
816
            $element->setStatus($status);
817
818
            // Trigger event
819
            $this->trigger(
820
                static::EVENT_AFTER_STATUS_CHANGE,
821
                $event
822
            );
823
824
            // Green light?
825
            if (!$event->isValid) {
826
                // Roll back on failures
827
                $transaction->rollBack();
828
829
                return false;
830
            }
831
        } catch (\Exception $e) {
832
            // Roll back on failures
833
            $transaction->rollBack();
834
835
            throw $e;
836
        }
837
838
        // Commit db transaction
839
        $transaction->commit();
840
841
        return true;
842
    }
843
844
    /*******************************************
845
     * OWNER
846
     *******************************************/
847
848
    /**
849
     * @param OrganizationElement $element
850
     * @param $newOwnerId
851
     * @return bool
852
     * @throws \Exception
853
     * @throws \yii\db\Exception
854
     */
855
    public function transferOwner(
856
        OrganizationElement $element,
857
        $newOwnerId
858
    ) {
859
    
860
861
        // The event
862
        $event = new ChangeOwnerEvent([
863
            'organization' => $element,
864
            'fromOwner' => $element->getOwner(),
865
            'toOwner' => $newOwnerId
866
        ]);
867
868
        // Trigger event
869
        $this->trigger(
870
            static::EVENT_BEFORE_TRANSFER_OWNERSHIP,
871
            $event
872
        );
873
874
        // Green light?
875
        if (!$event->isValid) {
876
            return false;
877
        }
878
879
        // Db transaction
880
        $transaction = Craft::$app->getDb()->beginTransaction();
881
882
        try {
883
            // Get record (or throw an Exception)
884
            /** @var OrganizationRecord $record */
885
            $record = $this->getRecordByCondition([
886
                'id' => $element->id
887
            ]);
888
889
            // Set owner
890
            $record->ownerId = $newOwnerId;
891
892
            // Validate record (status only)
893
            if (!$record->save(true, ['ownerId'])) {
894
                // Transfer errors
895
                $element->addErrors($record->getErrors());
896
897
                // Roll back on failures
898
                $transaction->rollBack();
899
900
                return false;
901
            }
902
903
            // Transfer record attribute(s) to element
904
            $element->ownerId = $record->ownerId;
905
906
            // Trigger event
907
            $this->trigger(
908
                static::EVENT_AFTER_TRANSFER_OWNERSHIP,
909
                $event
910
            );
911
912
            // Green light?
913
            if (!$event->isValid) {
914
                // Roll back on failures
915
                $transaction->rollBack();
916
917
                return false;
918
            }
919
        } catch (\Exception $e) {
920
            // Roll back on failures
921
            $transaction->rollBack();
922
923
            throw $e;
924
        }
925
926
        // Commit db transaction
927
        $transaction->commit();
928
929
        return true;
930
    }
931
932
    /*******************************************
933
     * UTILITIES
934
     *******************************************/
935
936
    /**
937
     * @param int|null $siteId
938
     * @return FieldLayoutModel
939
     */
940
    public function getDefaultFieldLayout(int $siteId = null)
941
    {
942
        return OrganizationPlugin::getInstance()->getSettings()->getSite(
943
            SiteHelper::resolveSiteId($siteId)
944
        )->getFieldLayout();
945
    }
946
}
947