ModelSave   A
last analyzed

Complexity

Total Complexity 15

Size/Duplication

Total Lines 152
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 8

Test Coverage

Coverage 0%

Importance

Changes 0
Metric Value
wmc 15
lcom 1
cbo 8
dl 0
loc 152
ccs 0
cts 69
cp 0
rs 10
c 0
b 0
f 0

5 Methods

Rating   Name   Duplication   Size   Complexity  
toRecord() 0 1 ?
C save() 0 80 9
A beforeSave() 0 4 1
A afterSave() 0 8 1
A transferFromRecord() 0 14 4
1
<?php
2
3
/**
4
 * @copyright  Copyright (c) Flipbox Digital Limited
5
 * @license    https://github.com/flipbox/spark/blob/master/LICENSE
6
 * @link       https://github.com/flipbox/spark
7
 */
8
9
namespace flipbox\spark\services\traits;
10
11
use Craft;
12
use craft\events\ModelEvent;
13
use flipbox\spark\helpers\RecordHelper;
14
use flipbox\spark\models\Model;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, flipbox\spark\services\traits\Model.

Let’s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let’s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
15
use flipbox\spark\models\ModelWithId;
16
use flipbox\spark\records\Record;
17
use flipbox\spark\records\RecordWithId;
18
19
/**
20
 * @author Flipbox Factory <[email protected]>
21
 * @since 1.0.0
22
 */
23
trait ModelSave
24
{
25
26
    /*******************************************
27
     * ABSTRACTS
28
     *******************************************/
29
30
    /**
31
     * @param Model $model
32
     * @param bool $mirrorScenario
33
     * @return Record
34
     */
35
    abstract protected function toRecord(Model $model, bool $mirrorScenario = true): Record;
36
37
38
    /*******************************************
39
     * SAVE
40
     *******************************************/
41
42
    /**
43
     * @param Model $model
44
     * @param bool $runValidation
45
     * @param null $attributes
46
     * @param bool $mirrorScenario
47
     * @return bool
48
     * @throws \Exception
49
     */
50
    public function save(Model $model, bool $runValidation = true, $attributes = null, bool $mirrorScenario = true)
51
    {
52
53
        // Validate
54
        if ($runValidation && !$model->validate($attributes)) {
55
            Craft::info('Model not saved due to validation error.', __METHOD__);
56
            return false;
57
        }
58
59
        $isNew = $model->isNew();
60
61
        // a 'beforeSave' event
62
        if (!$this->beforeSave($model, $isNew)) {
63
            return false;
64
        }
65
66
        // Create event
67
        $event = new ModelEvent([
68
            'isNew' => $isNew
69
        ]);
70
71
        // Db transaction
72
        $transaction = RecordHelper::beginTransaction();
73
74
        try {
75
            // The 'before' event
76
            if (!$model->beforeSave($event)) {
77
                $transaction->rollBack();
78
79
                return false;
80
            }
81
82
            $record = $this->toRecord($model, $mirrorScenario);
83
84
            // Validate
85
            if (!$record->validate($attributes)) {
86
                $model->addErrors($record->getErrors());
87
88
                $transaction->rollBack();
89
90
                return false;
91
            }
92
93
            // Insert record
94
            if (!$record->save($attributes)) {
0 ignored issues
show
Documentation introduced by
$attributes is of type null, but the function expects a boolean.

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...
95
                // Transfer errors to model
96
                $model->addErrors($record->getErrors());
97
98
                $transaction->rollBack();
99
100
                return false;
101
            }
102
103
            // Transfer attributes to model
104
            $this->transferFromRecord(
105
                $model,
106
                $record,
107
                $isNew
108
            );
109
110
111
            // The 'after' event
112
            if (!$model->afterSave($event)) {
113
                $transaction->rollBack();
114
115
                return false;
116
            }
117
        } catch (\Exception $e) {
118
            $transaction->rollBack();
119
120
            throw $e;
121
        }
122
123
        $transaction->commit();
124
125
        // an 'afterSave' event
126
        $this->afterSave($model, $isNew);
127
128
        return true;
129
    }
130
131
    /**
132
     * @param Model $model
133
     * @param bool $isNew
134
     * @return bool
135
     */
136
    protected function beforeSave(Model $model, bool $isNew): bool
0 ignored issues
show
Unused Code introduced by
The parameter $model is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $isNew is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
137
    {
138
        return true;
139
    }
140
141
    /**
142
     * @param Model $model
143
     * @param bool $isNew
144
     */
145
    protected function afterSave(Model $model, bool $isNew)
0 ignored issues
show
Unused Code introduced by
The parameter $isNew is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
146
    {
147
148
        Craft::info(sprintf(
149
            "Model '%s' was saved successfully.",
150
            (string)get_class($model)
151
        ), __METHOD__);
152
    }
153
154
    /**
155
     * @param Model $model
156
     * @param Record $record
157
     * @param bool $isNew
158
     * @return void
159
     */
160
    protected function transferFromRecord(Model $model, Record $record, bool $isNew)
161
    {
162
163
        // Transfer record to model
164
        if ($isNew) {
165
            if ($model instanceof ModelWithId && $record instanceof RecordWithId) {
166
                $model->id = $record->id;
167
            }
168
169
            $model->dateCreated = $record->dateCreated;
170
            $model->uid = $record->uid;
171
        }
172
        $model->dateUpdated = $record->dateUpdated;
173
    }
174
}
175