Source for file DBDataSet.class.php

Documentation is available at DBDataSet.class.php

  1. /**
  2.  * Содержит класс DBDataSet
  3.  *
  4.  * @package energine
  5.  * @author dr.Pavka
  6.  * @copyright ColoCall 2006
  7.  * @version $Id: fsource_energine__modulessharecomponentsDBDataSet.class.php.html,v 1.1 2007/09/17 14:32:31 pavka Exp $
  8.  */
  9.  
  10. require_once('core/modules/share/components/DataSet.class.php');
  11. require_once('core/framework/MultiLanguageBuilder.class.php');
  12.  
  13. /**
  14.  * Класс позволяющий выводить  данные из БД
  15.  *
  16.  * @package energine
  17.  * @subpackage share
  18.  */
  19. class DBDataSet extends DataSet {
  20.  
  21.     /**
  22.      * Имя таблицы содержащей переводы
  23.      *
  24.      * @var string 
  25.      * @access private
  26.      */
  27.     private $translationTableName = false;
  28.  
  29.     /**
  30.      * Имя поля первичного ключа
  31.      *
  32.      * @var string 
  33.      * @access private
  34.      */
  35.     private $pk = false;
  36.  
  37.     /**
  38.      * Условия выборки
  39.      *
  40.      * @var mixed (string | array)
  41.      * @access private
  42.      */
  43.     private $filter = null;
  44.  
  45.     /**
  46.      * Условие сортировки
  47.      *
  48.      * @var array 
  49.      * @access protected
  50.      */
  51.     private $order = null;
  52.  
  53.     /**
  54.      * Ограничение количества записей
  55.      *
  56.      * @var array 
  57.      * @access private
  58.      */
  59.     private $limit = null;
  60.  
  61.     /**
  62.      * Действие которое исполнялось на предыдущем шаге
  63.      * используется в методе сохранения
  64.      *
  65.      * @var string 
  66.      * @access private
  67.      */
  68.     private $previousAction = false;
  69.  
  70.     /**
  71.      * Конструктор класса
  72.      *
  73.      * @return void 
  74.      */
  75.     public function __construct($name$moduleDocument $document,  array $params null{
  76.         parent::__construct($name$module$document,  $params);
  77.         $this->setType(self::COMPONENT_TYPE_LIST);
  78.     }
  79.  
  80.     /**
  81.      * Добавлен параметр tableName
  82.      *
  83.      * @return type 
  84.      * @access protected
  85.      */
  86.  
  87.     protected function defineParams({
  88.         return array_merge(
  89.         parent::defineParams(),
  90.         array(
  91.         'tableName' => false,
  92.         'onlyCurrentLang' => false
  93.         )
  94.         );
  95.     }
  96.  
  97.     /**
  98.      * Переопределенный метод загрузки описания данных
  99.      * Возвращает информацию о колонках в основной таблице и таблице переводов
  100.      *
  101.      * @return array 
  102.      * @access protected
  103.      */
  104.     protected function loadDataDescription({
  105.         $result $this->dbh->getColumnsInfo($this->getTableName());
  106.         if ($this->getTranslationTableName()) {
  107.             $transColumnsDescription $this->dbh->getColumnsInfo($this->getTranslationTableName());
  108.             foreach (array_keys($transColumnsDescriptionas $fieldName{
  109.                 //для всех полей кроме идентификатора языка и первичного ключа выставляем дополнительное свойство isMultiLanguage
  110.                 if (!in_array($fieldNamearray($this->getPK()'lang_id'))) {
  111.                     $transColumnsDescription[$fieldName]['isMultilanguage'true;
  112.                 }
  113.                 elseif ($fieldName === 'lang_id' && $this->getPK(!== 'lang_id'{
  114.                     $transColumnsDescription[$fieldName]['languageID'true;
  115.                 }
  116.             }
  117.             $result += $transColumnsDescription;
  118.             if (isset($result['lang_id'])) {
  119.                 $result['lang_id']['key'false;
  120.             }
  121.             else {
  122.                 throw new SystemException('ERR_DEV_NO_LANG_ID'SystemException::ERR_DEVELOPER);
  123.             }
  124.         }
  125.  
  126.         return $result;
  127.     }
  128.  
  129.     /**
  130.       * Переопределенный метод загрузки данных
  131.       *
  132.       * @return array 
  133.       * @access protected
  134.       */
  135.     protected function loadData({
  136.         $data false;
  137.         if ($this->pager{
  138.             // pager существует -- загружаем только часть данных, текущую страницу
  139.             $this->setLimit($this->pager->getLimit());
  140.         }
  141.         //Если не существует таблицы с переводами, то выбираем данные из основной таблицы
  142.         if (!$this->getTranslationTableName()) {
  143.             $dbFields array();
  144.             foreach ($this->getDataDescription()->getFieldDescriptions(as $fieldName => $field{
  145.                 if (is_null($field->getPropertyValue('customField'))) {
  146.                     array_push($dbFields$fieldName);
  147.                 }
  148.             }
  149.             //Если не пустой массив полей для отбора
  150.             if (!empty($dbFields)) {
  151.                 if ($this->pager{
  152.                     $recordCount simplifyDBResult($this->dbh->select($this->getTableName()'count(*) as recordsCount'$this->getFilter())'recordsCount'true);
  153.                     $this->pager->setRecordsCount($recordCount);
  154.                 }
  155.                 if ($this->getType(== self::COMPONENT_TYPE_FORM_ADD {
  156.                     $dbFields = array_flip($dbFields);
  157.                     foreach ($dbFields as $key => $value{
  158.                         $dbFields[$key'';
  159.                     }
  160.                     $res array($dbFields);
  161.                 }
  162.                 else {
  163.                     $res $this->dbh->select($this->getTableName()$dbFields$this->getFilter()$this->getOrder()$this->getLimit());
  164.                 }
  165.                 if (is_array($res)) {
  166.                     $data $res;
  167.                 }
  168.             }
  169.         }
  170.         else {
  171.             //Для мультиязычной таблицы - дергаем метод загрузки данных
  172.             $data $this->multiLoadData();
  173.         }
  174.         return $data;
  175.     }
  176.     /**
  177.      * Возвращает язык, на котором берутся данные
  178.      *
  179.      * @return int 
  180.      * @access protected
  181.      */
  182.  
  183.     protected function getDataLanguage({
  184.         $result false;
  185.         if ($this->getParam('onlyCurrentLang')) {
  186.             $result $this->document->getLang();
  187.         }
  188.         return $result;
  189.     }
  190.  
  191.     /**
  192.      * Загрузка мультиязычных данных
  193.      *
  194.      * @return array 
  195.      * @access private
  196.      */
  197.  
  198.     private function multiLoadData({
  199.         $data false;
  200.         $lang Language::getInstance();
  201.         $lang $lang->getLanguages();
  202.         $dbFields array();
  203.  
  204.         $filter $order $limit '';
  205.         //Создаем перечень полей  в формате array('имя основной таблицы' => array('имя поля'=>'имя таблицы.имя поля'), 'имя таблицыпереводов' => array('имя поля'=>'имя таблицы.имя поля'))
  206.         foreach ($this->getDataDescription()->getFieldDescriptions(as $fieldName => $field{
  207.             //Не включаем в набор идентификатор языка
  208.             if (!$field->getPropertyValue('languageID'&& $field->getPropertyValue('key'!== true{
  209.                 //не включаем в набор поля полученные  из конфигурации
  210.                 if (is_null($field->getPropertyValue('customField'))) {
  211.                     $dbFields[$field->getPropertyValue('tableName')][$fieldName$field->getPropertyValue('tableName').'.'.$fieldName;
  212.                 }
  213.             }
  214.         }
  215.  
  216.         if (!is_null($this->getOrder())){
  217.             $order $this->dbh->buildOrderCondition($this->getOrder());
  218.         }
  219.  
  220.         if (!is_null($this->getFilter())) {
  221.             $filter $this->dbh->buildWhereCondition($this->getFilter()).($this->getParam('onlyCurrentLang')?' AND lang_id = '.$this->getDataLanguage():'');
  222.         }
  223.         elseif($this->getDataLanguage(&&  $this->getParam('onlyCurrentLang')) {
  224.             $filter ' WHERE lang_id = '.$this->getDataLanguage();
  225.         }
  226.  
  227.         if (!is_null($this->getLimit())) {
  228.             $limit $this->getLimit();
  229.             $limit $this->dbh->buildLimitStatement($limit);
  230.         }
  231.  
  232.         //Если существует листалка указываем ей количество записей
  233.         if ($this->pager{
  234.             //Определяем общее количество записей
  235.             $request = sprintf(
  236.             "SELECT COUNT(*) as records_count
  237.                    FROM %s
  238.                    LEFT JOIN %s ON %s.%s = %s.%s
  239.                    %s
  240.                    ",
  241.             $this->getTableName(),
  242.             $this->getTranslationTableName()$this->getTranslationTableName()$this->getPK()$this->getTableName()$this->getPK(),
  243.             $filter
  244.             );
  245.             $recordsCount $this->dbh->selectRequest($request);
  246.             $recordsCount simplifyDBResult($recordsCount'records_count'true);
  247.             $this->pager->setRecordsCount($recordsCount);
  248.         }
  249.         if ($this->getType(!= self::COMPONENT_TYPE_FORM_ADD{
  250.             $request=sprintf(
  251.             "SELECT
  252.                    %s.%s, %s.lang_id,
  253.                    %s
  254.                    %s
  255.                    FROM %s
  256.                    LEFT JOIN %s ON %s.%s = %s.%s
  257.                    %s
  258.                    %s
  259.                    %s
  260.                    ",
  261.             $this->getTableName()$this->getPK()$this->getTranslationTableName(),
  262.             (isset($dbFields[$this->getTableName()]))?implode(','$dbFields[$this->getTableName()]):'',
  263.             isset($dbFields[$this->getTranslationTableName()])?((isset($dbFields[$this->getTableName()]))?',':'').implode(','$dbFields[$this->getTranslationTableName()]):'',
  264.             $this->getTableName(),
  265.             $this->getTranslationTableName()$this->getTranslationTableName()$this->getPK()$this->getTableName()$this->getPK(),
  266.             $filter,
  267.             $order,
  268.             $limit
  269.             );
  270.  
  271.             $data $this->dbh->selectRequest($request);
  272.  
  273.             //Если данные не только для текущего языка
  274.             if (is_array($data&&(!$this->getDataLanguage(|| $this->getDataLanguage()&&!$this->getParam('onlyCurrentLang'&& isset($dbFields[$this->getTranslationTableName()]))) {
  275.  
  276.                 //формируем матрицу
  277.                 foreach ($data as $row{
  278.                     $matrix[$row[$this->getPK()]][$row['lang_id']] $row;
  279.                 }
  280.                 //формируем образец
  281.                 //в нем все языкозависимые поля заполнены nullами
  282.                 foreach (array_keys($dbFields[$this->getTranslationTableName()]as $fieldName{
  283.                     $translationColumns['NULL as '.$fieldName;
  284.                 }
  285.                 $request = sprintf('
  286.                     SELECT %s, %s %s
  287.                     FROM %s
  288.                     WHERE %s IN(%s)
  289.                 ',
  290.                 $this->getPK()(isset($dbFields[$this->getTableName()]))?implode(','$dbFields[$this->getTableName()]).',':''implode(','$translationColumns),
  291.                 $this->getTableName(),
  292.                 $this->getPK()implode(','array_keys($matrix)));
  293.                 $res $this->dbh->selectRequest($request);
  294.  
  295.                 foreach ($res as $row{
  296.                     $template[$row[$this->getPK()]] $row;
  297.                 }
  298.  
  299.                 $data array();
  300.  
  301.                 if ($this->getDataLanguage()&&!$this->getParam('onlyCurrentLang')) {
  302.                     $lang array($this->getDataLanguage(=> $lang[$this->getDataLanguage()]);
  303.                 }
  304.  
  305.                 foreach ($matrix as $ltagID => $langVersions{
  306.                     foreach (array_keys($langas $langID{
  307.                         if (isset($langVersions[$langID])) {
  308.                             $data[$langVersions[$langID];
  309.                         }
  310.                         else {
  311.                             $data[arrayPush($data$template[$ltagID])]['lang_id'$langID;
  312.                         }
  313.                     }
  314.                 }
  315.             }
  316.         }
  317.         else {
  318.             $i=0;
  319.             $dbFields = array_merge(
  320.             array_keys($dbFields[$this->getTableName()]),
  321.             array_keys($dbFields[$this->getTranslationTableName()])
  322.             );
  323.             $dbFields = array_flip($dbFields);
  324.             foreach ($dbFields as $key => $value{
  325.                 $dbFields[$key'';
  326.             }
  327.             foreach (array_keys($langas $langID{
  328.                 $data[$i][$this->getPK()null;
  329.                 $data[$i]['lang_id'$langID;
  330.                 $data[$i= array_merge($data[$i]$dbFields);
  331.                 $i++;
  332.             }
  333.         }
  334.  
  335.         return $data;
  336.     }
  337.  
  338.     /**
  339.      * Устанавливает имя таблицы
  340.      *
  341.      * @param string 
  342.      * @return type 
  343.      * @access protected
  344.      */
  345.  
  346.     protected function setTableName($tableName{
  347.         $this->setParam('tableName'$tableName);
  348.     }
  349.     /**
  350.      * Для параметра tableName устанавливаем еще и имя таблицы переводов
  351.      *
  352.      * @param string $name 
  353.      * @param mixed $value 
  354.      * @return void 
  355.      * @access protected
  356.      */
  357.  
  358.     protected function setParam($name$value{
  359.         if ($name == 'tableName'{
  360.             $this->translationTableName $this->dbh->getTranslationTablename($value);
  361.         }
  362.  
  363.         parent::setParam($name$value);
  364.     }
  365.     /**
  366.      * Возвращает имя таблицы
  367.      *
  368.      * @return string 
  369.      * @access protected
  370.      * @final
  371.      */
  372.  
  373.     final protected function getTableName({
  374.         if (!$this->getParam('tableName')) {
  375.             throw new SystemException('ERR_DEV_NO_TABLENAME'SystemException::ERR_DEVELOPER);
  376.         }
  377.  
  378.         return $this->getParam('tableName');
  379.     }
  380.  
  381.     /**
  382.      * Возвращает значение фильтра
  383.      *
  384.      * @return mixed 
  385.      * @access protected
  386.      * @final
  387.      */
  388.  
  389.     final protected function getFilter({
  390.         return $this->filter;
  391.     }
  392.  
  393.     /**
  394.      * Устанавливает значение фильтра
  395.      *
  396.      * @param mixed 
  397.      * @return void 
  398.      * @access protected
  399.      * @final
  400.      * @see QAL::select()
  401.      */
  402.  
  403.     final protected function setFilter($filter{
  404.         if (empty($filter)) {
  405.             throw new SystemException('ERR_DEV_BAD_FILTER'SystemException::ERR_DEVELOPER'Воспользуйтесь методом clearFilter()');
  406.         }
  407.         if (is_numeric($filter)) {
  408.             $filter array($this->getTableName().'.'.$this->getPK()=>$filter);
  409.         }
  410.  
  411.         $this->filter $filter;
  412.     }
  413.  
  414.     /**
  415.      * Сброс фильтра
  416.      *
  417.      * @return void 
  418.      * @access protected
  419.      * @final
  420.      */
  421.  
  422.     final protected function clearFilter({
  423.         $this->filter null;
  424.     }
  425.  
  426.     /**
  427.      * Возвращает условия сортровки
  428.      *
  429.      * @return array 
  430.      * @access protected
  431.      * @final
  432.      */
  433.  
  434.     final protected function getOrder({
  435.         return $this->order;
  436.     }
  437.  
  438.     /**
  439.      * Устанавливает условие сортровки
  440.      *
  441.      * @param mixed 
  442.      * @return void 
  443.      * @access protected
  444.      * @final
  445.      */
  446.  
  447.     final protected function setOrder($order{
  448.         if (is_array($order)) {
  449.             if (!in_array(current($order)array(QAL::ASCQAL::DESC))) {
  450.                 throw new SystemException('ERR_DEV_BAD_ORDER_FORMAT'SystemException::ERR_DEVELOPER);
  451.             }
  452.             $this->order $order;
  453.         }
  454.         else {
  455.             $this->order array($order=>QAL::ASC);
  456.         }
  457.     }
  458.  
  459.     /**
  460.      * Возвращает ограничения по количеству записей
  461.      *
  462.      * @return array 
  463.      * @access protected
  464.      * @final
  465.      */
  466.  
  467.     final protected function getLimit({
  468.         return $this->limit;
  469.     }
  470.  
  471.     /**
  472.      * Устанавливает ограничения по количеству записей
  473.      *
  474.      * @param array 
  475.      * @return void 
  476.      * @access protected
  477.      * @final
  478.      */
  479.  
  480.     final protected function setLimit(array $limit{
  481.         $this->limit $limit;
  482.     }
  483.  
  484.  
  485.  
  486.     /**
  487. /**
  488.      * Возвращает имя поля - первичного ключа
  489.      *
  490.      * @return string 
  491.      * @access protected
  492.      * @final
  493.      */
  494.  
  495.     final protected function getPK({
  496.         if (!$this->pk{
  497.             $res $this->dbh->getColumnsInfo($this->getTableName());
  498.             if (is_array($res)) {
  499.                 foreach ($res as $fieldName => $fieldInfo{
  500.                     if ($fieldInfo['key'=== true{
  501.                         $this->pk $fieldName;
  502.                     }
  503.                 }
  504.                 if (!isset($this->pk)) {
  505.                     throw new SystemException('ERR_DEV_NO_PK'SystemException::ERR_DEVELOPER);
  506.                 }
  507.             }
  508.             else {
  509.                 throw new SystemException('ERR_DEV_NO_PK'SystemException::ERR_DEVELOPER);
  510.             }
  511.  
  512.         }
  513.  
  514.         return $this->pk;
  515.     }
  516.  
  517.     /**
  518.      * Для мультиязычного грида
  519.      * подменяем построитель
  520.      *
  521.      * @return Builder 
  522.      * @access protected
  523.      */
  524.  
  525.     protected function createBuilder({
  526.         if (!$this->getTranslationTableName()) {
  527.             $result parent::createBuilder();
  528.         }
  529.         else {
  530.             $result new MultiLanguageBuilder();
  531.         }
  532.         return $result;
  533.     }
  534.  
  535.     /**
  536.      * добавлена обработка ключей
  537.      *
  538.      * @return DataDescription 
  539.      * @access protected
  540.      */
  541.  
  542.     protected function createDataDescription({
  543.         $result parent::createDataDescription();
  544.         foreach ($result->getFieldDescriptions(as $fieldName => $fieldMetaData{
  545.             $keyInfo $fieldMetaData->getPropertyValue('key');
  546.             //Если это внешний ключ
  547.             if (is_array($keyInfo)) {
  548.                 $fkTableName $keyInfo['tableName'];
  549.                 $fkKeyName $keyInfo['fieldName'];
  550.                 //загружаем информацию о возможных значениях
  551.                 call_user_func_array(array($fieldMetaData'loadAvailableValues')$this->getFKData($fkTableName$fkKeyName));
  552.  
  553.             }
  554.         }
  555.         return $result;
  556.     }
  557.  
  558.     /**
  559.      * Возвращает данные о значения в связанной таблицы
  560.      *
  561.      * @return array 
  562.      * @access protected
  563.      */
  564.  
  565.     protected function getFKData($fkTableName$fkKeyName{
  566.         $fkValueName = substr($fkKeyName0strpos($fkKeyName'_')).'_name';
  567.         //если существует таблица с переводами для связанной таблицы
  568.         //нужно брать значения оттуда
  569.         $transTableName $this->dbh->getTranslationTablename($fkTableName);
  570.  
  571.         if ($transTableName{
  572.             $request = sprintf('SELECT main.*,trans.%s FROM %s main LEFT JOIN %s trans on trans.%s = main.%s WHERE lang_id =%s'$fkValueName$fkTableName$transTableName$fkKeyName$fkKeyName$this->document->getLang());
  573.             $res $this->dbh->selectRequest($request);
  574.         }
  575.         else {
  576.             $res $this->dbh->select($fkTableName);
  577.         }
  578.  
  579.         return array($res$fkKeyName$fkValueName);
  580.     }
  581.  
  582.     /**
  583.      * Возвращает имя таблицы переводов
  584.      *
  585.      * @return string 
  586.      * @access protected
  587.      * @final
  588.      */
  589.  
  590.     final protected function getTranslationTableName({
  591.         return $this->translationTableName;
  592.     }
  593.  
  594.     /**
  595.      * Метод выводит форму просмотра
  596.      *
  597.      * @return void 
  598.      * @access protected
  599.      */
  600.  
  601.     protected function view({
  602.         $this->setType(self::COMPONENT_TYPE_FORM);
  603.         //$this->addCrumb('TXT_VIEW_ITEM');
  604.         $id $this->getActionParams();
  605.         list($id$id;
  606.         if (!$this->recordExists($id)) {
  607.             throw new SystemException('ERR_404'SystemException::ERR_404);
  608.         }
  609.         $this->setFilter($id);
  610.  
  611.         $this->prepare();
  612.         foreach ($this->getDataDescription()->getFieldDescriptions(as $fieldDescription{
  613.             $fieldDescription->setMode(FieldDescription::FIELD_MODE_READ);
  614.         }
  615.     }
  616.  
  617.     /**
  618.      * Определяет существует ли запись с идентификатором переданным в параметре
  619.      * Вызывается из методов где нужно быть уверенным в наличии записи(view, edit,delete)
  620.      *
  621.      * @param string 
  622.      * @param mixed 
  623.      * @return void 
  624.      * @access protected
  625.      * @final
  626.      */
  627.  
  628.     final protected function recordExists($id$fieldName false{
  629.         if (!$fieldName{
  630.             $fieldName $this->getPK();
  631.         }
  632.  
  633.         $res $this->dbh->select($this->getTableName()array($fieldName)array($fieldName=>$id));
  634.         return is_array($res);
  635.     }
  636.  
  637.     /**
  638.      * Возвращает предыдущее действие
  639.      *
  640.      * @return string 
  641.      * @access protected
  642.      * @final
  643.      */
  644.  
  645.     final protected function getPreviousAction({
  646.         if (!$this->previousAction{
  647.             if (!isset($_POST['componentAction'])) {
  648.                 throw new SystemException('ERR_NO_COMPONENT_ACTION'SystemException::ERR_CRITICAL);
  649.             }
  650.             else {
  651.                 $this->previousAction $_POST['componentAction'];
  652.             }
  653.         }
  654.  
  655.         return $this->previousAction;
  656.     }
  657. }

Documentation generated on Mon, 17 Sep 2007 13:27:15 +0300 by phpDocumentor 1.4.0a2