Completed
Push — master ( 6f2475...9a35ef )
by Nate
16:01
created

Records::save()   B

Complexity

Conditions 5
Paths 7

Size

Total Lines 26
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 26
rs 8.439
c 0
b 0
f 0
cc 5
eloc 16
nc 7
nop 1
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\services;
10
11
use Craft;
12
use flipbox\ember\services\traits\records\Accessor;
13
use flipbox\organizations\events\ChangeStateEvent;
14
use flipbox\organizations\records\Organization as OrganizationRecord;
15
use yii\base\Component;
16
17
/**
18
 * @author Flipbox Factory <[email protected]>
19
 * @since 1.0.0
20
 *
21
 * @method OrganizationRecord create(array $attributes = [], string $toScenario = null)
22
 * @method OrganizationRecord find($identifier, string $toScenario = null)
23
 * @method OrganizationRecord get($identifier, string $toScenario = null)
24
 * @method OrganizationRecord findByCondition($condition = [], string $toScenario = null)
25
 * @method OrganizationRecord getByCondition($condition = [], string $toScenario = null)
26
 * @method OrganizationRecord findByCriteria($criteria = [], string $toScenario = null)
27
 * @method OrganizationRecord getByCriteria($criteria = [], string $toScenario = null)
28
 * @method OrganizationRecord[] findAllByCondition($condition = [], string $toScenario = null)
29
 * @method OrganizationRecord[] getAllByCondition($condition = [], string $toScenario = null)
30
 * @method OrganizationRecord[] findAllByCriteria($criteria = [], string $toScenario = null)
31
 * @method OrganizationRecord[] getAllByCriteria($criteria = [], string $toScenario = null)
32
 */
33
class Records extends Component
34
{
35
    use Accessor;
36
37
    /**
38
     * @event ChangeStateEvent The event that is triggered before a organization has a custom status change.
39
     *
40
     * You may set [[ChangeStateEvent::isValid]] to `false` to prevent the organization changing the status.
41
     */
42
    const EVENT_BEFORE_STATE_CHANGE = 'beforeStateChange';
43
44
    /**
45
     * @event ChangeStateEvent The event that is triggered after a organization has a custom status change.
46
     *
47
     * You may set [[ChangeStateEvent::isValid]] to `false` to prevent the organization changing the status.
48
     */
49
    const EVENT_AFTER_STATE_CHANGE = 'afterStateChange';
50
51
    /**
52
     * @inheritdoc
53
     */
54
    public static function recordClass(): string
55
    {
56
        return OrganizationRecord::class;
57
    }
58
59
    /**
60
     * @param OrganizationRecord $record
61
     * @return bool
62
     * @throws \Exception
63
     * @throws \yii\db\Exception
64
     */
65
    public function save(OrganizationRecord $record): bool
66
    {
67
        // Change state w/ events (see below)
68
        $changedState = $this->hasStateChanged($record);
69
70
        $transaction = Craft::$app->getDb()->beginTransaction();
71
        try {
72
            if (!$record->save()) {
73
                $transaction->rollBack();
74
                return false;
75
            }
76
77
            if (false !== $changedState &&
78
                true !== $this->changeState($record, $changedState)
79
            ) {
80
                $transaction->rollBack();
81
                return false;
82
            }
83
        } catch (\Exception $e) {
84
            $transaction->rollBack();
85
            throw $e;
86
        }
87
88
        $transaction->commit();
89
        return true;
90
    }
91
92
    /**
93
     * @param OrganizationRecord $record
94
     * @return false|string|null
95
     */
96
    private function hasStateChanged(OrganizationRecord $record)
97
    {
98
        if ($record->getIsNewRecord()) {
99
            return false;
100
        }
101
102
        if (!$record->isAttributeChanged('state', false)) {
103
            return false;
104
        }
105
106
        $oldState = $record->getOldAttribute('state');
107
        $newState = $record->getAttribute('state');
108
109
        // Revert record to old
110
        $record->setAttribute('state', $oldState);
111
112
        return $newState;
113
    }
114
115
116
    /**
117
     * @param OrganizationRecord $record
118
     * @param string|null $state
119
     * @return bool
120
     * @throws \Exception
121
     * @throws \yii\db\Exception
122
     */
123
    public function changeState(
124
        OrganizationRecord $record,
125
        string $state = null
126
    ): bool {
127
        $event = new ChangeStateEvent([
128
            'organization' => $record,
129
            'to' => $state
130
        ]);
131
132
        $this->trigger(
133
            static::EVENT_BEFORE_STATE_CHANGE,
134
            $event
135
        );
136
137
        if (!$event->isValid) {
138
            return false;
139
        }
140
141
        $transaction = Craft::$app->getDb()->beginTransaction();
142
        try {
143
            $record->state = $event->to;
144
145
            // Organization Record (status only)
146
            if (!$record->save(true, ['state'])) {
147
                $transaction->rollBack();
148
                return false;
149
            }
150
151
            // Trigger event
152
            $this->trigger(
153
                static::EVENT_AFTER_STATE_CHANGE,
154
                $event
155
            );
156
        } catch (\Exception $e) {
157
            $transaction->rollBack();
158
            throw $e;
159
        }
160
161
        $transaction->commit();
162
        return true;
163
    }
164
}
165