Completed
Push — master ( 600ac0...da8e51 )
by Arjay
03:51
created

OracleEloquent::updateBinary()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 1 Features 0
Metric Value
c 1
b 1
f 0
dl 0
loc 8
rs 9.4285
cc 2
eloc 5
nc 2
nop 3
1
<?php
2
3
namespace Yajra\Oci8\Eloquent;
4
5
use Illuminate\Database\Eloquent\Builder;
6
use Illuminate\Database\Query\Builder as IlluminateQueryBuilder;
7
use Illuminate\Database\Eloquent\Model;
8
use Yajra\Oci8\Oci8Connection;
9
use Yajra\Oci8\Query\Grammars\OracleGrammar;
10
use Yajra\Oci8\Query\OracleBuilder as QueryBuilder;
11
12
class OracleEloquent extends Model
13
{
14
    /**
15
     * List of binary (blob) columns
16
     *
17
     * @var array
18
     */
19
    protected $binaries = [];
20
21
    /**
22
     * @var array
23
     */
24
    protected $wrapBinaries = [];
25
26
    /**
27
     * Sequence name variable
28
     *
29
     * @var string
30
     */
31
    protected $sequence = null;
32
33
    /**
34
     * Get model's sequence name
35
     *
36
     * @return string
37
     */
38
    public function getSequenceName()
39
    {
40
        if ($this->sequence) {
41
            return $this->sequence;
42
        }
43
44
        return $this->getTable() . '_' . $this->getKeyName() . '_seq';
45
    }
46
47
    /**
48
     * Set sequence name
49
     *
50
     * @param string $name
51
     * @return string
52
     */
53
    public function setSequenceName($name)
54
    {
55
        return $this->sequence = $name;
56
    }
57
58
    /**
59
     * Update the model in the database.
60
     *
61
     * @param  array  $attributes
62
     * @param  array  $options
63
     * @return bool|int
64
     */
65
    public function update(array $attributes = [], array $options = [])
66
    {
67
        if (! $this->exists) {
68
            // If dirty attributes contains binary field
69
            // extract binary fields to new array
70
            if ($this->wrapBinary($dirty)) {
71
                return $this->newQuery()->updateLob($attributes, $this->wrapBinaries, $this->getKeyName());
72
            }
73
74
            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...
75
        }
76
77
        return $this->fill($attributes)->save();
78
    }
79
80
    /**
81
     * wrap binaries to each attributes
82
     *
83
     * @param  array $attributes
84
     * @return array
85
     */
86
    public function wrapBinary(&$attributes)
87
    {
88
        // If attributes contains binary field
89
        // extract binary fields to new array
90
        $binaries = [];
91
        if ($this->checkBinary($attributes) and $this->getConnection() instanceof Oci8Connection) {
92
            foreach ($attributes as $key => $value) {
93
                if (in_array($key, $this->binaries)) {
94
                    $binaries[$key] = $value;
95
                    unset($attributes[$key]);
96
                }
97
            }
98
        }
99
100
        return $this->wrapBinaries = $binaries;
101
    }
102
103
    /**
104
     * Check if attributes contains binary field
105
     *
106
     * @param  array $attributes
107
     * @return boolean
108
     */
109
    public function checkBinary(array $attributes)
110
    {
111
        foreach ($attributes as $key => $value) {
112
            // if attribute is in binary field list
113
            if (in_array($key, $this->binaries)) {
114
                return true;
115
            }
116
        }
117
118
        return false;
119
    }
120
121
    /**
122
     * Get the table qualified key name.
123
     *
124
     * @return string
125
     */
126
    public function getQualifiedKeyName()
127
    {
128
        $pos = strpos($this->getTable(), '@');
129
130
        if ($pos === false) {
131
            return $this->getTable() . '.' . $this->getKeyName();
132
        } else {
133
            $table  = substr($this->getTable(), 0, $pos);
134
            $dblink = substr($this->getTable(), $pos);
135
136
            return $table . '.' . $this->getKeyName() . $dblink;
137
        }
138
    }
139
140
    /**
141
     * Get a new query builder instance for the connection.
142
     *
143
     * @return \Yajra\Oci8\Query\OracleBuilder
144
     */
145
    protected function newBaseQueryBuilder()
146
    {
147
148
        $conn      = $this->getConnection();
149
        $grammar   = $conn->getQueryGrammar();
150
151
        if ($grammar instanceof OracleGrammar) {
152
            return new QueryBuilder($conn, $grammar, $conn->getPostProcessor());
0 ignored issues
show
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...
153
        }
154
155
        return new IlluminateQueryBuilder($conn, $grammar, $conn->getPostProcessor());
156
    }
157
158
    /**
159
     * Perform a model update operation.
160
     *
161
     * @param  \Illuminate\Database\Eloquent\Builder $query
162
     * @param  array $options
163
     * @return boolean
164
     */
165
    protected function performUpdate(Builder $query, array $options = [])
166
    {
167
        $dirty = $this->getDirty();
168
169
        if (count($dirty) > 0) {
170
            // If the updating event returns false, we will cancel the update operation so
171
            // developers can hook Validation systems into their models and cancel this
172
            // operation if the model does not pass validation. Otherwise, we update.
173
            if ($this->fireModelEvent('updating') === false) {
174
                return false;
175
            }
176
177
            // First we need to create a fresh query instance and touch the creation and
178
            // update timestamp on the model which are maintained by us for developer
179
            // convenience. Then we will just continue saving the model instances.
180
            if ($this->timestamps && array_get($options, 'timestamps', true)) {
181
                $this->updateTimestamps();
182
            }
183
184
            // Once we have run the update operation, we will fire the "updated" event for
185
            // this model instance. This will allow developers to hook into these after
186
            // models are updated, giving them a chance to do any special processing.
187
            $dirty = $this->getDirty();
188
189
            if (count($dirty) > 0) {
190
                // If dirty attributes contains binary field
191
                // extract binary fields to new array
192
                $this->updateBinary($query, $dirty, $options);
193
194
                $this->fireModelEvent('updated', false);
195
            }
196
        }
197
198
        return true;
199
    }
200
201
    /**
202
     * @param Builder $query
203
     * @param array $dirty
204
     * @param array $options
205
     */
206
    protected function updateBinary(Builder $query, $dirty, $options = [])
207
    {
208
        if ($this->wrapBinary($dirty)) {
209
            $this->setKeysForSaveQuery($query)->updateLob($dirty, $this->wrapBinaries, $this->getKeyName());
210
        } else {
211
            $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...
212
        }
213
    }
214
215
    /**
216
     * Perform a model insert operation.
217
     *
218
     * @param  \Illuminate\Database\Eloquent\Builder $query
219
     * @param  array $options
220
     * @return bool
221
     */
222
    protected function performInsert(Builder $query, array $options = [])
223
    {
224
        if ($this->fireModelEvent('creating') === false) {
225
            return false;
226
        }
227
228
        // First we'll need to create a fresh query instance and touch the creation and
229
        // update timestamps on this model, which are maintained by us for developer
230
        // convenience. After, we will just continue saving these model instances.
231
        if ($this->timestamps && array_get($options, 'timestamps', true)) {
232
            $this->updateTimestamps();
233
        }
234
235
        // If the model has an incrementing key, we can use the "insertGetId" method on
236
        // the query builder, which will give us back the final inserted ID for this
237
        // table from the database. Not all tables have to be incrementing though.
238
        $attributes = $this->attributes;
239
240
        if ($this->incrementing) {
241
            $this->insertAndSetId($query, $attributes);
242
        }
243
244
        // If the table is not incrementing we'll simply insert this attributes as they
245
        // are, as this attributes arrays must contain an "id" column already placed
246
        // there by the developer as the manually determined key for these models.
247
        else {
248
            // If attributes contains binary field
249
            // extract binary fields to new array
250
            if ($this->wrapBinary($attributes)) {
251
                $query->getQuery()->insertLob($attributes, $this->wrapBinaries, $this->getKeyName());
252
            } else {
253
                $query->insert($attributes);
254
            }
255
        }
256
257
        // We will go ahead and set the exists property to true, so that it is set when
258
        // the created event is fired, just in case the developer tries to update it
259
        // during the event. This will allow them to do so and run an update here.
260
        $this->exists = true;
261
262
        $this->wasRecentlyCreated = true;
263
264
        $this->fireModelEvent('created', false);
265
266
        return true;
267
    }
268
269
    /**
270
     * Insert the given attributes and set the ID on the model.
271
     *
272
     * @param  \Illuminate\Database\Eloquent\Builder $query
273
     * @param  array $attributes
274
     * @return int|void
275
     */
276
    protected function insertAndSetId(Builder $query, $attributes)
277
    {
278
        if ($binaries = $this->wrapBinary($attributes)) {
279
            $id = $query->getQuery()->insertLob($attributes, $binaries, $keyName = $this->getKeyName());
280
        } else {
281
            $id = $query->insertGetId($attributes, $keyName = $this->getKeyName());
282
        }
283
284
        $this->setAttribute($keyName, $id);
285
    }
286
}
287