Issues (99)

src/Db/Driver/Oracle.php (4 issues)

1
<?php
2
/**
3
 * DronePHP (http://www.dronephp.com)
4
 *
5
 * @link      http://github.com/Pleets/DronePHP
6
 * @copyright Copyright (c) 2016-2018 Pleets. (http://www.pleets.org)
7
 * @license   http://www.dronephp.com/license
8
 * @author    Darío Rivera <[email protected]>
9
 */
10
11
namespace Drone\Db\Driver;
12
13
/**
14
 * Oracle class
15
 *
16
 * This is a database driver class to connect to Oracle
17
 */
18
class Oracle extends AbstractDriver implements DriverInterface
19
{
20
    /**
21
     * {@inheritdoc}
22
     *
23
     * @var resource
24
     */
25
    protected $dbconn;
26
27
    /**
28
     * {@inheritdoc}
29
     *
30
     * @param array $options
31
     */
32
    public function __construct($options)
33
    {
34
        $this->driverName = 'Oci8';
35
36
        if (!array_key_exists("dbchar", $options)) {
37
            $options["dbchar"] = "AL32UTF8";
38
        }
39
40
        parent::__construct($options);
41
42
        $auto_connect = array_key_exists('auto_connect', $options) ? $options["auto_connect"] : true;
43
44
        if ($auto_connect) {
45
            $this->connect();
46
        }
47
    }
48
49
    /**
50
     * Connects to database
51
     *
52
     * @throws RuntimeException
53
     * @throws Exception\ConnectionException
54
     *
55
     * @return resource
56
     */
57
    public function connect()
58
    {
59
        if (!extension_loaded('oci8')) {
60
            throw new \RuntimeException("The Oci8 extension is not loaded");
61
        }
62
63
        $connection_string = (is_null($this->dbhost) || empty($this->dbhost))
64
            ? $this->dbname
65
            :
66
                (!is_null($this->dbport) && !empty($this->dbport))
67
                    ? $this->dbhost .":". $this->dbport ."/". $this->dbname
68
                    : $this->dbhost ."/". $this->dbname;
69
70
        $conn = @oci_connect($this->dbuser, $this->dbpass, $connection_string, $this->dbchar);
71
72
        if ($conn === false) {
73
            $error = oci_error();
74
            throw new Exception\ConnectionException($error["message"], $error["code"]);
75
        }
76
77
        $this->dbconn = $conn;
78
79
        return $this->dbconn;
80
    }
81
82
    /**
83
     * Excecutes a statement
84
     *
85
     * @param string $sql
86
     * @param array $params
87
     *
88
     * @throws Exception\InvalidQueryException
89
     *
90
     * @return resource
91
     */
92
    public function execute($sql, array $params = [])
93
    {
94
        $this->numRows = 0;
95
        $this->numFields = 0;
96
        $this->rowsAffected = 0;
97
98
        $this->arrayResult = null;
99
100
        $this->result = $stid = @oci_parse($this->dbconn, $sql);
101
102
        if (!$stid) {
0 ignored issues
show
$stid is of type false|resource, thus it always evaluated to false.
Loading history...
103
            $error = $stid ? oci_error($stid) : oci_error();
0 ignored issues
show
$stid is of type false|resource, thus it always evaluated to false.
Loading history...
104
105
            if (!empty($error)) {
106
                $error = [
107
                    "message" => "Could not prepare statement!",
108
                ];
109
110
                $this->error($error["message"]);
0 ignored issues
show
The method error() does not exist on Drone\Db\Driver\Oracle. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

110
                $this->/** @scrutinizer ignore-call */ 
111
                       error($error["message"]);
Loading history...
111
            } else {
112
                $this->error($error["code"], $error["message"]);
113
            }
114
115
            if (array_key_exists("code", $error)) {
0 ignored issues
show
It seems like $error can also be of type false; however, parameter $search of array_key_exists() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

115
            if (array_key_exists("code", /** @scrutinizer ignore-type */ $error)) {
Loading history...
116
                throw new Exception\InvalidQueryException($error["message"], $error["code"]);
117
            } else {
118
                throw new Exception\InvalidQueryException($error["message"]);
119
            }
120
        }
121
122
        # Bound variables
123
        if (count($params)) {
124
            $param_keys   = array_keys($params);
125
            $param_values = array_values($params);
126
127
            $param_count = count($params);
128
129
            for ($i = 0; $i < $param_count; $i++) {
130
                oci_bind_by_name($stid, $param_keys[$i], $param_values[$i], -1);
131
            }
132
        }
133
134
        $prev_error_handler = set_error_handler(['\Drone\Error\ErrorHandler', 'errorControlOperator'], E_ALL);
135
136
        // may be throw a Fatal error (Ex: Maximum execution time)
137
        $r = ($this->transac_mode) ? oci_execute($stid, OCI_NO_AUTO_COMMIT) : oci_execute($stid, OCI_COMMIT_ON_SUCCESS);
138
139
        set_error_handler($prev_error_handler);
140
141
        if (!$r) {
142
            $error = oci_error($stid);
143
            $this->error($error["code"], $error["message"]);
144
145
            throw new Exception\InvalidQueryException($error["message"], $error["code"]);
146
        }
147
148
        # This should be before of getArrayResult() because oci_fetch() is incremental.
149
        $this->rowsAffected = oci_num_rows($stid);
150
151
        $rows = $this->getArrayResult();
152
153
        $this->numRows = count($rows);
154
        $this->numFields = oci_num_fields($stid);
155
156
        if ($this->transac_mode) {
157
            $this->transac_result = is_null($this->transac_result) ? $stid : $this->transac_result && $stid;
158
        }
159
160
        $this->result = $stid;
161
162
        return $this->result;
163
    }
164
165
    /**
166
     * {@inheritdoc}
167
     */
168
    public function commit()
169
    {
170
        return oci_commit($this->dbconn);
171
    }
172
173
    /**
174
     * {@inheritdoc}
175
     */
176
    public function rollback()
177
    {
178
        return oci_rollback($this->dbconn);
179
    }
180
181
    /**
182
     * {@inheritdoc}
183
     */
184
    public function disconnect()
185
    {
186
        parent::disconnect();
187
188
        return oci_close($this->dbconn);
189
    }
190
191
    /**
192
     * Returns an array with the rows fetched
193
     *
194
     * @throws LogicException
195
     *
196
     * @return array
197
     */
198
    protected function toArray()
199
    {
200
        $data = [];
201
202
        if ($this->result) {
203
            while (($row = @oci_fetch_array($this->result, OCI_BOTH + OCI_RETURN_NULLS)) !== false) {
204
                $data[] = $row;
205
            }
206
        } else {             # This error is thrown because of 'execute' method has not been executed.
207
            throw new \LogicException('There are not data in the buffer!');
208
        }
209
210
        $this->arrayResult = $data;
211
212
        return $data;
213
    }
214
215
    /**
216
     * By default __destruct() disconnects to database
217
     *
218
     * @return null
219
     */
220
    public function __destruct()
221
    {
222
        if ($this->dbconn) {
223
            oci_close($this->dbconn);
224
        }
225
    }
226
}
227