Source for file Grid.class.php

Documentation is available at Grid.class.php

  1.  
  2. /**
  3.  * Содержит класс Grid
  4.  *
  5.  * @package energine
  6.  * @author dr.Pavka
  7.  * @copyright ColoCall 2006
  8.  * @version $Id: fsource_energine__modulessharecomponentsGrid.class.php.html,v 1.1 2007/09/17 14:32:31 pavka Exp $
  9.  */
  10.  
  11. require_once('core/modules/share/components/DBDataSet.class.php');
  12. require_once('core/framework/JSONBuilder.class.php');
  13. require_once('core/framework/Saver.class.php');
  14. require_once('core/framework/FormException.class.php');
  15. require_once('core/modules/share/components/FileLibrary.class.php');
  16. /**
  17.  * Сетка
  18.  *
  19.  * @package energine
  20.  * @subpackage share
  21.  */
  22. class Grid extends DBDataSet {
  23.     /**
  24.      * Направление вверх
  25.      *
  26.      */
  27.     const DIR_UP = '<';
  28.     /**
  29.      * Направление вниз
  30.      *
  31.      */
  32.     const DIR_DOWN = '>';
  33.     /**
  34.      * Количество записей в гриде по умолчанию
  35.      *
  36.      */
  37.     const RECORD_PER_PAGE = 30;
  38.  
  39.     /**
  40.      * Компонент: менеджер изображений
  41.      *
  42.      * @var ImageManager 
  43.      * @access private
  44.      */
  45.     private $imageManager;
  46.  
  47.     /**
  48.      * Компонент: библиотека изображений
  49.      *
  50.      * @var FileLibrary 
  51.      * @access private
  52.      */
  53.     private $fileLibrary;
  54.  
  55.     /**
  56.      * сейвер
  57.      *
  58.      * @var Saver 
  59.      * @access protected
  60.      */
  61.     protected $saver;
  62.  
  63.     /**
  64.      * Имя колонки для определения порядка пользовательскорй сортировки
  65.      *
  66.      * @var string 
  67.      * @access private
  68.      */
  69.     private $orderColumn = false;
  70.  
  71.  
  72.     /**
  73.      * Конструктор класса
  74.      *
  75.      * @param string $name 
  76.      * @param string $module 
  77.      * @param Document $document 
  78.      * @param array $params 
  79.      * @access public
  80.      */
  81.     public function __construct($name$moduleDocument $document,  array $params null{
  82.         parent::__construct($name$module$document,  $params);
  83.         $this->setProperty('grid''grid');
  84.         if (!$this->getParam('recordsPerPage')) {
  85.             $this->setParam('recordsPerPage'self::RECORD_PER_PAGE);
  86.         }
  87.         $this->setTitle($this->translate('TXT_'.strtoupper($this->getName())));
  88.     }
  89.     /**
  90.      * Переопределен параметр configFilename
  91.      *
  92.      * @return int 
  93.      * @access protected
  94.      */
  95.  
  96.      protected function defineParams({
  97.         $params array();
  98.         if (!$this->params['configFilename']{
  99.             $fileConf ComponentConfig::SITE_CONFIG_DIR.get_class($this).'.component.xml';
  100.             $coreConf = sprintf(ComponentConfig::CORE_CONFIG_DIR$this->module).get_class($this).'.component.xml';
  101.             if (file_exists($fileConf)) {
  102.                 $params['configFilename'$fileConf;
  103.             }
  104.             elseif (file_exists($coreConf)) {
  105.                 $params['configFilename'$coreConf;
  106.             }
  107.             else {
  108.                 $params['configFilename'= sprintf(ComponentConfig::CORE_CONFIG_DIR'share/').'Grid.component.xml';
  109.             }
  110.         }
  111.         $params['active'true;
  112.         return array_merge(parent::defineParams(),$params);
  113.      }
  114.     /**
  115.      * Метод выводящий форму добавления
  116.      *
  117.      * @return void 
  118.      * @access protected
  119.      */
  120.  
  121.     protected function add({
  122.         $this->setType(self::COMPONENT_TYPE_FORM_ADD);
  123.         $this->prepare();
  124.  
  125.         //$this->addCrumb('TXT_ADD_ITEM');
  126.     }
  127.  
  128.     /**
  129.      * Метод выводящий форму редактирования
  130.      *
  131.      * @return void 
  132.      * @access protected
  133.      */
  134.  
  135.     protected function edit({
  136.         $this->setType(self::COMPONENT_TYPE_FORM_ALTER);
  137.  
  138.         $id $this->getActionParams();
  139.         list($id$id;
  140.         if (!$this->recordExists($id)) {
  141.             throw new SystemException('ERR_404'SystemException::ERR_404);
  142.         }
  143.         $this->setFilter($id);
  144.  
  145.         $this->prepare();
  146.     }
  147.  
  148.     /**
  149.      * Добавлены переводы для фильтра
  150.      *
  151.      * @return void 
  152.      * @access protected
  153.      */
  154.  
  155.      protected function main({
  156.         parent::main();
  157.         $this->addTranslation('TXT_FILTER');
  158.         $this->addTranslation('BTN_APPLY_FILTER');
  159.         $this->addTranslation('TXT_RESET_FILTER');
  160.      }
  161.  
  162.     /**
  163.      * Внешний метод удаления
  164.      *
  165.      * @return mixed 
  166.      * @access protected
  167.      * @see Grid::save()
  168.      */
  169.  
  170.     protected function delete({
  171.         $transactionStarted $this->dbh->beginTransaction();
  172.         try {
  173.             list($id$this->getActionParams();
  174.             if (!$this->recordExists($id)) {
  175.                 throw new SystemException('ERR_404'SystemException::ERR_404);
  176.             }
  177.  
  178.             $this->deleteData($id);
  179.  
  180.             $JSONResponse array(
  181.             'result'=>true
  182.             );
  183.             $this->dbh->commit();
  184.         }
  185.         catch (SystemException $e){
  186.             if ($transactionStarted{
  187.                 $this->dbh->rollback();
  188.             }
  189.             $JSONResponse $this->generateError($e->getCode()$e->getMessage());
  190.  
  191.         }
  192.         $this->response->write(json_encode($JSONResponse));
  193.         $this->response->commit();
  194.     }
  195.  
  196.     /**
  197.      * Внутренний метод удаления записи
  198.      *
  199.      * @param int идентификаотр записи
  200.      * @return void 
  201.      * @access protected
  202.      */
  203.  
  204.     protected function deleteData($id{
  205.         $this->dbh->modify(QAL::DELETE $this->getTableName()nullarray($this->getPK()=>$id));
  206.     }
  207.  
  208.     /**
  209.      * переписан родительский метод
  210.      *
  211.      * @return int 
  212.      * @access protected
  213.      */
  214.  
  215.     protected function getDataLanguage({
  216.         if (isset($_POST['languageID']&& $this->getAction()=='getRawData'{
  217.             $langID $_POST['languageID'];
  218.             if (!Language::getInstance()->isValidLangID($langID)) {
  219.                 throw new SystemException('ERR_BAD_LANG_ID'SystemException::ERR_WARNING);
  220.             }
  221.             $result $langID;
  222.         }
  223.         else $result parent::getDataLanguage();
  224.  
  225.         return $result;
  226.     }
  227.  
  228.  
  229.     /**
  230.      * Выводит данные в JSON формате для AJAX
  231.      *
  232.      * @return void 
  233.      * @access protected
  234.      */
  235.  
  236.     protected function getRawData({
  237.  
  238.         try {
  239.             $this->setParam('onlyCurrentLang'true);
  240.             $this->config->setCurrentMethod(self::DEFAULT_ACTION_NAME);
  241.             $this->setBuilder(new JSONBuilder());
  242.  
  243.             $this->setDataDescription($this->createDataDescription());
  244.             $this->createPager();
  245.             $this->getBuilder()->setDataDescription($this->getDataDescription());
  246.             $data $this->createData();
  247.             if ($data instanceof Data{
  248.                 $this->setData($data);
  249.                 $this->getBuilder()->setData($this->getData());
  250.             }
  251.  
  252.             if ($this->getBuilder()->build()) {
  253.                 if ($this->pager$this->getBuilder()->setPager($this->pager);
  254.                 $result $this->getBuilder()->getResult();
  255.             }
  256.             else {
  257.                 $result $this->getBuilder()->getErrors();
  258.             }
  259.  
  260.         }
  261.         catch (Exception $e){
  262.             $message['errors'][array('message'=>$e->getMessage().current($e->getCustomMessage()));
  263.             $result = json_encode(array_merge(array('result'=>false'header'=>$this->translate('TXT_SHIT_HAPPENS'))$message));
  264.         }
  265.  
  266.         $this->response->write($result);
  267.         $this->response->commit();
  268.     }
  269.  
  270.     /**
  271.      * Внешний метод сохранения
  272.      * Вызывает внутренний метод сохранения saveData(), который и производит собственно все действия
  273.      *
  274.      * @return void 
  275.      * @access protected
  276.      */
  277.  
  278.     protected function save({
  279.         $transactionStarted $this->dbh->beginTransaction();
  280.         try {
  281.             $result $this->saveData();
  282.  
  283.             $transactionStarted !($this->dbh->commit());
  284.             $JSONResponse array(
  285.             'result' => true,
  286.             'mode' => (is_int($result))?'insert':'update'
  287.             );
  288.         }
  289.         catch (FormException $formError{
  290.             $this->dbh->rollback();
  291.             //Формируем JS массив ошибок который будет разбираться на клиенте
  292.             $errors $this->saver->getErrors();
  293.             foreach ($errors as $errorFieldName{
  294.                 $message['errors'][array(
  295.                 'field'=>$this->translate('FIELD_'.strtoupper($errorFieldName)),
  296.                 'message'=>$this->translate($this->saver->getDataDescription()->getFieldDescriptionByName($errorFieldName)->getPropertyValue('message'))
  297.                 );
  298.             }
  299.             $JSONResponse = array_merge(array('result'=>false'header'=>$this->translate('TXT_SHIT_HAPPENS'))$message);
  300.         }
  301.         catch (SystemException $e){
  302.             if ($transactionStarted{
  303.                 $this->dbh->rollback();
  304.             }
  305.             $message['errors'][array('message'=>$e->getMessage().current($e->getCustomMessage()));
  306.             $JSONResponse = array_merge(array('result'=>false'header'=>$this->translate('TXT_SHIT_HAPPENS'))$message);
  307.  
  308.         }
  309.         $this->response->write(json_encode($JSONResponse));
  310.         $this->response->commit();
  311.     }
  312.  
  313.     /**
  314.      * Переписан родительский метод генерации ошибки, поскольку для AJAX такая не подходит
  315.      *
  316.      * @param string тип ошибки
  317.      * @param string сообщение об ошибке
  318.      * @param mixed  необязательная дополнительная информация об ошибке
  319.      *
  320.      * @return void 
  321.      * @access protected
  322.      */
  323.     protected function generateError($errorType$errorMessage$errorCustomInfo false{
  324.         $message['errors'][array('message'=>$errorMessage);
  325.         $response = array_merge(array('result'=>false'header'=>$this->translate('TXT_SHIT_HAPPENS'))$message);
  326.         return $response;
  327.     }
  328.  
  329.     /**
  330.      * Внутренний метод сохранения
  331.      *
  332.      * @return mixed 
  333.      * @access protected
  334.      */
  335.  
  336.     protected function saveData ({
  337.         $result false;
  338.         //если в POST не пустое значение значение первичного ключа - значит мы находимся в режиме редактирования
  339.         if (isset($_POST[$this->getTableName()][$this->getPK()]&& !empty($_POST[$this->getTableName()][$this->getPK()])) {
  340.             $mode self::COMPONENT_TYPE_FORM_ALTER;
  341.             $this->setFilter(array($this->getPK()=>$_POST[$this->getTableName()][$this->getPK()]));
  342.         }
  343.         else {
  344.             $mode self::COMPONENT_TYPE_FORM_ADD;
  345.         }
  346.  
  347.         //создаем объект описания данных
  348.         $dataDescriptionObject new DataDescription();
  349.  
  350.         if (!method_exists($this$this->getPreviousAction())) {
  351.             throw new SystemException('ERR_NO_ACTION'SystemException::ERR_CRITICAL);
  352.         }
  353.  
  354.         //получаем описание полей для метода
  355.         $configDataDescription $this->config->getMethodConfig($this->getPreviousAction());
  356.         //если в конфиге есть описание полей для метода - загружаем их
  357.         if (isset($configDataDescription->fields)) {
  358.             $dataDescriptionObject->loadXML($configDataDescription->fields);
  359.         }
  360.  
  361.         //Создаем объект описания данных взятых из БД
  362.         $DBDataDescription new DataDescription();
  363.         //Загружаем в него инфу о колонках
  364.         $DBDataDescription->load($this->loadDataDescription());
  365.         $this->setDataDescription($dataDescriptionObject->intersect($DBDataDescription));
  366.  
  367.         $dataObject new Data();
  368.         $dataObject->load($this->loadData());
  369.         $this->setData($dataObject);
  370.  
  371.         //Создаем сейвер
  372.         $this->saver new Saver();
  373.         //Устанавливаем его режим
  374.         $this->saver->setMode($mode);
  375.         $this->saver->setDataDescription($this->getDataDescription());
  376.         $this->saver->setData($this->getData());
  377.  
  378.         if($this->saver->validate(=== true{
  379.             $this->saver->setFilter($this->getFilter());
  380.             $this->saver->save();
  381.             $result $this->saver->getResult();
  382.  
  383.         }
  384.         else {
  385.             //выдвигается пустой exception который перехватывается в методе save
  386.             throw new FormException();
  387.         }
  388.  
  389.         return $result;
  390.     }
  391.  
  392.  
  393.     /**
  394.      * Переопределенный метод построения
  395.      * Перед построением - добавляется перевод
  396.      * После построения добавляется информация о закладках
  397.      *
  398.      * @return void 
  399.      * @access public
  400.      */
  401.  
  402.     public function build({
  403.         if (!$this->getTranslationTableName()) {
  404.             //Немультиязычные грид и форма
  405.             if (!empty($this->tabs)) {
  406.                 $this->tabs array_push_before($this->tabs$this->buildTab($this->getTitle())0);
  407.             }
  408.             else {
  409.                 $this->addTab($this->buildTab($this->getTitle()));
  410.             }
  411.         }
  412.         elseif ($this->getType(== self::COMPONENT_TYPE_LIST {
  413.             //Мультиязычный грид
  414.             $this->buildLangTabs();
  415.         }
  416.         else {
  417.             //Мультиязычная форма
  418.             $this->buildLangTabs();
  419.             $this->tabs array_push_before($this->tabs$this->buildTab($this->translate('TXT_PROPERTIES'))0);
  420.         }
  421.  
  422.         switch ($this->getAction()) {
  423.             case 'imageManager':
  424.                 return $this->imageManager->build();
  425.                 break;
  426.             case 'fileLibrary':
  427.                 return $this->fileLibrary->build();
  428.                 break;
  429.             default:
  430.                 // do nothing
  431.         }
  432.  
  433.         if ($this->getType(== self::COMPONENT_TYPE_LIST{
  434.             $this->addTranslation('MSG_CONFIRM_DELETE');
  435.         }
  436.  
  437.         $result parent::build();
  438.         return $result;
  439.     }
  440.     /**
  441.      * Для действия main не выводим данные
  442.      * Для действия save определяем другой формат данных
  443.      *
  444.      * @return mixed 
  445.      * @access protected
  446.      */
  447.  
  448.     protected function loadData({
  449.         if ($this->getAction(== self::DEFAULT_ACTION_NAME{
  450.             $result false;
  451.         }
  452.         elseif ($this->getAction(== 'save'{
  453.             if (!isset($_POST[$this->getTableName()])) {
  454.                 throw new SystemException('ERR_NO_DATA'SystemException::ERR_CRITICAL);
  455.             }
  456.  
  457.             $data $_POST[$this->getTableName()];
  458.             //Приводим данные к стандартному виду
  459.             $result array($data);
  460.             if ($this->getTranslationTableName()) {
  461.                 if (!isset($_POST[$this->getTranslationTableName()])) {
  462.                     throw new SystemException('ERR_NO_DATA'SystemException::ERR_CRITICAL);
  463.                 }
  464.                 $result array();
  465.                 $multidata $_POST[$this->getTranslationTableName()];
  466.                 foreach ($multidata as $langID => $langValues{
  467.                     $idx arrayPush($result$data);
  468.                     $result[$idx]['lang_id'$langID;
  469.                     foreach ($langValues as $fieldName => $fieldValue{
  470.                         $result[$idx][$fieldName$fieldValue;
  471.                     }
  472.                 }
  473.             }
  474.  
  475.         }
  476.         elseif ($this->getAction(=='getRawData'{
  477.             //Формат фильтра
  478.             //$_POST['filter'][$tableName][$fieldName] = значение фильтра
  479.             if (isset($_POST['filter'])) {
  480.                 $tableName = key($_POST['filter']);
  481.                 $fieldName = key($_POST['filter'][$tableName]);
  482.                 $value $_POST['filter'][$tableName][$fieldName];
  483.                 $this->setFilter($tableName.'.'.$fieldName.' LIKE \'%'.$value.'%\' ');
  484.             }
  485.  
  486.             $result parent::loadData();
  487.         }
  488.         else {
  489.             $result parent::loadData();
  490.         }
  491.  
  492.         return $result;
  493.     }
  494.  
  495.     /**
  496.      * Создает вкладки языков
  497.      *
  498.      * @return void 
  499.      * @access private
  500.      */
  501.  
  502.     private function buildLangTabs({
  503.         $lang Language::getInstance()->getLanguages();
  504.         foreach ($lang as $langID => $langInfo{
  505.             $tabProperties array(
  506.             'id' => $langID,
  507.             'abbr' => $langInfo['lang_abbr']
  508.             );
  509.             $this->addTab($this->buildTab($langInfo['lang_name']$tabProperties));
  510.         }
  511.     }
  512.  
  513.     /**
  514.      * Выводит компонент: менеджер изображений
  515.      *
  516.      * @return void 
  517.      * @access protected
  518.      */
  519.     protected function imageManager({
  520.         $this->imageManager  = $this->document->componentManager->createComponent('imagemanager''image''ImageManager'null);
  521.         //$this->imageManager->getAction();
  522.         $this->imageManager->run();
  523.     }
  524.  
  525.     /**
  526.      * Выводит компонент: библиотека изображений
  527.      *
  528.      * @return void 
  529.      * @access protected
  530.      */
  531.     protected function fileLibrary({
  532.         $this->request->setPathOffset($this->request->getPathOffset(1);
  533.         $this->fileLibrary = $this->document->componentManager->createComponent('filelibrary''share''FileLibrary'null);
  534.         //$this->fileLibrary->getAction();
  535.         $this->fileLibrary->run();
  536.     }
  537.  
  538.     /**
  539.      * Метод генерящий thumbnail и сохраняющий его в БД
  540.      *
  541.      * @param $sourceFileName string имя исходного файла
  542.      * @param $destFieldName string имя поля
  543.      * @param $width int ширина
  544.      * @param $height int высота
  545.      * @param $filter array фильтр
  546.      * @return имя файла - превьюхи
  547.      * @access protected
  548.      */
  549.  
  550.     protected function generateThumbnail($sourceFileName$destFieldName$width$height$filter$rewrite true{
  551.         $destFileName false;
  552.         if (!empty($sourceFileName)) {
  553.             $destFileName = dirname($sourceFileName).'/'.$destFieldName.'_'.basename($sourceFileName);
  554.             if (
  555.                 (
  556.                     file_exists($fullDestFileName = dirname($_SERVER['SCRIPT_FILENAME']).'/'.$destFileName)
  557.                     && $rewrite
  558.                 )
  559.                 || !file_exists($fullDestFileName)
  560.             {
  561.                 $image new Image();
  562.                 $image->loadFromFile($sourceFileName);
  563.                 $image->resize($width,$height);
  564.                 $image->saveToFile($destFileName);
  565.                 $image new FileObject();
  566.                 $image->createFromPath($destFileName$this->translate($destFieldName).': '.basename($sourceFileName));
  567.                 //Сохраняем в БД
  568.                 $this->dbh->modify(QAL::UPDATE$this->getTableName()array($destFieldName=>$destFileName)$filter);
  569.             }
  570.         }
  571.  
  572.         return $destFileName;
  573.     }
  574.  
  575.     /**
  576.      * Устанавливает имя колонки для пользовательской сортировки
  577.      *
  578.      * @return void 
  579.      * @access protected
  580.      */
  581.  
  582.      protected function setOrderColumn($columnName{
  583.         $this->orderColumn $columnName;
  584.      }
  585.  
  586.      /**
  587.       * Возвращает имя колонки для пользовательской сортировки
  588.       *
  589.       * @return string 
  590.       * @access protected
  591.       */
  592.  
  593.       protected function getOrderColumn({
  594.          return $this->orderColumn;
  595.       }
  596.  
  597.     /**
  598.      * Метод для изменения порядка следования  - вверх
  599.      *
  600.      * @return void 
  601.      * @access protected
  602.      */
  603.  
  604.     protected function up({
  605.         $this->response->write($this->changeOrder(Grid::DIR_UP));
  606.         $this->response->commit();
  607.     }
  608.  
  609.     /**
  610.      * Метод для изменения порядка следования  - вниз
  611.      *
  612.      * @return void 
  613.      * @access protected
  614.      */
  615.  
  616.     protected function down({
  617.         $this->response->write($this->changeOrder(Grid::DIR_DOWN));
  618.         $this->response->commit();
  619.     }
  620.  
  621.     /**
  622.      * Изменяет порядок следования
  623.      *
  624.      * @param string  - направление
  625.      * @return JSON String
  626.      * @access protected
  627.      */
  628.  
  629.     protected function changeOrder($direction{
  630.         try {
  631.  
  632.             if (!$this->getOrderColumn()) {
  633.                 //Если не задана колонка для пользовательской сортировки то на выход
  634.                 throw new SystemException('ERR_NO_ORDER_COLUMN'SystemException::ERR_DEVELOPER);
  635.             }
  636.  
  637.             $currentID $this->getActionParams();
  638.             list($currentID$currentID;
  639.  
  640.             //Определяем order_num текущей страницы
  641.             $currentOrderNum simplifyDBResult($this->dbh->selectRequest('select '.$this->getOrderColumn().' from '.$this->getTableName().' where '.$this->getPK().' = %s'$currentID)$this->getOrderColumn()true);
  642.             $orderDirection ($direction == Grid::DIR_DOWN)?QAL::ASC:QAL::DESC;
  643.  
  644.             //Определяем идентификатор записи которая находится рядом с текущей
  645.             $request 'SELECT '.$this->getPK().' as neighborID, '.$this->getOrderColumn().' as neighborOrderNum FROM '.$this->getTableName().' WHERE '.$this->getOrderColumn().' '.$direction.' '.$currentOrderNum.' order by '.$this->getOrderColumn().' '.$orderDirection.' Limit 1';
  646.  
  647.             $data convertDBResult($this->dbh->selectRequest($request)'neighborID');
  648.             if ($data{
  649.                     extract(current($data));
  650.                     $this->dbh->beginTransaction();
  651.                     $this->dbh->modify(QAL::UPDATE$this->getTableName()array($this->getOrderColumn()=>$neighborOrderNum)array($this->getPK()=>$currentID));
  652.                     $this->dbh->modify(QAL::UPDATE$this->getTableName()array($this->getOrderColumn()=>$currentOrderNum)array($this->getPK()=>$neighborID));
  653.                     $this->dbh->commit();
  654.             }
  655.  
  656.             $JSONResponse array(
  657.             'result' => true,
  658.             'dir' => $direction
  659.             );
  660.         }
  661.         catch (SystemException $e){
  662.             $JSONResponse $this->generateError($e->getCode()$e->getMessage());
  663.  
  664.         }
  665.         return json_encode($JSONResponse);
  666.     }
  667.  
  668. }

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