Joostina CMS / CMF v2.* API
  • Docs
  • Package
  • Class
  • Tree
  • Todo
Overview

Packages

  • Components
    • Acls
      • Models
        • Admin
        • Site
    • BlogCategory
      • Models
        • Admin
        • Site
    • Blogs
      • Controllers
        • Admin
        • Site
      • Helpers
      • Models
        • Admin
        • Site
    • Coder
      • Controllers
        • Admin
      • Models
        • Admin
    • Comments
      • Controllers
        • Admin
        • Site
      • Helpers
      • Models
        • Admin
        • Site
    • CommentsCounter
      • Models
        • Admin
        • Site
    • Mainpage
      • Controllers
        • Site
    • News
      • Controllers
        • Admin
        • Site
      • Helpers
      • Models
        • Admin
        • Site
    • Pages
      • Controllers
        • Admin
        • Site
      • Models
        • Site
    • Search
      • Controllers
        • Site
    • Site
      • Controllers
        • Admin
        • Site
    • Sitemap
      • Controllers
        • Admin
        • Site
      • Models
        • Admin
        • Site
    • Test
      • Controllers
        • Site
    • Torrents
      • Controllers
        • Site
    • Users
      • Controllers
        • Admin
        • Site
      • Models
        • Admin
        • Site
  • Compression
  • Core
    • Libraries
      • Arhive
      • Array
      • Attached
      • Autoadmin
      • Autoloader
      • Benchmark
      • Breadcrumbs
      • Cache
      • Config
      • Cookie
      • Csrf
      • Database
        • Drivers
          • Interfaces
      • Datetime
      • Debug
      • Editor
      • Events
      • File
      • Filter
      • Flashmessage
      • Folder
      • Hit
      • Html
      • Image
      • Inflector
      • Inputfilter
      • Libraries
      • Mail
      • Module
      • Nestedset
      • Pager
      • Pages
      • Params
      • Randomizer
      • Request
      • RobotLoader
      • Route
      • Security
      • Session
      • Static
      • String
      • Text
      • Trash
      • Validate
  • Email
  • Extra
    • Libraries
      • Basket
  • Joostina
    • Controller
    • Core
    • Document
  • JSMin
  • Libraries
    • Extra
      • Basket
        • Models
          • Site
  • None
  • Plugins
    • Autoadmin
    • Editor
    • Sitemap
  • SimpleMail
  • Vendors
    • Libraries
      • Email

Classes

  • joosDatabase
  • joosDatabaseMysqli
  • joosDatabasePDO
  1: <?php defined('_JOOS_CORE') or exit();
  2: 
  3: /**
  4:  * Библиотека работы с базой данных MySQL через PDO
  5:  * Системная библиотека
  6:  *
  7:  * @version    1.0
  8:  * @package    Core\Libraries
  9:  * @subpackage Database\Drivers
 10:  * @category   Libraries
 11:  * @author     Joostina Team <info@joostina.ru>
 12:  * @copyright  (C) 2007-2012 Joostina Team
 13:  * @license    MIT License http://www.opensource.org/licenses/mit-license.php
 14:  * Информация об авторах и лицензиях стороннего кода в составе Joostina CMS: docs/copyrights
 15:  *
 16:  * */
 17: class joosDatabasePDO implements joosInterfaceDatabase
 18: {
 19:     /**
 20:      * @var joosDatabasePDO Объект работы с базой данных
 21:      */
 22:     private static $instance = NULL;
 23: 
 24:     /**
 25:      * @var PDO Объект соединения с базой данных
 26:      */
 27:     protected $_connection = NULL;
 28: 
 29:     /**
 30:      * @var string Префикс таблиц базы данных
 31:      */
 32:     private $_table_prefix = NULL;
 33: 
 34:     /**
 35:      * @var string Что именно считается префиксом
 36:      */
 37:     private $_prefix_key = '#__';
 38: 
 39:     /**
 40:      * @var string Строка, хранящая последний установленный запрос
 41:      */
 42:     private $_sql = NULL;
 43: 
 44:     /**
 45:      * @var PDOStatement Последний использованный объект запроса
 46:      */
 47:     private $_statement = NULL;
 48: 
 49:     /**
 50:      * @var array Массив параметров для привязки
 51:      */
 52:     private $_params = array();
 53: 
 54:     /**
 55:      * Закрытый конструктор для соединений с базой данных. В случае отсутствия соединения
 56:      * прекращает работу сайта.
 57:      *
 58:      * @param string $host     Хост базы
 59:      * @param string $user     Имя пользователя
 60:      * @param string $password Пароль
 61:      * @param string $db       Имя базы
 62:      * @param string $charset  Кодировка базы
 63:      * @param string $prefix   Префикс таблиц
 64:      */
 65:     protected function __construct($host, $user, $password, $db, $charset = 'utf8', $prefix = 'jos_')
 66:     {
 67:         //а существует ли расширение вообще
 68:         if (!extension_loaded('PDO') || !extension_loaded('pdo_mysql')) {
 69: 
 70:             $this->offline();
 71:         }
 72: 
 73:         //пытаемся соединиться
 74:         try {
 75: 
 76:             $connection = new PDO('mysql:host=' . $host . ';dbname=' . $db . ';charset=' . $charset, $user, $password);
 77:             $this->_connection = $connection;
 78:             $this->_table_prefix = $prefix;
 79: 
 80:         } catch (Exception $e) {
 81: 
 82:             $this->offline();
 83:         }
 84: 
 85:         //указание charset в строке DSN игнорируется, поэтому указываем так
 86:         $this->set_query('SET NAMES ' . $charset)->query();
 87: 
 88:         $this->set_profiling();
 89:     }
 90: 
 91:     /**
 92:      * Любая ошибка соединений с базой это повод выключить сайт.
 93:      */
 94:     private function offline()
 95:     {
 96:         include JPATH_BASE . '/app/templates/system/offline.php';
 97:         exit();
 98:     }
 99: 
100:     /**
101:      * Простой синглетон для единого коннекта к базе данных
102:      *
103:      * @return joosDatabasePDO Объект соединений с базой
104:      */
105:     public static function instance()
106:     {
107:         //объект создается однажды
108:         if (self::$instance === NULL) {
109: 
110:             $db = joosConfig::get('db');
111:             joosDatabasePDO::$instance = new joosDatabasePDO($db['host'], $db['user'], $db['password'], $db['name'], $db['charset'], $db['prefix']);
112:         }
113: 
114:         return joosDatabasePDO::$instance;
115:     }
116: 
117:     /**
118:      * При включенной отладке необходимо профилирование запросов
119:      */
120:     private function set_profiling()
121:     {
122:         if (JDEBUG) {
123: 
124:             $this->set_query('set profiling=1')->query();
125:             $this->set_query('set profiling_history_size=100')->query();
126:         }
127:     }
128: 
129:     /**
130:      * Пока что метод клонирование закрываем, хз зачем он вообще нужен
131:      */
132:     public function __clone()
133:     {
134:     }
135: 
136:     /**
137:      * Метод обрамления служебных названий кавычками
138:      *
139:      * @param  string $s Входная строка
140:      * @return string Заквотированная строка
141:      */
142:     public function name_quote($s)
143:     {
144:         return '`' . $s . '`';
145:     }
146: 
147:     /**
148:      * Получение нулевого значения времени для использования по умолчанию в sql запросах
149:      *
150:      * @return string строка определяющая нулевое значение времени для использования в базе
151:      */
152:     public function get_null_date()
153:     {
154:         return '0000-00-00 00:00:00';
155:     }
156: 
157:     /**
158:      * Установка запроса для последующего исполнения
159:      *
160:      * @param  string          $sql    SQL-запрос
161:      * @param  array           $params Массив параметров для замены вида :name => $value
162:      * @return joosDatabasePDO
163:      */
164:     public function set_query($sql, $params = array())
165:     {
166:         $this->_sql = str_replace($this->_prefix_key, $this->_table_prefix, $sql);
167:         $this->_params = $params;
168: 
169:         return $this;
170:     }
171: 
172:     /**
173:      * Исполнение запроса с указанными параметрами. Если произошла ошибка - выбрасывается
174:      * исключение и работа прекращается.
175:      *
176:      * @return PDOStatement В случае успеха возвращается объект запроса
177:      */
178:     public function query()
179:     {
180:         //установка запроса и привязка параметров
181:         $this->_statement = $this->_connection->prepare($this->_sql);
182:         $this->bind_params();
183: 
184:         //исполнение и обработка ошибок
185:         $this->_statement->execute();
186:         if ('00000' != $this->_statement->errorCode()) {
187: 
188:             //тут хранится информация об ошибке
189:             $error_info = $this->_statement->errorInfo();
190: 
191:             throw new joosDatabaseException('Ошибка выполнения SQL #:error_num <br /> :error_message.<br /><br /> Ошибка в SQL: :sql', array(':error_num' => $this->_statement->errorCode(), ':error_message' => $error_info[2], ':sql' => $this->_sql));
192:         }
193: 
194:         return $this->_statement;
195:     }
196: 
197:     /**
198:      * Хитрая привязка параметров для исполнения запроса
199:      *
200:      * @param array $params Параметры
201:      */
202:     private function bind_params()
203:     {
204:         foreach ($this->_params as $param_name => $param_value) {
205: 
206:             //эта сволочь привязывается к переменной, а в цикле она всегда будет привязана
207:             //к последнему значению переменной, поэтому такой изврат с новой переменной
208:             $tmp = 'aaa' . rand(1, 1000) . rand(1, 1000) . rand(1, 1000) . rand(1, 1000) . rand(1, 1000);
209:             $$tmp = $param_value;
210: 
211:             $this->_statement->bindParam(':' . $param_name, $$tmp);
212:         }
213:     }
214: 
215:     /**
216:      * Возвращает число строк, измененныхп при последнем запросе DELETE, UPDATE или INSERT
217:      */
218:     public function get_affected_rows()
219:     {
220:         return $this->_statement->rowCount();
221:     }
222: 
223:     /**
224:      * Возвращает первый результат запроса
225:      *
226:      * @return string Значение поля
227:      */
228:     public function load_result()
229:     {
230:         //результат исполнения запроса не проверяем, так как если что - оно само упадет
231:         $this->query();
232: 
233:         //получаем массив, пронумерованный с нуля
234:         $result = $this->_statement->fetch(PDO::FETCH_NUM);
235: 
236:         $this->free_result();
237: 
238:         //и пытаемся вернуть нулевой элемент
239:         return isset($result[0]) ? $result[0] : NULL;
240:     }
241: 
242:     /**
243:      * Получение одного столбца запроса (по умолчанию нулевого) как обычного
244:      * массива со значениями полей.
245:      *
246:      * @param  int   $column Индекс поля в запросе (с нуля)
247:      * @return array Массив значений
248:      */
249:     public function load_result_array($column = 0)
250:     {
251:         //исполняем запрос
252:         $this->query();
253: 
254:         $result = array();
255:         while ($row = $this->_statement->fetch(PDO::FETCH_NUM)) {
256: 
257:             $result[] = isset($row[$column]) ? $row[$column] : NULL;
258:         }
259: 
260:         $this->free_result();
261: 
262:         return $result;
263:     }
264: 
265:     /**
266:      * Возвращает массив строк выборки, где каждая строка это ассоциативный
267:      * массив с данными столбцов
268:      *
269:      * @param string $key Ключ выборки
270:      */
271:     public function load_assoc_list($key = '')
272:     {
273:         $this->query();
274: 
275:         $result = array();
276:         while ($row = $this->_statement->fetch(PDO::FETCH_ASSOC)) {
277: 
278:             if ($key) {
279: 
280:                 $result[$row[$key]] = $row;
281:             } else {
282: 
283:                 $result[] = $row;
284:             }
285:         }
286: 
287:         $this->free_result();
288: 
289:         return $result;
290:     }
291: 
292:     /**
293:      * Загрузка полей выборки в указанный объект.
294:      *
295:      * @param object $object Куда сохраняем данные
296:      */
297:     public function load_object(& $object)
298:     {
299:         $this->query();
300: 
301:         if ($object !== NULL) {
302: 
303:             $array = $this->_statement->fetch(PDO::FETCH_ASSOC);
304:             $this->bind_array_to_object($array, $object, null, null, false);
305:         } else {
306: 
307:             $object = $this->_statement->fetch(PDO::FETCH_OBJ);
308:         }
309: 
310:         $this->free_result();
311:     }
312: 
313:     /**
314:      * Загрузка строк из таблицы как массива объектов stdClass
315:      *
316:      * @param  string $key Ключ массива (имя столбца)
317:      * @return array  Результирующий массив
318:      */
319:     public function load_object_list($key = '')
320:     {
321:         $this->query();
322: 
323:         $result = array();
324:         while ($row = $this->_statement->fetch(PDO::FETCH_OBJ)) {
325: 
326:             if ($key) {
327: 
328:                 $result[$row->$key] = $row;
329:             } else {
330: 
331:                 $result[] = $row;
332:             }
333:         }
334: 
335:         $this->free_result();
336: 
337:         return $result;
338:     }
339: 
340:     /**
341:      * Вставка в базу готового ассоциативного массива с данными
342:      *
343:      * @param string $table        Имя таблицы
344:      * @param object $object       Объект модели с полями
345:      * @param array  $values_array Массив массивов значений
346:      */
347:     public function insert_array($table, $object, array $values_array)
348:     {
349:         $ignore = isset($object->__ignore) ? ' IGNORE ' : '';
350:         unset($object->__ignore);
351: 
352:         $fmtsql = "INSERT {$ignore} INTO {$table} ( %s ) VALUES %s ";
353: 
354:         //храним поля и значения
355:         $fields = array();
356:         $values = array();
357:         $values_size = 0;
358: 
359:         //получаем все простые публичные поля модели (не начинающиеся с _)
360:         foreach (get_object_vars($object) as $field_name => $model_field_value) {
361: 
362:             if (is_array($model_field_value) or is_object($model_field_value)) {
363:                 continue;
364:             }
365: 
366:             if ($field_name[0] == '_') {
367:                 continue;
368:             }
369: 
370:             //имена полей базы
371:             $fields[] = $this->name_quote($field_name);
372: 
373:             //цикл по входному массиву массивов
374:             foreach ($values_array as $value_index => $one_array) {
375: 
376:                 //если указано значение в самой модели - то оно важнее данных в массиве
377:                 if ($model_field_value !== NULL) {
378: 
379:                     $result = $model_field_value;
380:                 } else {
381: 
382:                     //если поле есть во входном массиве - используем его
383:                     if (isset($one_array[$field_name])) {
384: 
385:                         $result = $one_array[$field_name];
386:                     }
387:                     //иначе NULL
388:                     else {
389: 
390:                         $result = 'NULL';
391:                     }
392:                 }
393: 
394:                 //кладем в массив, который потом развернем в SQL-запрос
395:                 $values[$field_name][] = $result;
396:             }
397: 
398:             //число элементов в подчиненном массиве
399:             $values_size++;
400:         }
401: 
402:         //формируем заполнение полей для столбца VALUE()
403:         $params = array();
404:         for ($i = 0; $i < $values_size; $i++) {
405: 
406:             //формируем кортеж одной записи
407:             $row = array();
408:             foreach ($values as $field => $one_array) {
409: 
410:                 //$row[] = $one_array[$i];
411:                 $param_name = $field . '_' . $i;
412:                 $params[$param_name] = $one_array[$i];
413: 
414:                 $row[] = ':' . $param_name;
415:             }
416: 
417:             $row_strings[] = '(' . implode(', ', $row) . ')';
418:         }
419: 
420:         //готовим запрос
421:         $query = sprintf($fmtsql, implode(",", $fields), implode(",", $row_strings));
422:         //и исполняем
423:         $this->set_query($query, $params);
424:         $this->query();
425: 
426:         $this->free_result();
427: 
428:         return true;
429:     }
430: 
431:     /**
432:      * Возвращает значение ID, сгенерированное для столбца AUTO_INCREMENT в
433:      * предыдущем запросе INSERT
434:      *
435:      * @return int Значение последнего ID
436:      */
437:     public function insert_id()
438:     {
439:         return $this->_connection->lastInsertId();
440:     }
441: 
442:     /**
443:      * Возвращаем объект с утилитарными функциями работы с базой данных
444:      * @return joosDatabaseUtilsPDO Объект функций
445:      */
446:     public function get_utils()
447:     {
448:         return new joosDatabaseUtilsPDO($this);
449:     }
450: 
451:     /**
452:      * Преобразование массива в объект (взял без изменения из старого класса)
453:      *
454:      * @param array  $array        исходный массив ключ=>значение
455:      * @param object $obj          объект, свойства которого будут заполнены значениями сообтветсвующих ключей массива
456:      * @param string $ignore       свойства объекта которые следует игнорировать, через пробел ('id title slug')
457:      * @param string $prefix       префикс полей массива. Например в объекте title, а в массивe blog_title
458:      * @param bool   $checkSlashes флаг экранизации значений через addslashes
459:      *
460:      * @return bool результат предразования
461:      */
462:     public function bind_array_to_object(array $array, &$obj, $ignore = '', $prefix = null, $checkSlashes = false)
463:     {
464:         $ignore = ' ' . $ignore . ' ';
465:         foreach (get_object_vars($obj) as $k => $v) {
466:             if (substr($k, 0, 1) != '_') { // закрытые свойства пропускаем
467:                 if (strpos($ignore, ' ' . $k . ' ') === false) {
468:                     if ($prefix) {
469:                         $ak = $prefix . $k;
470:                     } else {
471:                         $ak = $k;
472:                     }
473:                     if (isset($array[$ak])) {
474:                         $obj->$k = $checkSlashes ? addslashes($array[$ak]) : $array[$ak];
475:                     }
476:                 }
477:             }
478:         }
479: 
480:         return true;
481:     }
482: 
483:     /**
484:      * Освобождаем ресурсы соединения
485:      */
486:     private function free_result()
487:     {
488:         if (!JDEBUG) {
489: 
490:             $this->_statement->closeCursor();
491:             $this->_statement = NULL;
492:         }
493:     }
494: 
495:     /**
496:      * Быстрое статическое создание модели и доступ к её медотам и свойствам
497:      *
498:      * @tutorial joosDatabase::models('modelUsers')->count()
499:      * @tutorial joosDatabase::models('Blog')->get_list( array('where'=>'sate=1') )
500:      * @tutorial joosDatabase::models('Blog')->save( $_POST )
501:      *
502:      * @param string $model_name
503:      *
504:      * @return joosModel объект выбранной модели
505:      */
506:     public static function models($model_name)
507:     {
508:         return new $model_name;
509:     }
510: }
511: 
512: /**
513:  * Библиотека утилитарных функций работы с базой данных через расширение PDO
514:  *
515:  * @version    1.0
516:  * @package    Core\Libraries
517:  * @subpackage Libraries
518:  * @subpackage joosDatabase
519:  * @author     Joostina Team <info@joostina.ru>
520:  * @copyright  (C) 2007-2012 Joostina Team
521:  * @license    MIT License http://www.opensource.org/licenses/mit-license.php
522:  * Информация об авторах и лицензиях стороннего кода в составе Joostina CMS: docs/copyrights
523:  *
524:  * */
525: class joosDatabaseUtilsPDO extends joosDatabasePDO implements joosInterfaceDatabaseUtils
526: {
527:     /**
528:      * @var joosDatabasePDO Объект базы данных
529:      */
530:     private $_db;
531: 
532:     /**
533:      * @param joosDatabase $db Уже существующий объект работы с базой данных
534:      */
535:     public function __construct(joosDatabasePDO $db)
536:     {
537:         $this->_db = $db;
538:     }
539: 
540:     /**
541:      * Возвращает список таблиц активной базы
542:      *
543:      * @param  bool  $only_joostina флаг позволяющий оставить в результирующем наборе только таблицы текущего сайта
544:      * @return array массив таблиц текущей базы данных
545:      */
546:     public function get_table_list($only_joostina = true)
547:     {
548:         $only_joostina = $only_joostina ? " LIKE '" . $this->_db->_table_prefix . "%' " : '';
549: 
550:         return $this->_db->set_query('SHOW TABLES ' . $only_joostina)->load_result_array();
551:     }
552: 
553:     /**
554:      * Возвращает ассоциативный массив свойств столбцов таблицы
555:      *
556:      * @param  string $tables название таблицы
557:      * @return array  ассоциативный массив, ключами которого являются названия полей, а значения - свойства полей
558:      */
559:     public function get_table_fields($tables)
560:     {
561:         $fields = $this->_db->set_query('SHOW FIELDS FROM ' . $tables)->load_object_list();
562: 
563:         $result = array();
564:         foreach ($fields as $field) {
565:             $result[$field->Field] = $field->Type;
566:         }
567: 
568:         return $result;
569:     }
570: }
571: 
Joostina CMS / CMF v2.* API API documentation generated by ApiGen 2.6.1 – Template adapted by @olvlv and Joostina Team