Completed
Push — master ( 160359...d1ec24 )
by Vitaly
03:59
created

Database::delete()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

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