Completed
Push — master ( 62b9b0...72415f )
by Vitaly
02:50
created

Database::fetchCollectionByField()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9
Code Lines 5

Duplication

Lines 9
Ratio 100 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 9
loc 9
rs 9.6667
cc 1
eloc 5
nc 1
nop 3
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
     * Get database name
30
     * @return string
31
     */
32
    public function database()
33
    {
34
        return $this->database;
35
    }
36
37
    /**
38
     * Connect to a database using driver with parameters
39
     * @param string $database Database name
40
     * @param string $username Database username
41
     * @param string $password Database password
42
     * @param string $host Database host(localhost by default)
43
     * @param int $port Database port(3306 by default)
44
     * @param string $driver Database driver for interaction(MySQL by default)
45
     * @param string $charset Database character set
46
     * @return bool True if connection to database was successful
47
     */
48
    public function connect(
49
        $database,
50
        $username,
51
        $password,
52
        $host = 'localhost',
53
        $port = 3306,
54
        $driver = 'mysql',
55
        $charset = 'utf8'
56
    ) {
57
        // If we have not connected yet
58
        if (!isset($this->driver)) {
59
60
            $this->database = $database;
61
62
            // Check if configured database exists
63
            $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...
64
65
            // Set correct encodings
66
            $this->query("set character_set_client='utf8'");
67
            $this->query("set character_set_results='utf8'" );
68
            $this->query("set collation_connection='utf8_general_ci'");
69
        }
70
    }
71
72
    /**
73
     * Create new database record
74
     * @param string $className Entity class name
75
     */
76
    public function entity($className)
77
    {
78
        return new $className($this);
79
    }
80
81
    /**
82
     * High-level database query executor
83
     * @param string $sql SQL statement
84
     * @return mixed Database query result
85
     */
86
    public function &query($sql)
87
    {
88
        $result = array();
89
90
        if (isset($this->driver)) {
91
            // Store timestamp
92
            $tsLast = microtime(true);
93
94
            try {
95
                // Perform database query
96
                $result = $this->driver->prepare($sql)->execute();
97
            } catch (\PDOException $e) {
98
                echo("\n" . $sql . '-' . $e->getMessage());
99
            }
100
101
            // Store queries count
102
            $this->count++;
103
104
            // Count elapsed time
105
            $this->elapsed += microtime(true) - $tsLast;
106
        }
107
108
        return $result;
109
    }
110
111
    /**
112
     * Retrieve array of records from a database, if $className is passed method
113
     * will try to create an object of that type. If request has failed than
114
     * method will return empty array of stdClass all arrays regarding to $className is
115
     * passed or not.
116
     *
117
     * @param string $sql           Query text
118
     * @param string $className     Class name if we want to create object
119
     * @return array Collection of arrays or objects
120
     */
121 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...
122
    {
123
        // Return value
124
        $result = array();
125
126
        if (isset($this->driver)) {
127
            // Store timestamp
128
            $tsLast = microtime(true);
129
130
            try {
131
                // Perform database query
132
                if (!isset($className)) { // Return array
133
                    $result = $this->driver->query($sql)->fetchAll(\PDO::FETCH_ASSOC);
134
                } else { // Create object of passed class name
135
                    $result = $this->driver->query($sql)->fetchAll(\PDO::FETCH_CLASS, $className, array(&$this));
136
                }
137
            } catch (\PDOException $e) {
138
                echo("\n" . $sql . '-' . $e->getMessage());
139
            }
140
141
            // Store queries count
142
            $this->count++;
143
144
            // Count elapsed time
145
            $this->elapsed += microtime(true) - $tsLast;
146
        }
147
148
        return $result;
149
    }
150
151
    /**
152
     * Special accelerated function to retrieve db record fields instead of objects
153
     *
154
     * @param string $className
155
     * @param mixed $query
156
     * @param string $field
157
     *
158
     * @return array
159
     */
160
    public function &fetchColumn($className, $query, $field)
161
    {
162
        $result = array();
163
164
        if (isset($this->driver)) {
165
            // Store timestamp
166
            $tsLast = microtime(true);
167
168
            // Get SQL
169
            $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...
170
171
            // Get table column index by its name
172
            $columnIndex = array_search($field, array_values($className::$_table_attributes));
173
174
            try {
175
                // Perform database query
176
                $result = $this->driver->query($sql)->fetchAll(\PDO::FETCH_COLUMN, $columnIndex);
177
            } catch (\PDOException $e) {
178
                echo("\n" . $sql . '-' . $e->getMessage());
179
            }
180
181
            // Store queries count
182
            $this->count++;
183
184
            // Count elapsed time
185
            $this->elapsed += microtime(true) - $tsLast;
186
        }
187
188
        return $result;
189
    }
190
191
    /**
192
     * Retrieve one record from a database, if $className is passed method
193
     * will try to create an object of that type. If request has failed than
194
     * method will return empty array or stdClass regarding to $className is
195
     * passed or not.
196
     *
197
     * @param string $sql           Query text
198
     * @param string $className     Class name if we want to create object
199
     * @return array|object Record as array or object
200
     */
201 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...
202
    {
203
        // Return value, configure to return correct type
204
        $result = isset($className) ? new \stdClass() : array();
205
206
        if (isset($this->driver)) {
207
            // Store timestamp
208
            $tsLast = microtime(true);
209
210
            try {
211
                // Perform database query
212
                if (!isset($className)) { // Return array
213
                    $result = $this->driver->query($sql)->fetch(\PDO::FETCH_ASSOC);
214
                } else { // Create object of passed class name
215
                    $result = $this->driver->query($sql)->fetchObject($className, array(&$this));
216
                }
217
218
            } catch (\PDOException $e) {
219
                echo("\n" . $sql . '-' . $e->getMessage());
220
            }
221
222
            // Store queries count
223
            $this->count++;
224
225
            // Count elapsed time
226
            $this->elapsed += microtime(true) - $tsLast;
227
        }
228
229
        return $result;
230
    }
231
232
    /**
233
     * Get collection record from database by its field value
234
     * @param string $className Enitity
235
     * @param string $fieldName Field name
236
     * @param string $fieldValue Field value
237
     * @return object[] Found object instance or an empty stdClass instance
238
     */
239 View Code Duplication
    public function fetchCollectionByField($className, $fieldName, $fieldValue)
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...
240
    {
241
        // Build SQL statement
242
        $sql = 'SELECT *
243
        FROM `'.$className::$_table_name.'`
244
        WHERE `'.$fieldName.'` = '.$this->driver->quote($fieldValue);
245
246
        return $this->fetch($sql);
247
    }
248
249
    /**
250
     * Get one record from database by its field value
251
     * @param string $className Enitity
252
     * @param string $fieldName Field name
253
     * @param string $fieldValue Field value
254
     * @return object Found object instance or an empty stdClass instance
255
     */
256 View Code Duplication
    public function fetchField($className, $fieldName, $fieldValue)
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...
257
    {
258
        // Build SQL statement
259
        $sql = 'SELECT *
260
        FROM `'.$className::$_table_name.'`
261
        WHERE `'.$fieldName.'` = '.$this->driver->quote($fieldValue);
262
263
        return $this->fetchOne($sql);
264
    }
265
266
    public function create($className, & $object = null)
267
    {
268
        // ??
269
        $fields = $this->getQueryFields($className, $object);
270
271
        // Build SQL query
272
        $sql = 'INSERT INTO `' . $className::$_table_name . '` (`'
273
            . implode('`,`', array_keys($fields)) . '`)
274
            VALUES (' . implode(',', $fields) . ')';
275
276
        $this->query($sql);
277
278
        // Return last inserted row identifier
279
        return $this->driver->lastInsertId();
280
    }
281
282
    public function update($className, & $object)
283
    {
284
        // ??
285
        $fields = $this->getQueryFields($className, $object, true);
286
287
        // Build SQL query
288
        $sql = 'UPDATE `' . $className::$_table_name . '` SET ' . implode(',',
289
                $fields) . ' WHERE ' . $className::$_table_name . '.' . $className::$_primary . '="' . $object->id . '"';
290
291
        $this->query($sql);
292
    }
293
294
    public function delete($className, & $object)
295
    {
296
        // Build SQL query
297
        $sql = 'DELETE FROM `' . $className::$_table_name . '` WHERE ' . $className::$_primary . ' = "' . $object->id . '"';
298
299
        $this->query($sql);
300
    }
301
302
    /** Count query result */
303
    public function count($className, $query)
304
    {
305
        // Get SQL
306
        $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...
307
308
        // Выполним запрос к БД
309
        $result = $this->fetch($sql);
310
311
        return $result[0]['__Count'];
312
    }
313
314
    /**
315
     * Выполнить защиту значения поля для его безопасного использования в запросах
316
     *
317
     * @param string $value Значения поля для запроса
318
     * @return string $value Безопасное представление значения поля для запроса
319
     */
320
    protected function protectQueryValue($value)
321
    {
322
        // If magic quotes are on - remove slashes
323
        if (get_magic_quotes_gpc()) {
324
            $value = stripslashes($value);
325
        }
326
327
        // Normally escape string
328
        $value = $this->driver->quote($value);
329
330
        // Return value in quotes
331
        return $value;
332
    }
333
334
    /**
335
     * Prepare create & update SQL statements fields
336
     * @param string $className Entity name
337
     * @param Record $object Database object to get values(if needed)
338
     * @param bool $straight Way of forming SQL field statements
339
     * @return array Collection of key => value with SQL fields statements
340
     */
341
    protected function &getQueryFields($className, & $object = null, $straight = false)
342
    {
343
        // Результирующая коллекция
344
        $collection = array();
345
346
        // Установим флаг получения значений атрибутов из переданного объекта
347
        $use_values = isset($object);
348
349
        // Переберем "настоящее" имена атрибутов схемы данных для объекта
350
        foreach ($className::$_table_attributes as $attribute => $map_attribute) {
351
            // Отметки времени не заполняем
352
            if ($className::$_types[$attribute] == 'timestamp') {
353
                continue;
354
            }
355
356
            // Основной ключ не заполняем
357
            if ($className::$_primary == $attribute) {
358
                continue;
359
            }
360
361
            // Получим значение атрибута объекта защитив от инъекций, если объект передан
362
            $value = $use_values ? $this->driver->quote($object->$map_attribute) : '';
363
364
            // Добавим значение поля, в зависимости от вида вывывода метода
365
            $collection[$map_attribute] = ($straight ? $className::$_table_name . '.' . $map_attribute . '=' : '') . $value;
366
        }
367
368
        // Вернем полученную коллекцию
369
        return $collection;
370
    }
371
372
    /** @deprecated Use query() */
373
    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...
374
    {
375
        return $this->query($sql);
376
    }
377
}
378