energine
[ class tree: energine ] [ index: energine ] [ all elements ]

Source for file QAL.class.php

Documentation is available at QAL.class.php

  1. <?php
  2.  
  3. /**
  4.  * Класс QAL.
  5.  *
  6.  * @package energine
  7.  * @subpackage core
  8.  * @author 1m.dm
  9.  * @copyright Energine 2006
  10.  * @version $Id$
  11.  */
  12.  
  13. //require_once('core/framework/DBA.class.php');
  14.  
  15. /**
  16.  * Query Abstraction Layer.
  17.  *
  18.  * @package energine
  19.  * @subpackage core
  20.  * @author 1m.dm
  21.  * @final
  22.  */
  23. final class QAL extends DBA {
  24.  
  25.     /**
  26.      * Режимы модифицирующих операций
  27.      */
  28.     const INSERT = 'INSERT';
  29.     const UPDATE = 'UPDATE';
  30.     const DELETE = 'DELETE';
  31.  
  32.     /**
  33.      * Направления сортировки
  34.      */
  35.     const ASC = 'ASC';
  36.     const DESC = 'DESC';
  37.  
  38.     /**
  39.      * Пустая строка
  40.      */
  41.     const EMPTY_STRING = null;
  42.  
  43.     /**
  44.      * Ошибки
  45.      */
  46.     const ERR_BAD_QUERY_FORMAT = 'Bad query format.';
  47.  
  48.     /**
  49.      * Конструктор класса.
  50.      *
  51.      * @access public
  52.      * @param string $dsn 
  53.      * @param string $username 
  54.      * @param string $password 
  55.      * @param object $driverOptions 
  56.      * @return void 
  57.      */
  58.     public function __construct($dsn$username$passwordarray $driverOptions$charset 'utf8'{
  59.         parent::__construct($dsn$username$password$driverOptions$charset);
  60.     }
  61.  
  62.     /**
  63.      * Выполняет простой SELECT-запрос к БД и возвращает результат выборки.
  64.      *
  65.      * Имена полей $fields задаётся одним из трёх способов:
  66.      *     1. массив имён полей;
  67.      *     2. имя одного поля;
  68.      *     3. true, для выборки всех полей таблицы.
  69.      *
  70.      * Условие выборки $condition задаётся массивом вида array(имя_поля => значение),
  71.      * или строкой WHERE-условия типа 'field1 = 4 AND field2 = 8'.
  72.      *
  73.      * Порядок сортировки результа задаётся массивом вида array(имя_поля => порядок_сортировки),
  74.      * или строкой предложения ORDER BY типа 'field1 DESC, field2 ASC'.
  75.      *
  76.      * Лимит выборки задаётся массивом вида array(смещение, кол-во_строк),
  77.      * или строкой предложения LIMIT типа '32'.
  78.      *
  79.      * Возвращает массив результата выборки или true, если результат пустой.
  80.      *
  81.      * @access public
  82.      * @param string $tableName имя таблицы
  83.      * @param mixed $fields массив имен полей ИЛИ имя одного поля ИЛИ true для выборки всех полей таблицы
  84.      * @param mixed $condition условие выборки
  85.      * @param mixed $order порядок сортировки результата
  86.      * @param mixed $limit лимит выборки
  87.      * @return array 
  88.      * @see DBA::selectRequest()
  89.      */
  90.     public function select($tableName$fields true$condition null$order null$limit null{
  91.         //$tableName = strtolower($tableName);
  92.  
  93.         if (is_array($fields&& !empty($fields)) {
  94.             $fields array_map('strtolower'$fields);
  95.             $fields implode(', '$fields);
  96.         }
  97.         elseif (is_string($fields)) {
  98.             $fields strtolower($fields);
  99.         }
  100.         elseif ($fields === true{
  101.             $fields '*';
  102.         }
  103.         else {
  104.             throw new SystemException(self::ERR_BAD_QUERY_FORMATSystemException::ERR_DBarray($tableName$fields$condition$order$limit));
  105.         }
  106.  
  107.         if ($this->pdo->getAttribute(PDO::ATTR_DRIVER_NAME=== 'mysql'{
  108.             $tableName "`$tableName`";
  109.         }
  110.  
  111.         $sqlQuery "SELECT $fields FROM $tableName";
  112.  
  113.         if (isset($condition)) {
  114.             $sqlQuery .= $this->buildWhereCondition($condition);
  115.         }
  116.  
  117.         if (isset($order)) {
  118.             $sqlQuery .= $this->buildOrderCondition($order);
  119.         }
  120.  
  121.         if (isset($limit)) {
  122.             if (is_array($limit)) {
  123.                 $sqlQuery .= ' LIMIT '.implode(', '$limit);
  124.             }
  125.             else {
  126.                 $sqlQuery .= " LIMIT $limit";
  127.             }
  128.         }
  129.  
  130.         return $this->selectRequest($sqlQuery);
  131.     }
  132.  
  133.     /**
  134.      * Выполняет простую модифицирующую (INSERT, UPDATE, DELETE) операцию в БД.
  135.      *
  136.      * Режим операции задаётся одной из трёх констант:
  137.      *     1. QAL::INSERT - вставка;
  138.      *     2. QAL::UPDATE - обновление;
  139.      *     3. QAL::DELETE - удаление.
  140.      *
  141.      * Данные для операций типа QAL::INSERT и QAL::UPDATE задаются массивом
  142.      * вида array(имя_поля => значение).
  143.      *
  144.      * Условие операции задаётся массивом вида array(имя_поля => значение),
  145.      * или строкой WHERE-условия типа 'field1 = 4 AND field2 = 8'.
  146.      *
  147.      * В режиме QAL::INSERT метод возвращает последний сгенерированный ID для
  148.      * поля типа AUTO_INCREMENT, или true если такого поля в таблице нет.
  149.      *
  150.      * В режимах QAL::UPDATE и QAL::DELETE при успешном выполнении запроса
  151.      * всегда возвращается true.
  152.      *
  153.      * При ошибке выполнения любого типа операций возвращается false.
  154.      *
  155.      * @access public
  156.      * @param int $mode режим операции
  157.      * @param string $tableName имя таблицы
  158.      * @param array $data данные для операции
  159.      * @param mixed $condition условие операции
  160.      * @return array 
  161.      * @see DBA::modifyRequest()
  162.      */
  163.     public function modify($mode$tableNamearray $data null$condition null{
  164.         if (empty($mode|| empty($tableName)) {
  165.             throw new SystemException(self::ERR_BAD_QUERY_FORMATSystemException::ERR_DB);
  166.         }
  167.  
  168.         $sqlQuery '';
  169.  
  170.         switch ($mode{
  171.             case self::INSERT:
  172.                 if (!empty($data)) {
  173.                     $fieldNames array();
  174.                     $fieldValues array();
  175.                     foreach ($data as $fieldName => $fieldValue{
  176.                         $fieldNames[$fieldName;
  177.                         if ($fieldValue === self::EMPTY_STRING{
  178.                             $fieldValue $this->quote('');
  179.                         }
  180.                         elseif ($fieldValue == ''{
  181.                             $fieldValue 'NULL';
  182.                         }
  183.                         else {
  184.                             $fieldValue $this->quote($fieldValue);
  185.                         }
  186.                         $fieldValues[$fieldValue;
  187.                     }
  188.                     $sqlQuery "INSERT INTO `$tableName` (".implode(', '$fieldNames).') VALUES ('.implode(', '$fieldValues).')';
  189.                 }
  190.                 else {
  191.                     $sqlQuery "INSERT INTO `$tableName` VALUES ()";
  192.                 }
  193.                 break;
  194.             case self::UPDATE:
  195.                 if (!empty($data)) {
  196.                     $fields array();
  197.                     foreach ($data as $fieldName => $fieldValue{
  198.                         if ($fieldValue === self::EMPTY_STRING{
  199.                             $fieldValue $this->quote('');
  200.                         }
  201.                         elseif ($fieldValue === ''{
  202.                             $fieldValue 'NULL';
  203.                         }
  204.                         else {
  205.                             $fieldValue $this->quote($fieldValue);
  206.                         }
  207.                         $fields["$fieldName = $fieldValue";
  208.                     }
  209.                     $sqlQuery "UPDATE `$tableName` SET ".implode(', '$fields);
  210.                 }
  211.                 else {
  212.                     throw new SystemException(self::ERR_BAD_QUERY_FORMATSystemException::ERR_DB);
  213.                 }
  214.                 break;
  215.             case self::DELETE:
  216.                 $sqlQuery "DELETE FROM `$tableName`";
  217.                 break;
  218.             default:
  219.                 throw new SystemException(self::ERR_BAD_QUERY_FORMATSystemException::ERR_DB);
  220.         }
  221.  
  222.         if (isset($condition&& $mode != self::INSERT{
  223.             $sqlQuery .= $this->buildWhereCondition($condition);
  224.         }
  225.  
  226.         return $this->modifyRequest($sqlQuery);
  227.     }
  228.  
  229.     /**
  230.      * Строит WHERE-условие для SQL-запроса.
  231.      *
  232.      * @access public
  233.      * @param mixed $condition 
  234.      * @return string 
  235.      * @see QAL::selectRequest()
  236.      */
  237.     public function buildWhereCondition($condition{
  238.         $result '';
  239.  
  240.         if (!empty($condition)) {
  241.             $result ' WHERE ';
  242.  
  243.             if (is_array($condition)) {
  244.                 $cond array();
  245.                 foreach ($condition as $fieldName => $value{
  246.                     //$fieldName = strtolower($fieldName);
  247.                     if (is_null($value)) {
  248.                         $cond["$fieldName IS NULL";
  249.                     }
  250.                     elseif (is_numeric($fieldName)) {
  251.                         $cond[$value;
  252.                     }
  253.                     elseif (is_array($value)) {
  254.                         $value implode(',',array_filter($value));
  255.                         if(!empty($value))
  256.                             $cond[$fieldName.' IN ('.$value.')';
  257.                         else $cond[' FALSE ';    
  258.                     }
  259.                     else {
  260.                         $cond["$fieldName = ".$this->quote($value);
  261.                     }
  262.                 }
  263.                 $result .= implode(' AND '$cond);
  264.             }
  265.             else {
  266.                 $result .= $condition;
  267.             }
  268.         }
  269.  
  270.         return $result;
  271.     }
  272.  
  273.     /**
  274.      * ВОзвращает данные из таблицы связанной по внешнему ключу
  275.      *
  276.      * @param string Имя таблицы
  277.      * @param string имя ключа
  278.      * @param int идентификатор текущего языка
  279.      * @param mixed ограничение на выборку
  280.      * @access public
  281.      * @return array 
  282.      *
  283.      * @todo Исключать поля типа текст из результатов выборки для таблицы с переводами
  284.      * @todo Подключить фильтрацию
  285.      */
  286.     public function getForeignKeyData($fkTableName$fkKeyName$currentLangID$filter null{
  287.         $fkValueName substr($fkKeyName0strpos($fkKeyName'_')).'_name';
  288.  
  289.         //если существует таблица с переводами для связанной таблицы
  290.         //нужно брать значения оттуда
  291.         if ($transTableName $this->getTranslationTablename($fkTableName)) {
  292.             if($filter){
  293.                $filter ' AND '.str_replace('WHERE'''$this->buildWhereCondition($filter));    
  294.             }
  295.             else{
  296.                 $filter '';
  297.             }
  298.             
  299.             $request sprintf(
  300.                 'SELECT 
  301.                     %2$s.*, %3$s.%s 
  302.                     FROM %s %2$s 
  303.                     LEFT JOIN %s %3$s on %3$s.%s = %2$s.%s 
  304.                     WHERE lang_id =%s'.$filter
  305.                 $fkValueName
  306.                 $fkTableName
  307.                 $transTableName
  308.                 $fkKeyName
  309.                 $fkKeyName
  310.                 $currentLangID
  311.             );
  312.             $res $this->selectRequest($request);
  313.         }
  314.         else {
  315.             $columns $this->getColumnsInfo($fkTableName);
  316.             $columns array_filter($columns,
  317.                 create_function('$value''return !($value["type"] == QAL::COLTYPE_TEXT);')
  318.             );
  319.             $res $this->select($fkTableNamearray_keys($columns)$filterarray($fkValueName=>QAL::ASC));
  320.         }
  321.  
  322.         return array($res$fkKeyName$fkValueName);
  323.     }
  324.  
  325.     /**
  326.      * Строит предложение ORDER BY для SQL-запроса.
  327.      *
  328.      * @access public
  329.      * @param mixed $order 
  330.      * @return string 
  331.      * @see QAL::selectRequest()
  332.      */
  333.     public function buildOrderCondition($clause{
  334.         $orderClause ' ORDER BY ';
  335.  
  336.         if (is_array($clause)) {
  337.             $cls array();
  338.             foreach ($clause as $fieldName => $direction{
  339.                 //$fieldName = strtolower($fieldName);
  340.                 $cls["$fieldName ".constant("self::$direction");
  341.             }
  342.             $orderClause .= implode(', '$cls);
  343.         }
  344.         else {
  345.             $orderClause .= $clause;
  346.         }
  347.  
  348.         return $orderClause;
  349.     }
  350.  
  351.     /**
  352.      * Строит предложение LIMIT для SQL-запроса.
  353.      *
  354.      * @access public
  355.      * @param mixed $limit 
  356.      * @return string 
  357.      * @see QAL::selectRequest()
  358.      */
  359.     public function buildLimitStatement($clause{
  360.         $limitClause '';
  361.         if (is_array($clause)) {
  362.             $limitClause " LIMIT {$clause[0]}";
  363.             if (isset($clause[1])) {
  364.                 $limitClause .= ", {$clause[1]}";
  365.             }
  366.         }
  367.  
  368.         return $limitClause;
  369.     }
  370. }
В создании документации нам помог: phpDocumentor