Completed
Push — master ( e7b533...82e63d )
by Arjay
01:59
created

OracleEloquent::performInsert()   B

Complexity

Conditions 6
Paths 7

Size

Total Lines 46
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 46
rs 8.4751
cc 6
eloc 17
nc 7
nop 2
1
<?php
2
3
namespace Yajra\Oci8\Eloquent;
4
5
use Illuminate\Database\Eloquent\Builder;
6
use Illuminate\Database\Eloquent\Model;
7
use Yajra\Oci8\Oci8Connection;
8
use Yajra\Oci8\Query\OracleBuilder as QueryBuilder;
9
10
class OracleEloquent extends Model
11
{
12
    /**
13
     * List of binary (blob) columns
14
     *
15
     * @var array
16
     */
17
    protected $binaries = [];
18
19
    /**
20
     * @var array
21
     */
22
    protected $wrapBinaries = [];
23
24
    /**
25
     * Sequence name variable
26
     *
27
     * @var string
28
     */
29
    protected $sequence = null;
30
31
    /**
32
     * Get model's sequence name
33
     *
34
     * @return string
35
     */
36
    public function getSequenceName()
37
    {
38
        if ($this->sequence) {
39
            return $this->sequence;
40
        }
41
42
        return $this->getTable() . '_' . $this->getKeyName() . '_seq';
43
    }
44
45
    /**
46
     * Set sequence name
47
     *
48
     * @param string $name
49
     * @return string
50
     */
51
    public function setSequenceName($name)
52
    {
53
        return $this->sequence = $name;
54
    }
55
56
    /**
57
     * Update the model in the database.
58
     *
59
     * @param  array  $attributes
60
     * @param  array  $options
61
     * @return bool|int
62
     */
63
    public function update(array $attributes = [], array $options = [])
64
    {
65
        if (! $this->exists) {
66
            // If dirty attributes contains binary field
67
            // extract binary fields to new array
68
            if ($this->wrapBinary($dirty)) {
69
                return $this->newQuery()->updateLob($attributes, $this->wrapBinaries, $this->getKeyName());
70
            }
71
72
            return $this->newQuery()->update($attributes);
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this->newQuery()->update($attributes); (integer) is incompatible with the return type of the parent method Illuminate\Database\Eloquent\Model::update of type boolean.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

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

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
73
        }
74
75
        return $this->fill($attributes)->save();
76
    }
77
78
    /**
79
     * wrap binaries to each attributes
80
     *
81
     * @param  array $attributes
82
     * @return array
83
     */
84
    public function wrapBinary(&$attributes)
85
    {
86
        // If attributes contains binary field
87
        // extract binary fields to new array
88
        $binaries = [];
89
        if ($this->checkBinary($attributes) and $this->getConnection() instanceof Oci8Connection) {
90
            foreach ($attributes as $key => $value) {
91
                if (in_array($key, $this->binaries)) {
92
                    $binaries[$key] = $value;
93
                    unset($attributes[$key]);
94
                }
95
            }
96
        }
97
98
        return $this->wrapBinaries = $binaries;
99
    }
100
101
    /**
102
     * Check if attributes contains binary field
103
     *
104
     * @param  array $attributes
105
     * @return boolean
106
     */
107
    public function checkBinary(array $attributes)
108
    {
109
        foreach ($attributes as $key => $value) {
110
            // if attribute is in binary field list
111
            if (in_array($key, $this->binaries)) {
112
                return true;
113
            }
114
        }
115
116
        return false;
117
    }
118
119
    /**
120
     * Get the table qualified key name.
121
     *
122
     * @return string
123
     */
124
    public function getQualifiedKeyName()
125
    {
126
        $pos = strpos($this->getTable(), '@');
127
128
        if ($pos === false) {
129
            return $this->getTable() . '.' . $this->getKeyName();
130
        } else {
131
            $table  = substr($this->getTable(), 0, $pos);
132
            $dblink = substr($this->getTable(), $pos);
133
134
            return $table . '.' . $this->getKeyName() . $dblink;
135
        }
136
    }
137
138
    /**
139
     * Get a new query builder instance for the connection.
140
     *
141
     * @return \Yajra\Oci8\Query\OracleBuilder
142
     */
143
    protected function newBaseQueryBuilder()
144
    {
145
        $conn = $this->getConnection();
146
147
        $grammar = $conn->getQueryGrammar();
148
149
        return new QueryBuilder($conn, $grammar, $conn->getPostProcessor());
0 ignored issues
show
Compatibility introduced by
$grammar of type object<Illuminate\Databa...Query\Grammars\Grammar> is not a sub-type of object<Yajra\Oci8\Query\Grammars\OracleGrammar>. It seems like you assume a child class of the class Illuminate\Database\Query\Grammars\Grammar to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
Compatibility introduced by
$conn->getPostProcessor() of type object<Illuminate\Databa...y\Processors\Processor> is not a sub-type of object<Yajra\Oci8\Query\...essors\OracleProcessor>. It seems like you assume a child class of the class Illuminate\Database\Query\Processors\Processor to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
150
    }
151
152
    /**
153
     * Perform a model update operation.
154
     *
155
     * @param  \Illuminate\Database\Eloquent\Builder $query
156
     * @param  array $options
157
     * @return boolean
158
     */
159
    protected function performUpdate(Builder $query, array $options = [])
160
    {
161
        $dirty = $this->getDirty();
162
163
        if (count($dirty) > 0) {
164
            // If the updating event returns false, we will cancel the update operation so
165
            // developers can hook Validation systems into their models and cancel this
166
            // operation if the model does not pass validation. Otherwise, we update.
167
            if ($this->fireModelEvent('updating') === false) {
168
                return false;
169
            }
170
171
            // First we need to create a fresh query instance and touch the creation and
172
            // update timestamp on the model which are maintained by us for developer
173
            // convenience. Then we will just continue saving the model instances.
174
            if ($this->timestamps && array_get($options, 'timestamps', true)) {
175
                $this->updateTimestamps();
176
            }
177
178
            // Once we have run the update operation, we will fire the "updated" event for
179
            // this model instance. This will allow developers to hook into these after
180
            // models are updated, giving them a chance to do any special processing.
181
            $dirty = $this->getDirty();
182
183
            if (count($dirty) > 0) {
184
                // If dirty attributes contains binary field
185
                // extract binary fields to new array
186
                $this->updateBinary($query, $dirty, $options);
187
188
                $this->fireModelEvent('updated', false);
189
            }
190
        }
191
192
        return true;
193
    }
194
195
    /**
196
     * @param Builder $query
197
     * @param array $dirty
198
     * @param array $options
199
     */
200
    protected function updateBinary(Builder $query, $dirty, $options = [])
201
    {
202
        if ($this->wrapBinary($dirty)) {
203
            $this->setKeysForSaveQuery($query)->updateLob($dirty, $this->wrapBinaries, $this->getKeyName());
204
        } else {
205
            $this->setKeysForSaveQuery($query)->update($dirty, $options);
0 ignored issues
show
Unused Code introduced by
The call to Builder::update() has too many arguments starting with $options.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
206
        }
207
    }
208
209
    /**
210
     * Perform a model insert operation.
211
     *
212
     * @param  \Illuminate\Database\Eloquent\Builder $query
213
     * @param  array $options
214
     * @return bool
215
     */
216
    protected function performInsert(Builder $query, array $options = [])
217
    {
218
        if ($this->fireModelEvent('creating') === false) {
219
            return false;
220
        }
221
222
        // First we'll need to create a fresh query instance and touch the creation and
223
        // update timestamps on this model, which are maintained by us for developer
224
        // convenience. After, we will just continue saving these model instances.
225
        if ($this->timestamps && array_get($options, 'timestamps', true)) {
226
            $this->updateTimestamps();
227
        }
228
229
        // If the model has an incrementing key, we can use the "insertGetId" method on
230
        // the query builder, which will give us back the final inserted ID for this
231
        // table from the database. Not all tables have to be incrementing though.
232
        $attributes = $this->attributes;
233
234
        if ($this->incrementing) {
235
            $this->insertAndSetId($query, $attributes);
236
        }
237
238
        // If the table is not incrementing we'll simply insert this attributes as they
239
        // are, as this attributes arrays must contain an "id" column already placed
240
        // there by the developer as the manually determined key for these models.
241
        else {
242
            // If attributes contains binary field
243
            // extract binary fields to new array
244
            if ($this->wrapBinary($attributes)) {
245
                $query->getQuery()->insertLob($attributes, $this->wrapBinaries, $this->getKeyName());
246
            } else {
247
                $query->insert($attributes);
248
            }
249
        }
250
251
        // We will go ahead and set the exists property to true, so that it is set when
252
        // the created event is fired, just in case the developer tries to update it
253
        // during the event. This will allow them to do so and run an update here.
254
        $this->exists = true;
255
256
        $this->wasRecentlyCreated = true;
257
258
        $this->fireModelEvent('created', false);
259
260
        return true;
261
    }
262
263
    /**
264
     * Insert the given attributes and set the ID on the model.
265
     *
266
     * @param  \Illuminate\Database\Eloquent\Builder $query
267
     * @param  array $attributes
268
     * @return int|void
269
     */
270
    protected function insertAndSetId(Builder $query, $attributes)
271
    {
272
        if ($binaries = $this->wrapBinary($attributes)) {
273
            $id = $query->getQuery()->insertLob($attributes, $binaries, $keyName = $this->getKeyName());
274
        } else {
275
            $id = $query->insertGetId($attributes, $keyName = $this->getKeyName());
276
        }
277
278
        $this->setAttribute($keyName, $id);
279
    }
280
}
281