Passed
Push — master ( bf0683...f36612 )
by Radu
02:26
created

AbstractPdoDatabase::setAttribute()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 1
c 1
b 0
f 0
dl 0
loc 3
rs 10
cc 1
nc 1
nop 2
1
<?php
2
namespace WebServCo\Framework\Database;
3
4
use WebServCo\Framework\Exceptions\DatabaseException;
5
6
abstract class AbstractPdoDatabase extends \WebServCo\Framework\AbstractLibrary
7
{
8
    protected $db;
9
    protected $stmt;
10
    protected $rows;
11
12
    use \WebServCo\Framework\Traits\DatabaseTrait;
13
    use \WebServCo\Framework\Traits\DatabaseAddQueryTrait;
14
15
    abstract protected function getDataSourceName($host, $port, $dbname);
16
17
    public function __construct($settings = [])
18
    {
19
        parent::__construct($settings);
20
21
        try {
22
            $dsn = $this->getDataSourceName(
23
                $this->setting('connection/host', '127.0.0.1'),
24
                $this->setting('connection/port', null),
25
                $this->setting('connection/dbname', 'test')
26
            );
27
            $this->db = new \PDO(
28
                $dsn,
29
                $this->setting('connection/username', 'root'),
30
                $this->setting('connection/passwd', ''),
31
                [
32
                    \PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
33
                    \PDO::ATTR_DEFAULT_FETCH_MODE => \PDO::FETCH_ASSOC,
34
                    \PDO::ATTR_EMULATE_PREPARES => false,
35
                    \PDO::ATTR_PERSISTENT => false
36
                ]
37
            );
38
        } catch (\Exception $e) { // PDOException/RuntimeException/Exception
39
            throw new DatabaseException($e->getMessage(), $e);
40
        }
41
    }
42
43
    public function affectedRows()
44
    {
45
        if (!($this->stmt instanceof \PDOStatement)) {
46
            throw new DatabaseException('No Statement object available.');
47
        }
48
        return $this->stmt->rowCount();
49
    }
50
51
    public function escape($string)
52
    {
53
        return $this->db->quote($string);
54
    }
55
56
    public function getColumn($query, $params = [], $columnNumber = 0)
57
    {
58
        $this->query($query, $params);
59
        return $this->stmt->fetchColumn($columnNumber);
60
    }
61
62
    protected function getDataType($variable)
63
    {
64
        $type = gettype($variable);
65
66
        switch ($type) {
67
            case 'NULL':
68
                return \PDO::PARAM_NULL;
69
            case 'integer':
70
                return \PDO::PARAM_INT;
71
            case 'boolean':
72
            // causes data not to be inserted
73
            //return \PDO::PARAM_BOOL;
74
            case 'string':
75
            case 'double':
76
            case 'array':
77
            case 'object':
78
            case 'resource':
79
            case 'resource (closed)':
80
            case 'unknown type':
81
            default:
82
                return \PDO::PARAM_STR;
83
        }
84
    }
85
86
    public function getRow($query, $params = [])
87
    {
88
        $this->query($query, $params);
89
        return $this->stmt->fetch(\PDO::FETCH_ASSOC);
90
    }
91
92
    public function getRows($query, $params = [])
93
    {
94
        $this->query($query, $params);
95
        $this->rows = $this->stmt->fetchAll(\PDO::FETCH_ASSOC);
96
        return $this->rows;
97
    }
98
99
    /*
100
    * Get last inserted Id.
101
    *
102
    * https://dev.mysql.com/doc/refman/5.5/en/information-functions.html#function_last-insert-id
103
    * If you insert multiple rows using a single INSERT statement,
104
    * LAST_INSERT_ID() returns the value generated for the first inserted row only.
105
    * The reason for this is to make it possible to reproduce easily the same
106
    * INSERT statement against some other server.
107
    *
108
    * PDO:
109
    * Returns the ID of the last inserted row, or the last value from a sequence object,
110
    * depending on the underlying driver.
111
    * For example, PDO_PGSQL requires you to specify the name of a sequence object for the name parameter.
112
    */
113
    public function lastInsertId($name = null)
114
    {
115
        return $this->db->lastInsertId($name);
116
    }
117
118
    public function numRows()
119
    {
120
        if (!($this->stmt instanceof \PDOStatement)) {
121
            throw new DatabaseException('No Statement object available.');
122
        }
123
        if ('mysql' == $this->setting('driver')) {
124
            return $this->stmt->rowCount();
125
        }
126
        $rows = $this->rows ?: $this->stmt->fetchAll(\PDO::FETCH_ASSOC);
127
        return count($rows);
128
    }
129
130
    public function query($query, $params = [])
131
    {
132
        if (empty($query)) {
133
            throw new DatabaseException('No query specified.');
134
        }
135
136
        try {
137
            if (!empty($params)) {
138
                $this->stmt = $this->db->prepare($query);
139
                $this->bindParams($params);
140
                $this->stmt->execute();
141
            } else {
142
                $this->stmt = $this->db->query($query);
143
            }
144
            return $this->stmt;
145
        } catch (\Exception $e) { // \PDOException, \RuntimeException
146
            throw new DatabaseException($e->getMessage(), $e);
147
        }
148
    }
149
150
    public function setAttribute(int $attribute, $value)
151
    {
152
        return $this->db->setAttribute($attribute, $value);
153
    }
154
155
    public function transaction($queries)
156
    {
157
        try {
158
            $this->db->beginTransaction();
159
            foreach ($queries as $item) {
160
                if (!isset($item[0])) {
161
                    throw new DatabaseException('No query specified.');
162
                }
163
                $params = isset($item[1]) ? $item[1] : [];
164
                $this->query($item[0], $params);
165
            }
166
            $this->db->commit();
167
            return true;
168
        } catch (\Exception $e) { // DatabaseException, \PDOException, \RuntimeException
169
            $this->db->rollBack();
170
            throw new DatabaseException($e->getMessage(), $e);
171
        }
172
    }
173
174
    protected function bindParams($data)
175
    {
176
        if (empty($data)) {
177
            return false;
178
        }
179
180
        if (!is_array($data)) {
181
            throw new DatabaseException('"Parameters" is not an array.');
182
        }
183
184
        $i = 1;
185
        foreach ($data as $item) {
186
            if (is_array($item)) {
187
                foreach ($item as $v) {
188
                    $this->validateParam($v);
189
                    $this->stmt->bindValue($i, $v, $this->getDataType($v));
190
                    $i++;
191
                }
192
            } else {
193
                $this->validateParam($item);
194
                $this->stmt->bindValue($i, $item, $this->getDataType($item));
195
                $i++;
196
            }
197
        }
198
        return true;
199
    }
200
201
    protected function validateParam($param)
202
    {
203
        if (is_array($param)) {
204
            throw new DatabaseException('Parameter is an array.');
205
        }
206
        return true;
207
    }
208
}
209