Passed
Push — master ( 470498...a354b9 )
by Radu
01:17
created

MysqliDatabase::bindParams()   B

Complexity

Conditions 7
Paths 13

Size

Total Lines 32
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 21
dl 0
loc 32
rs 8.6506
c 0
b 0
f 0
cc 7
nc 13
nop 1
1
<?php
2
namespace WebServCo\Framework\Libraries;
3
4
use WebServCo\Framework\Settings;
5
use WebServCo\Framework\Exceptions\DatabaseException;
6
7
final class MysqliDatabase extends \WebServCo\Framework\AbstractDatabase implements
8
    \WebServCo\Framework\Interfaces\DatabaseInterface
9
{
10
    use \WebServCo\Framework\Traits\DatabaseTrait;
11
    use \WebServCo\Framework\Traits\DatabaseAddQueryTrait;
12
    use \WebServCo\Framework\Traits\MysqlDatabaseTrait;
13
14
    protected $mysqliResult;
15
16
    public function __construct($settings = [])
17
    {
18
        parent::__construct($settings);
19
20
        $driver = new \mysqli_driver();
21
        $driver->report_mode = MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT;
22
23
        try {
24
            $this->db = new \mysqli(
25
                $this->setting(sprintf('connection%shost', Settings::DIVIDER), '127.0.0.1'),
26
                $this->setting(sprintf('connection%susername', Settings::DIVIDER), 'root'),
27
                $this->setting(sprintf('connection%spasswd', Settings::DIVIDER), ''),
28
                $this->setting(sprintf('connection%sdbname', Settings::DIVIDER), 'test'),
29
                $this->setting(sprintf('connection%sport', Settings::DIVIDER), 3306)
30
            );
31
            $this->db->set_charset('utf8mb4');
32
        } catch (\Exception $e) { // mysqli_sql_exception/RuntimeException/Exception
33
            throw new DatabaseException($e->getMessage());
34
        }
35
    }
36
37
    public function escape($string)
38
    {
39
        return $this->db->real_escape_string($string);
40
    }
41
42
    public function query($query, $params = [])
43
    {
44
        if (empty($query)) {
45
            throw new DatabaseException('No query specified');
46
        }
47
48
        try {
49
            /**
50
             * For simplicity use statements even for simple queries.
51
             */
52
            $this->stmt = $this->db->prepare($query);
53
            $this->bindParams($params);
54
            $this->stmt->execute();
55
            $this->setLastInsertId();
56
            return $this->stmt;
57
        } catch (\Exception $e) { // mysqli_sql_exception/RuntimeException/Exception
58
            throw new DatabaseException($e->getMessage());
59
        }
60
    }
61
62
    public function transaction($queries)
63
    {
64
        try {
65
            $this->db->autocommit(false);
66
            foreach ($queries as $item) {
67
                if (!isset($item[0])) {
68
                    throw new DatabaseException('No query specified');
69
                }
70
                $params = isset($item[1]) ? $item[1] : [];
71
                $this->query($item[0], $params);
72
            }
73
            $this->db->commit();
74
            return true;
75
        } catch (\Exception $e) { // mysqli_sql_exception/RuntimeException/Exception
76
            $this->db->rollback();
77
            throw new DatabaseException($e->getMessage());
78
        }
79
    }
80
81
    public function numRows()
82
    {
83
        /**
84
         * @TODO Fix.
85
         * "$this->stmt->num_rows" will be 0 because we can't use
86
         * "$this->stmt->store_result();"
87
         * We could count "$this->mysqliResult" but that would mean
88
         * the method will only work if getRow*() was called before.
89
         */
90
        throw new DatabaseException('Method not implemented.');
91
    }
92
93
    public function affectedRows()
94
    {
95
        if (!($this->stmt instanceof \mysqli_stmt)) {
96
            throw new DatabaseException('No Statement object available.');
97
        }
98
        return $this->stmt->affected_rows;
99
    }
100
101
    public function getRows($query, $params = [])
102
    {
103
        $this->query($query, $params);
104
        $this->mysqliResult = $this->stmt->get_result();
105
        $this->rows = $this->mysqliResult->fetch_all(MYSQLI_ASSOC);
106
        return $this->rows;
107
    }
108
109
    public function getRow($query, $params = [])
110
    {
111
        $this->query($query, $params);
112
        $this->mysqliResult = $this->stmt->get_result();
113
        return $this->mysqliResult->fetch_assoc();
114
    }
115
116
    public function getColumn($query, $params = [], $columnNumber = 0)
117
    {
118
        $this->query($query, $params);
119
        $this->mysqliResult = $this->stmt->get_result();
120
        $row = $this->mysqliResult->fetch_array(MYSQLI_NUM);
121
        return array_key_exists($columnNumber, $row) ? $row[$columnNumber] : false;
122
    }
123
124
    protected function bindParams($params = [])
125
    {
126
        if (empty($params)) {
127
            return false;
128
        }
129
130
        $types = [];
131
        $values = [];
132
        foreach ($params as $item) {
133
            if (is_array($item)) {
134
                foreach ($item as $value) {
135
                    $types[] = $this->getDataType($value);
136
                    $values[] = $value;
137
                }
138
            } else {
139
                $types[] = $this->getDataType($item);
140
                $values[] = $item;
141
            }
142
        }
143
144
        $typeString = implode('', $types);
145
        $args = [
146
            0 => &$typeString,
147
        ];
148
        foreach ($values as &$v) {
149
            $args[] = &$v;
150
        }
151
        $callable = [$this->stmt, 'bind_param'];
152
        if (is_callable($callable)) {
153
            return call_user_func_array($callable, $args);
154
        }
155
        throw new DatabaseException('Method not found');
156
    }
157
158
    protected function getDataType($variable)
159
    {
160
        $type = gettype($variable);
161
162
        switch ($type) {
163
            case 'integer':
164
                return 'i';
165
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
166
            case 'double':
167
                return 'd';
168
                break;
169
            case 'string':
170
            case 'boolean':
171
            case 'NULL':
172
            case 'array':
173
            case 'object':
174
            case 'resource':
175
            case 'resource (closed)':
176
            case 'unknown type':
177
            default:
178
                return 's';
179
                break;
180
        }
181
    }
182
183
    protected function setLastInsertId()
184
    {
185
        $this->lastInsertId = $this->db->insert_id;
186
    }
187
}
188