Completed
Pull Request — 5.3 (#200)
by
unknown
38:36 queued 36:26
created

Oci8Connection::executeProcedure()   B

Complexity

Conditions 3
Paths 4

Size

Total Lines 25
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 5
Bugs 1 Features 1
Metric Value
cc 3
eloc 14
c 5
b 1
f 1
nc 4
nop 3
dl 0
loc 25
ccs 0
cts 15
cp 0
crap 12
rs 8.8571
1
<?php
2
3
namespace Yajra\Oci8;
4
5
use Doctrine\DBAL\Connection as DoctrineConnection;
6
use Doctrine\DBAL\Driver\OCI8\Driver as DoctrineDriver;
7
use Illuminate\Database\Connection;
8
use Illuminate\Database\Grammar;
9
use PDO;
10
use Yajra\Oci8\Query\Grammars\OracleGrammar as QueryGrammar;
11
use Yajra\Oci8\Query\OracleBuilder as QueryBuilder;
12
use Yajra\Oci8\Query\Processors\OracleProcessor as Processor;
13
use Yajra\Oci8\Schema\Grammars\OracleGrammar as SchemaGrammar;
14
use Yajra\Oci8\Schema\OracleBuilder as SchemaBuilder;
15
use Yajra\Oci8\Schema\Sequence;
16
use Yajra\Oci8\Schema\Trigger;
17
18
class Oci8Connection extends Connection
19
{
20
    /**
21
     * @var string
22
     */
23
    protected $schema;
24
25
    /**
26
     * @var \Yajra\Oci8\Schema\Sequence
27
     */
28
    protected $sequence;
29
30
    /**
31
     * @var \Yajra\Oci8\Schema\Trigger
32
     */
33
    protected $trigger;
34
35
    /**
36
     * @param PDO|\Closure $pdo
37
     * @param string       $database
38
     * @param string       $tablePrefix
39
     * @param array        $config
40
     */
41
    public function __construct($pdo, $database = '', $tablePrefix = '', array $config = [])
42
    {
43
        parent::__construct($pdo, $database, $tablePrefix, $config);
44
        $this->sequence = new Sequence($this);
45
        $this->trigger = new Trigger($this);
46
    }
47
48
    /**
49
     * Get current schema.
50
     *
51
     * @return string
52
     */
53
    public function getSchema()
54
    {
55
        return $this->schema;
56
    }
57
58
    /**
59
     * Set current schema.
60
     *
61
     * @param string $schema
62
     *
63
     * @return $this
64
     */
65
    public function setSchema($schema)
66
    {
67
        $this->schema = $schema;
68
        $sessionVars = [
69
            'CURRENT_SCHEMA' => $schema,
70
        ];
71
72
        return $this->setSessionVars($sessionVars);
73
    }
74
75
    /**
76
     * Update oracle session variables.
77
     *
78
     * @param array $sessionVars
79
     *
80
     * @return $this
81
     */
82
    public function setSessionVars(array $sessionVars)
83
    {
84
        $vars = [];
85
        foreach ($sessionVars as $option => $value) {
86
            if (strtoupper($option) == 'CURRENT_SCHEMA') {
87
                $vars[] = "$option  = $value";
88
            } else {
89
                $vars[] = "$option  = '$value'";
90
            }
91
        }
92
        if ($vars) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $vars of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
93
            $sql = 'ALTER SESSION SET '.implode(' ', $vars);
94
            $this->statement($sql);
95
        }
96
97
        return $this;
98
    }
99
100
    /**
101
     * Get sequence class.
102
     *
103
     * @return \Yajra\Oci8\Schema\Sequence
104
     */
105
    public function getSequence()
106
    {
107
        return $this->sequence;
108
    }
109
110
    /**
111
     * Set sequence class.
112
     *
113
     * @param \Yajra\Oci8\Schema\Sequence $sequence
114
     *
115
     * @return \Yajra\Oci8\Schema\Sequence
116
     */
117
    public function setSequence(Sequence $sequence)
118
    {
119
        return $this->sequence = $sequence;
120
    }
121
122
    /**
123
     * Get oracle trigger class.
124
     *
125
     * @return \Yajra\Oci8\Schema\Trigger
126
     */
127
    public function getTrigger()
128
    {
129
        return $this->trigger;
130
    }
131
132
    /**
133
     * Set oracle trigger class.
134
     *
135
     * @param \Yajra\Oci8\Schema\Trigger $trigger
136
     *
137
     * @return \Yajra\Oci8\Schema\Trigger
138
     */
139
    public function setTrigger(Trigger $trigger)
140
    {
141
        return $this->trigger = $trigger;
142
    }
143
144
    /**
145
     * Get a schema builder instance for the connection.
146
     *
147
     * @return \Yajra\Oci8\Schema\OracleBuilder
148
     */
149
    public function getSchemaBuilder()
150
    {
151
        if (is_null($this->schemaGrammar)) {
152
            $this->useDefaultSchemaGrammar();
153
        }
154
155
        return new SchemaBuilder($this);
156
    }
157
158
    /**
159
     * Begin a fluent query against a database table.
160
     *
161
     * @param string $table
162
     *
163
     * @return \Yajra\Oci8\Query\OracleBuilder
164
     */
165
    public function table($table)
166
    {
167
        $processor = $this->getPostProcessor();
168
169
        $query = new QueryBuilder($this, $this->getQueryGrammar(), $processor);
170
171
        return $query->from($table);
172
    }
173
174
    /**
175
     * Set oracle session date format.
176
     *
177
     * @param string $format
178
     *
179
     * @return $this
180
     */
181
    public function setDateFormat($format = 'YYYY-MM-DD HH24:MI:SS')
182
    {
183
        $sessionVars = [
184
            'NLS_DATE_FORMAT' => $format,
185
            'NLS_TIMESTAMP_FORMAT' => $format,
186
        ];
187
188
        return $this->setSessionVars($sessionVars);
189
    }
190
191
    /**
192
     * Get doctrine connection.
193
     *
194
     * @return \Doctrine\DBAL\Connection
195
     */
196
    public function getDoctrineConnection()
197
    {
198
        $driver = $this->getDoctrineDriver();
199
200
        $data = ['pdo' => $this->getPdo(), 'user' => $this->getConfig('username')];
201
202
        return new DoctrineConnection($data, $driver);
203
    }
204
205
    /**
206
     * Get doctrine driver.
207
     *
208
     * @return \Doctrine\DBAL\Driver\OCI8\Driver
209
     */
210
    protected function getDoctrineDriver()
211
    {
212
        return new DoctrineDriver();
213
    }
214
215
    /**
216
     * Execute a PL/SQL Function and return its value.
217
     * Usage: DB::executeFunction('function_name(:binding_1,:binding_n)', [':binding_1' => 'hi', ':binding_n' =>
218
     * 'bye'], PDO::PARAM_LOB).
219
     *
220
     * @author Tylerian - [email protected]
221
     *
222
     * @param string $sql        (mixed)
223
     * @param array  $bindings   (kvp array)
224
     * @param int    $returnType (PDO::PARAM_*)
225
     *
226
     * @return mixed $returnType
227
     */
228
    public function executeFunction($sql, array $bindings = [], $returnType = PDO::PARAM_STR)
229
    {
230
        $query = $this->getPdo()->prepare('begin :result := '.$sql.'; end;');
231
232
        foreach ($bindings as $key => &$value) {
233
            if (!preg_match('/^:(.*)$/i', $key)) {
234
                $key = ':'.$key;
235
            }
236
237
            $query->bindParam($key, $value);
238
        }
239
240
        $query->bindParam(':result', $result, $returnType);
241
        $query->execute();
242
243
        return $result;
244
    }
245
246
    /**
247
     * Execute a PL/SQL Procedure and return its result.
248
     * Usage: DB::executeProcedure($procedureName, $bindings).
249
     *
250
     * $bindings looks like:
251
     *         $bindings = [
252
     *                  'p_userid'  => $id
253
     *         ];
254
     *
255
     * @param string $procedureName
256
     * @param array  $bindings
257
     * @param mixed  $returnType
258
     *
259
     * @return array
260
     */
261
    public function executeProcedure($procedureName, $bindings, $returnType = PDO::PARAM_STMT)
262
    {
263
        $command = sprintf('begin %s(:%s, :cursor); end;', $procedureName, implode(', :', array_keys($bindings)));
264
265
        $stmt = $this->getPdo()->prepare($command);
266
267
        foreach ($bindings as $bindingName => &$bindingValue) {
268
            $stmt->bindParam(':'.$bindingName, $bindingValue, $this->suggestValueType($bindingValue));
269
        }
270
271
        $cursor = null;
272
273
        $stmt->bindParam(':cursor', $cursor, $returnType);
274
        $stmt->execute();
275
276
        if ($returnType === PDO::PARAM_STMT) {
277
            oci_execute($cursor, OCI_NO_AUTO_COMMIT);
278
            oci_fetch_all($cursor, $results, 0, -1, OCI_FETCHSTATEMENT_BY_ROW + OCI_ASSOC);
279
            oci_free_cursor($cursor);
280
281
            return $results;
282
        }
283
284
        return $cursor;
285
    }
286
287
    /**
288
     * Bind values to their parameters in the given statement.
289
     *
290
     * @param \PDOStatement $statement
291
     * @param array         $bindings
292
     */
293
    public function bindValues($statement, $bindings)
294
    {
295
        foreach ($bindings as $key => $value) {
296
            $statement->bindParam(
297
                $key,
298
                $bindings[$key],
299
                $this->suggestValueType($value)
300
            );
301
        }
302
    }
303
304
    /**
305
     * Get the default query grammar instance.
306
     *
307
     * @return \Illuminate\Database\Grammar|\Yajra\Oci8\Query\Grammars\OracleGrammar
308
     */
309
    protected function getDefaultQueryGrammar()
310
    {
311
        return $this->withTablePrefix(new QueryGrammar());
312
    }
313
314
    /**
315
     * Set the table prefix and return the grammar.
316
     *
317
     * @param \Illuminate\Database\Grammar|\Yajra\Oci8\Query\Grammars\OracleGrammar|\Yajra\Oci8\Schema\Grammars\OracleGrammar $grammar
318
     *
319
     * @return \Illuminate\Database\Grammar
320
     */
321
    public function withTablePrefix(Grammar $grammar)
322
    {
323
        return $this->withSchemaPrefix(parent::withTablePrefix($grammar));
324
    }
325
326
    /**
327
     * Set the schema prefix and return the grammar.
328
     *
329
     * @param \Illuminate\Database\Grammar|\Yajra\Oci8\Query\Grammars\OracleGrammar|\Yajra\Oci8\Schema\Grammars\OracleGrammar $grammar
330
     *
331
     * @return \Illuminate\Database\Grammar
332
     */
333
    public function withSchemaPrefix(Grammar $grammar)
334
    {
335
        $grammar->setSchemaPrefix($this->getConfigSchemaPrefix());
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class Illuminate\Database\Grammar as the method setSchemaPrefix() does only exist in the following sub-classes of Illuminate\Database\Grammar: Yajra\Oci8\Query\Grammars\OracleGrammar, Yajra\Oci8\Schema\Grammars\OracleGrammar. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
336
337
        return $grammar;
338
    }
339
340
    /**
341
     * Get config schema prefix.
342
     *
343
     * @return string
344
     */
345
    protected function getConfigSchemaPrefix()
346
    {
347
        return isset($this->config['prefix_schema']) ? $this->config['prefix_schema'] : '';
348
    }
349
350
    /**
351
     * Get the default schema grammar instance.
352
     *
353
     * @return \Illuminate\Database\Grammar|\Yajra\Oci8\Schema\Grammars\OracleGrammar
354
     */
355
    protected function getDefaultSchemaGrammar()
356
    {
357
        return $this->withTablePrefix(new SchemaGrammar());
358
    }
359
360
    /**
361
     * Get the default post processor instance.
362
     *
363
     * @return \Yajra\Oci8\Query\Processors\OracleProcessor
364
     */
365
    protected function getDefaultPostProcessor()
366
    {
367
        return new Processor();
368
    }
369
370
    /**
371
     * Returns PDO constant based on value type.
372
     *
373
     * @param string|int $value
374
     *
375
     * @return int
376
     */
377
    protected function suggestValueType($value)
378
    {
379
        return !is_string($value) && is_numeric($value) ? PDO::PARAM_INT : PDO::PARAM_STR;
380
    }
381
}
382