Passed
Push — master ( bd50b7...f7d0f0 )
by Kanto
01:32
created

DB::selectFirst()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 3
nc 2
nop 2
dl 0
loc 6
rs 10
c 0
b 0
f 0
1
<?php
2
namespace Kore;
3
4
use Kore\Config;
5
use Kore\Log;
6
7
class DB
8
{
9
    /**
10
     * @var \PDO
11
     */
12
    protected $pdo;
13
14
    /**
15
     * @param string $dbconfig
16
     * @return void
17
     */
18
    final private function __construct($dbconfig)
19
    {
20
        $this->connect($dbconfig);
21
    }
22
23
    /**
24
     * @return void
25
     * @throws \Exception
26
     */
27
    final public function __clone()
28
    {
29
        throw new \Exception('__clone is not allowed!');
30
    }
31
32
    /**
33
     * @param string $dbconfig
34
     * @return self
35
     */
36
    public static function connection($dbconfig='database')
37
    {
38
        static $instances = [];
39
        if (empty($instances[$dbconfig])) {
40
            $instances[$dbconfig] = new static($dbconfig);
41
        }
42
        return $instances[$dbconfig];
43
    }
44
45
    /**
46
     * @param string $dbconfig
47
     * @return void
48
     * @throws \PDOException
49
     */
50
    protected function connect($dbconfig)
51
    {
52
        $config = Config::get($dbconfig);
53
        if ($config === null) {
54
            throw new \Exception("Databse config $dbconfig is not found!");
55
        }
56
        $host = $config['host'];
57
        $db = $config['db'];
58
        $port = $config['port'];
59
        $user = $config['user'];
60
        $pass = $config['pass'];
61
62
        $dsn = sprintf('mysql:host=%s;port=%s;dbname=%s;charset=utf8', $host, $port, $db);
63
        $this->pdo = new \PDO($dsn, $user, $pass);
64
        $this->pdo->setAttribute(\PDO::ATTR_EMULATE_PREPARES, false);
65
        $this->pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
66
    }
67
68
    /**
69
     * @return \PDO
70
     */
71
    public function getPdo()
72
    {
73
        return $this->pdo;
74
    }
75
76
    /**
77
     * @param string $query
78
     * @param array<mixed> $params
79
     * @return array<mixed>
80
     */
81
    public function select($query, $params = [])
82
    {
83
        $stm = $this->execute($query, $params);
84
85
        $result = $stm->fetchAll(\PDO::FETCH_ASSOC);
86
        return $result !== false ? $result : array();
87
    }
88
89
    /**
90
     * @param string $query
91
     * @param array<mixed> $params
92
     * @return array<mixed>
93
     */
94
    public function selectFirst($query, $params = [])
95
    {
96
        $stm = $this->execute($query, $params);
97
        
98
        $result = $stm->fetch(\PDO::FETCH_ASSOC);
99
        return $result !== false ? $result: array();
100
    }
101
102
    /**
103
     * @param string $query
104
     * @param array<mixed> $params
105
     * @return mixed
106
     */
107
    public function count($query, $params = [])
108
    {
109
        $stm = $this->execute($query, $params);
110
111
        $result = $stm->fetchColumn();
112
        return $result !== false ? $result : 0;
113
    }
114
115
    /**
116
     * @param string $query
117
     * @param array<mixed> $params
118
     * @return string
119
     */
120
    public function insert($query, $params = [])
121
    {
122
        $this->execute($query, $params);
123
124
        return $this->pdo->lastInsertId();
125
    }
126
127
    /**
128
     * @param string $query
129
     * @param array<mixed> $params
130
     * @return int
131
     */
132
    public function update($query, $params = [])
133
    {
134
        $stm = $this->execute($query, $params);
135
136
        return $stm->rowCount();
137
    }
138
139
    /**
140
     * @param string $query
141
     * @param array<mixed> $params
142
     * @return int
143
     */
144
    public function delete($query, $params = [])
145
    {
146
        $stm = $this->execute($query, $params);
147
148
        return $stm->rowCount();
149
    }
150
151
    /**
152
     * @param callable $callback
153
     * @return void
154
     */
155
    public function transaction($callback)
156
    {
157
        try {
158
            $this->pdo->beginTransaction();
159
            $callback();
160
            $this->pdo->commit();
161
        } catch (\Exception $e) {
162
            Log::error($e->getMessage());
163
            $this->pdo->rollback();
164
        }
165
    }
166
167
    /**
168
     * @param string $marker
169
     * @param array<mixed> $values
170
     * @return array<mixed>
171
     */
172
    public static function getInClause($marker, $values)
173
    {
174
        $inClause = 'IN (';
175
        $params = [];
176
        foreach ($values as $i => $value) {
177
            if ($i !== 0) {
178
                $inClause .= ', ';
179
            }
180
            $key = $marker.'_'.$i;
181
            $inClause .= $key;
182
            $params[$key] = $value;
183
        }
184
        $inClause .= ')';
185
        return [$inClause, $params];
186
    }
187
188
    /**
189
     * @param string $query
190
     * @param array<mixed> $params
191
     * @return \PDOStatement<mixed>
192
     */
193
    private function execute($query, $params)
194
    {
195
        $stm = $this->pdo->prepare($query);
196
197
        $keys = [];
198
        $values = [];
199
        foreach ($params as $key => $value) {
200
            $parameter = ":{$key}";
201
            $keys[] = $parameter;
202
            $values[] = $this->debugValue($value);
203
            $stm->bindValue($parameter, $value, $this->dataType($value));
204
        }
205
206
        $start = microtime(true);
207
        $stm->execute();
208
        $end = microtime(true);
209
        /** @phpstan-ignore-next-line */
210
        Log::debug(sprintf('%f - %s', $end-$start, str_replace($keys, $values, preg_replace(['/[\n\t]/', '/\s+/'], ['', ' '], $query))));
211
        return $stm;
212
    }
213
214
    /**
215
     * @param mixed $value
216
     * @return mixed
217
     */
218
    private function debugValue($value)
219
    {
220
        switch (gettype($value)) {
221
            case 'string':
222
                $debugValue = "'$value'";
223
                break;
224
            case 'boolean':
225
                $debugValue = $value ? 'true' : 'false';
226
                break;
227
            case 'NULL':
228
                $debugValue = 'NULL';
229
                break;
230
            default:
231
                $debugValue = $value;
232
        
233
        }
234
        return $debugValue;
235
    }
236
237
    /**
238
     * @param mixed $value
239
     * @return int
240
     */
241
    private function dataType($value)
242
    {
243
        switch (gettype($value)) {
244
            case 'boolean':
245
                $datatype = \PDO::PARAM_BOOL;
246
                break;
247
            case 'integer':
248
                $datatype = \PDO::PARAM_INT;
249
                break;
250
            case 'double':
251
                // doubleに対応するdatatypeがないのでSTR
252
                $datatype = \PDO::PARAM_STR;
253
                break;
254
            case 'string':
255
                $datatype = \PDO::PARAM_STR;
256
                break;
257
            case 'NULL':
258
                $datatype = \PDO::PARAM_NULL;
259
                break;
260
            default:
261
                $datatype = \PDO::PARAM_STR;
262
        }
263
        return $datatype;
264
    }
265
}
266