Completed
Push — master ( e1c530...93bd80 )
by Nekrasov
01:25
created

D7Model::save()   B

Complexity

Conditions 4
Paths 4

Size

Total Lines 22
Code Lines 16

Duplication

Lines 6
Ratio 27.27 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
dl 6
loc 22
rs 8.9197
c 1
b 0
f 0
cc 4
eloc 16
nc 4
nop 1
1
<?php
2
3
namespace Arrilot\BitrixModels\Models;
4
5
use Arrilot\BitrixModels\Adapters\D7Adapter;
6
use Arrilot\BitrixModels\Exceptions\ExceptionFromBitrix;
7
use Arrilot\BitrixModels\Queries\D7Query;
8
use Illuminate\Support\Collection;
9
use LogicException;
10
11
/**
12
 * static int count()
13
 *
14
 * D7Query methods
15
 * @method static D7Query runtime(array|\Bitrix\Main\Entity\ExpressionField $fields)
16
 * @method static D7Query enableDataDoubling()
17
 * @method static D7Query disableDataDoubling()
18
 * @method static D7Query cacheJoins(bool $value)
19
 *
20
 * BaseQuery methods
21
 * @method static Collection getList()
22
 * @method static D7Model first()
23
 * @method static D7Model getById(int $id)
24
 * @method static D7Query sort(string|array $by, string $order='ASC')
25
 * @method static D7Query order(string|array $by, string $order='ASC') // same as sort()
26
 * @method static D7Query filter(array $filter)
27
 * @method static D7Query addFilter(array $filters)
28
 * @method static D7Query resetFilter()
29
 * @method static D7Query navigation(array $filter)
30
 * @method static D7Query select($value)
31
 * @method static D7Query keyBy(string $value)
32
 * @method static D7Query limit(int $value)
33
 * @method static D7Query offset(int $value)
34
 * @method static D7Query page(int $num)
35
 * @method static D7Query take(int $value) // same as limit()
36
 * @method static D7Query forPage(int $page, int $perPage=15)
37
 * @method static \Illuminate\Pagination\LengthAwarePaginator paginate(int $perPage = 15, string $pageName = 'page')
38
 * @method static \Illuminate\Pagination\Paginator simplePaginate(int $perPage = 15, string $pageName = 'page')
39
 * @method static D7Query stopQuery()
40
 * @method static D7Query cache(float|int $minutes)
41
 */
42
class D7Model extends BaseBitrixModel
43
{
44
    const TABLE_CLASS = null;
45
46
    /**
47
     * @var null|string
48
     */
49
    protected static $cachedTableClass = null;
50
51
    /**
52
     * Adapter to interact with Bitrix D7 API.
53
     *
54
     * @var D7Adapter
55
     */
56
    protected static $adapter;
57
58
    /**
59
     * Constructor.
60
     *
61
     * @param $id
62
     * @param $fields
63
     */
64
    public function __construct($id = null, $fields = null)
65
    {
66
        $this->id = $id;
67
        $this->fill($fields);
68
        static::instantiateAdapter();
69
    }
70
    
71
    /**
72
     * Setter for adapter (for testing)
73
     * @param $adapter
74
     */
75
    public static function setAdapter($adapter)
76
    {
77
        static::$adapter = $adapter;
78
    }
79
80
    /**
81
     * Instantiate adapter if it's not instantiated.
82
     *
83
     * @return D7Adapter
84
     */
85
    public static function instantiateAdapter()
86
    {
87
        if (static::$adapter) {
88
            return static::$adapter;
89
        }
90
91
        return static::$adapter = new D7Adapter(static::cachedTableClass());
92
    }
93
94
    /**
95
     * Instantiate a query object for the model.
96
     *
97
     * @return D7Query
98
     */
99
    public static function query()
100
    {
101
        return new D7Query(static::instantiateAdapter(), get_called_class());
102
    }
103
    
104
    /**
105
     * @return string
106
     * @throws LogicException
107
     */
108
    public static function tableClass()
109
    {
110
        $tableClass = static::TABLE_CLASS;
111
        if (!$tableClass) {
112
            throw new LogicException('You must set TABLE_CLASS constant inside a model or override tableClass() method');
113
        }
114
    
115
        return $tableClass;
116
    }
117
118
    /**
119
     * Cached version of table class.
120
     *
121
     * @return string
122
     */
123
    public static function cachedTableClass()
124
    {
125
        if (is_null(static::$cachedTableClass)) {
126
            static::$cachedTableClass = static::tableClass();
127
        }
128
129
        return static::$cachedTableClass;
130
    }
131
132
    /**
133
     * Internal part of create to avoid problems with static and inheritance
134
     *
135
     * @param $fields
136
     *
137
     * @throws ExceptionFromBitrix
138
     *
139
     * @return static|bool
140
     */
141
    protected static function internalCreate($fields)
142
    {
143
        $model = new static(null, $fields);
144
145
        if ($model->onBeforeSave() === false || $model->onBeforeCreate() === false) {
146
            return false;
147
        }
148
149
        $resultObject = static::instantiateAdapter()->add($model->fields);
0 ignored issues
show
Bug introduced by
It seems like $model->fields can also be of type null; however, Arrilot\BitrixModels\Adapters\D7Adapter::add() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
150
        $result = $resultObject->isSuccess();
151
        if ($result) {
152
            $model->setId($resultObject->getId());
153
        }
154
155
        $model->setEventErrorsOnFail($resultObject);
156
        $model->onAfterCreate($result);
157
        $model->onAfterSave($result);
158
        $model->throwExceptionOnFail($resultObject);
159
160
        return $model;
161
    }
162
163
    /**
164
     * Delete model
165
     *
166
     * @return bool
167
     * @throws ExceptionFromBitrix
168
     */
169
    public function delete()
170
    {
171
        if ($this->onBeforeDelete() === false) {
172
            return false;
173
        }
174
175
        $resultObject = static::instantiateAdapter()->delete($this->id);
176
        $result = $resultObject->isSuccess();
177
178
        $this->setEventErrorsOnFail($resultObject);
179
        $this->onAfterDelete($result);
180
        $this->resetEventErrors();
181
        $this->throwExceptionOnFail($resultObject);
182
183
        return $result;
184
    }
185
    
186
    /**
187
     * Save model to database.
188
     *
189
     * @param array $selectedFields save only these fields instead of all.
190
     * @return bool
191
     * @throws ExceptionFromBitrix
192
     */
193
    public function save($selectedFields = [])
194
    {
195
        $fieldsSelectedForSave = is_array($selectedFields) ? $selectedFields : func_get_args();
196
        $this->fieldsSelectedForSave = $fieldsSelectedForSave;
197 View Code Duplication
        if ($this->onBeforeSave() === false || $this->onBeforeUpdate() === false) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
198
            $this->fieldsSelectedForSave = [];
199
            return false;
200
        } else {
201
            $this->fieldsSelectedForSave = [];
202
        }
203
204
        $fields = $this->normalizeFieldsForSave($fieldsSelectedForSave);
205
        $resultObject = static::instantiateAdapter()->update($this->id, $fields);
206
        $result = $resultObject->isSuccess();
207
208
        $this->setEventErrorsOnFail($resultObject);
209
        $this->onAfterUpdate($result);
210
        $this->onAfterSave($result);
211
        $this->throwExceptionOnFail($resultObject);
212
213
        return $result;
214
    }
215
    
216
    /**
217
     * Determine whether the field should be stopped from passing to "update".
218
     *
219
     * @param string $field
220
     * @param mixed  $value
221
     * @param array  $selectedFields
222
     *
223
     * @return bool
224
     */
225
    protected function fieldShouldNotBeSaved($field, $value, $selectedFields)
226
    {
227
        return (!empty($selectedFields) && !in_array($field, $selectedFields)) || $field === 'ID';
228
    }
229
230
    /**
231
     * Throw bitrix exception on fail
232
     *
233
     * @param \Bitrix\Main\Entity\Result $resultObject
234
     * @throws ExceptionFromBitrix
235
     */
236
    protected function throwExceptionOnFail($resultObject)
237
    {
238
        if (!$resultObject->isSuccess()) {
239
            throw new ExceptionFromBitrix(implode('; ', $resultObject->getErrorMessages()));
240
        }
241
    }
242
243
    /**
244
     * Set eventErrors field on error.
245
     *
246
     * @param \Bitrix\Main\Entity\Result $resultObject
247
     */
248
    protected function setEventErrorsOnFail($resultObject)
249
    {
250
        if (!$resultObject->isSuccess()) {
251
            $this->eventErrors = (array) $resultObject->getErrorMessages();
252
        }
253
    }
254
}
255