Completed
Push — master ( ea6dab...74528d )
by Vitaly
12:23
created

Database::manager()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 4
rs 10
cc 1
eloc 2
nc 1
nop 1
1
<?php
2
/**
3
 * Created by PhpStorm.
4
 * User: egorov
5
 * Date: 09.05.2015
6
 * Time: 13:05
7
 */
8
namespace samsonframework\orm;
9
10
/**
11
 * Class Database
12
 * @package samsonframework\orm
13
 */
14
class Database
15
{
16
    /** @var \PDO Database driver */
17
    protected $driver;
18
19
    /** @var string Database name */
20
    protected $database;
21
22
    /** @var int Amount of miliseconds spent on queries */
23
    protected $elapsed;
24
25
    /** @var int Amount queries executed */
26
    protected $count;
27
28
    /**
29
     * Connect to a database using driver with parameters
30
     * @param string $database Database name
31
     * @param string $username Database username
32
     * @param string $password Database password
33
     * @param string $host Database host(localhost by default)
34
     * @param int $port Database port(3306 by default)
35
     * @param string $driver Database driver for interaction(MySQL by default)
36
     * @param string $charset Database character set
37
     * @return bool True if connection to database was successful
38
     */
39
    public function connect(
40
        $database,
41
        $username,
42
        $password,
43
        $host = 'localhost',
44
        $port = 3306,
45
        $driver = 'mysql',
46
        $charset = 'utf8'
47
    ) {
48
        // If we have not connected yet
49
        if (!isset($this->driver)) {
50
            $this->database = $database;
51
52
            // Check if configured database exists
53
            $this->driver = new PDO($host, $database, $username, $password, $charset, $port, $driver);
0 ignored issues
show
Documentation Bug introduced by
It seems like new \samsonframework\orm...harset, $port, $driver) of type object<samsonframework\orm\PDO> is incompatible with the declared type object<PDO> of property $driver.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
54
55
            // Set correct encodings
56
            $this->query("set character_set_client='utf8'");
57
            $this->query("set character_set_results='utf8'");
58
            $this->query("set collation_connection='utf8_general_ci'");
59
        }
60
    }
61
62
    /**
63
     * Get database name
64
     * @return string
65
     */
66
    public function database()
67
    {
68
        return $this->database;
69
    }
70
71
    /**
72
     * Create new database record
73
     * @param string $entity Entity class name
74
     * @return RecordInterface|null Entity instance
75
     */
76
    public function entity($entity)
77
    {
78
        if (class_exists($entity)) {
79
            return new $entity($this);
80
        }
81
82
        return null;
83
    }
84
85
    /**
86
     * Get entity query manager
87
     * @param string $entity Entity identifier
88
     * @return Query Query manager instance
89
     */
90
    public function manager($entity)
91
    {
92
        return new Query($entity);
93
    }
94
95
    /**
96
     * High-level database query executor
97
     * @param string $sql SQL statement
98
     * @return mixed Database query result
99
     */
100
    public function &query($sql)
101
    {
102
        $result = array();
103
104
        if (isset($this->driver)) {
105
            // Store timestamp
106
            $tsLast = microtime(true);
107
108
            try {
109
                // Perform database query
110
                $result = $this->driver->prepare($sql)->execute();
111
            } catch (\PDOException $e) {
112
                echo("\n" . $sql . '-' . $e->getMessage());
113
            }
114
115
            // Store queries count
116
            $this->count++;
117
118
            // Count elapsed time
119
            $this->elapsed += microtime(true) - $tsLast;
120
        }
121
122
        return $result;
123
    }
124
125
    /**
126
     * Retrieve array of records from a database, if $className is passed method
127
     * will try to create an object of that type. If request has failed than
128
     * method will return empty array of stdClass all arrays regarding to $className is
129
     * passed or not.
130
     *
131
     * @param string $sql Query text
132
     * @param string $className Class name if we want to create object
133
     * @return array Collection of arrays or objects
134
     */
135 View Code Duplication
    public function &fetch($sql, $className = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
136
    {
137
        // Return value
138
        $result = array();
139
140
        if (isset($this->driver)) {
141
            // Store timestamp
142
            $tsLast = microtime(true);
143
144
            try {
145
                // Perform database query
146
                if (!isset($className)) { // Return array
147
                    $result = $this->driver->query($sql)->fetchAll(\PDO::FETCH_ASSOC);
148
                } else { // Create object of passed class name
149
                    $result = $this->driver->query($sql)->fetchAll(\PDO::FETCH_CLASS, $className, array(&$this));
150
                }
151
            } catch (\PDOException $e) {
152
                echo("\n" . $sql . '-' . $e->getMessage());
153
            }
154
155
            // Store queries count
156
            $this->count++;
157
158
            // Count elapsed time
159
            $this->elapsed += microtime(true) - $tsLast;
160
        }
161
162
        return $result;
163
    }
164
165
    /**
166
     * Special accelerated function to retrieve db record fields instead of objects
167
     *
168
     * @param string $className
169
     * @param mixed $query
170
     * @param string $field
171
     *
172
     * @return array
173
     */
174
    public function &fetchColumn($className, $query, $field)
175
    {
176
        $result = array();
177
178
        if (isset($this->driver)) {
179
            // Store timestamp
180
            $tsLast = microtime(true);
181
182
            // Get SQL
183
            $sql = $this->prepareSQL($className, $query);
0 ignored issues
show
Bug introduced by
The method prepareSQL() does not seem to exist on object<samsonframework\orm\Database>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
184
185
            // Get table column index by its name
186
            $columnIndex = array_search($field, array_values($className::$_table_attributes));
187
188
            try {
189
                // Perform database query
190
                $result = $this->driver->query($sql)->fetchAll(\PDO::FETCH_COLUMN, $columnIndex);
191
            } catch (\PDOException $e) {
192
                echo("\n" . $sql . '-' . $e->getMessage());
193
            }
194
195
            // Store queries count
196
            $this->count++;
197
198
            // Count elapsed time
199
            $this->elapsed += microtime(true) - $tsLast;
200
        }
201
202
        return $result;
203
    }
204
205
    /**
206
     * Retrieve one record from a database, if $className is passed method
207
     * will try to create an object of that type. If request has failed than
208
     * method will return empty array or stdClass regarding to $className is
209
     * passed or not.
210
     *
211
     * @param string $sql Query text
212
     * @param string $className Class name if we want to create object
213
     * @return array|object Record as array or object
214
     */
215 View Code Duplication
    public function &fetchOne($sql, $className = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
216
    {
217
        // Return value, configure to return correct type
218
        $result = isset($className) ? new \stdClass() : array();
219
220
        if (isset($this->driver)) {
221
            // Store timestamp
222
            $tsLast = microtime(true);
223
224
            try {
225
                // Perform database query
226
                if (!isset($className)) { // Return array
227
                    $result = $this->driver->query($sql)->fetch(\PDO::FETCH_ASSOC);
228
                } else { // Create object of passed class name
229
                    $result = $this->driver->query($sql)->fetchObject($className, array(&$this));
230
                }
231
232
            } catch (\PDOException $e) {
233
                echo("\n" . $sql . '-' . $e->getMessage());
234
            }
235
236
            // Store queries count
237
            $this->count++;
238
239
            // Count elapsed time
240
            $this->elapsed += microtime(true) - $tsLast;
241
        }
242
243
        return $result;
244
    }
245
246
    /**
247
     * Get one record from database by its field value
248
     * @param string $className Enitity
249
     * @param string $fieldName Field name
250
     * @param string $fieldValue Field value
251
     * @return object Found object instance or an empty stdClass instance
252
     */
253
    public function fetchField($className, $fieldName, $fieldValue)
254
    {
255
        // Build SQL statement
256
        $sql = 'SELECT *
257
        FROM `' . $className::$_table_name . '`
258
        WHERE `' . $fieldName . '` = ' . $this->driver->quote($fieldValue);
259
260
        return $this->fetchOne($sql);
261
    }
262
263
    public function create($className, &$object = null)
264
    {
265
        // ??
266
        $fields = $this->getQueryFields($className, $object);
267
268
        // Build SQL query
269
        $sql = 'INSERT INTO `' . $className::$_table_name . '` (`'
270
            . implode('`,`', array_keys($fields)) . '`)
271
            VALUES (' . implode(',', $fields) . ')';
272
273
        $this->query($sql);
274
275
        // Return last inserted row identifier
276
        return $this->driver->lastInsertId();
277
    }
278
279
    public function update($className, &$object)
280
    {
281
        // ??
282
        $fields = $this->getQueryFields($className, $object, true);
283
284
        // Build SQL query
285
        $sql = 'UPDATE `' . $className::$_table_name . '` SET ' . implode(',',
286
                $fields) . ' WHERE ' . $className::$_table_name . '.' . $className::$_primary . '="' . $object->id . '"';
287
288
        $this->query($sql);
289
    }
290
291
    public function delete($className, &$object)
292
    {
293
        // Build SQL query
294
        $sql = 'DELETE FROM `' . $className::$_table_name . '` WHERE ' . $className::$_primary . ' = "' . $object->id . '"';
295
296
        $this->query($sql);
297
    }
298
299
    /** Count query result */
300
    public function count($className, $query)
301
    {
302
        // Get SQL
303
        $sql = 'SELECT Count(*) as __Count FROM (' . $this->prepareSQL($className, $query) . ') as __table';
0 ignored issues
show
Bug introduced by
The method prepareSQL() does not seem to exist on object<samsonframework\orm\Database>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
304
305
        // Выполним запрос к БД
306
        $result = $this->fetch($sql);
307
308
        return $result[0]['__Count'];
309
    }
310
311
    /**
312
     * Выполнить защиту значения поля для его безопасного использования в запросах
313
     *
314
     * @param string $value Значения поля для запроса
315
     * @return string $value Безопасное представление значения поля для запроса
316
     */
317
    protected function protectQueryValue($value)
318
    {
319
        // If magic quotes are on - remove slashes
320
        if (get_magic_quotes_gpc()) {
321
            $value = stripslashes($value);
322
        }
323
324
        // Normally escape string
325
        $value = $this->driver->quote($value);
326
327
        // Return value in quotes
328
        return $value;
329
    }
330
331
    /**
332
     * Prepare create & update SQL statements fields
333
     * @param string $className Entity name
334
     * @param Record $object Database object to get values(if needed)
335
     * @param bool $straight Way of forming SQL field statements
336
     * @return array Collection of key => value with SQL fields statements
337
     */
338
    protected function &getQueryFields($className, & $object = null, $straight = false)
339
    {
340
        // Результирующая коллекция
341
        $collection = array();
342
343
        // Установим флаг получения значений атрибутов из переданного объекта
344
        $use_values = isset($object);
345
346
        // Переберем "настоящее" имена атрибутов схемы данных для объекта
347
        foreach ($className::$_table_attributes as $attribute => $map_attribute) {
348
            // Отметки времени не заполняем
349
            if ($className::$_types[$attribute] == 'timestamp') {
350
                continue;
351
            }
352
353
            // Основной ключ не заполняем
354
            if ($className::$_primary == $attribute) {
355
                continue;
356
            }
357
358
            // Получим значение атрибута объекта защитив от инъекций, если объект передан
359
            $value = $use_values ? $this->driver->quote($object->$map_attribute) : '';
360
361
            // Добавим значение поля, в зависимости от вида вывывода метода
362
            $collection[$map_attribute] = ($straight ? $className::$_table_name . '.' . $map_attribute . '=' : '') . $value;
363
        }
364
365
        // Вернем полученную коллекцию
366
        return $collection;
367
    }
368
369
    /** @deprecated Use query() */
370
    public function &simple_query($sql)
0 ignored issues
show
Coding Style introduced by
Method name "Database::simple_query" is not in camel caps format
Loading history...
371
    {
372
        return $this->query($sql);
373
    }
374
}
375