Далеко не секрет что битрикс плохо работает с ajax'ом. И вот настала необходимость написать интерфейс для ExtJS.Версия сыровата но в процессе
Задача:
Продолжение следует....
Задача:
- Написать удобный инструмент для работы с ExtJS
- Он должен работать в двух режимах(аякс хтмл)
use Bitrix\Main, Inter\Olsc, Bitrix\Main\IO; /** * Class Component */ abstract class Component extends \CBitrixComponent { /**@var \CMain*/ protected $globalApplication; /**@var \Inter\Olsc\Component\Events */ protected $eventObj = null; protected $isAjaxResponse = false,//Флаг "ответ аяксом" $postJson = array(),//Массив из POST json'a $entryPointPrefix = 'action_';//префикс методов эвентов public $data = array(), $Response = array(); public function __construct($component = null) { parent::__construct($component); } /** * Подготовка компонента к работе * * @param $arParams * * @throws \Bitrix\Main\ArgumentTypeException if $APPLICATION isn't instanceof \CMain * @return array */ final public function onPrepareComponentParams(&$arParams) { $server = Main\Application::getInstance()->getContext()->getServer(); $ajax = $server->get('HTTP_X_REQUESTED_WITH'); $content_type = $server->get('CONTENT_TYPE'); if($ajax && strtolower($ajax) === 'xmlhttprequest' && strpos($content_type, 'multipart/form-data') === false)//На основе хедеров выясняем аякс ли это { $this->isAjaxResponse = true; define("PUBLIC_AJAX_MODE", true); } try { $arParams['SEF_URL_TEMPLATES']['classOnly'] = '#CLASS#/'; global $APPLICATION; if(!($APPLICATION instanceof \CMain)) { throw new Main\ArgumentTypeException('APPLICATION', '\CMain object'); } $this->globalApplication = $APPLICATION; if($this->isAjaxResponse) { $this->postJson = $this->getPostJsonFromInput();//Получение данных пришедших json'ом $this->globalApplication->RestartBuffer(); } $this->setVariablesSef($arParams);//Используем ЧПУ битрикса бля определения класса и метода //Подключение классов формы if(!empty($this->data['arVariables']['CLASS'])) { $this->eventObj = $this->initClassForm($this->data['arVariables']['CLASS']); //Вызов события компонента $this->eventObj->onPrepareComponentParams($arParams); } } catch(\Exception $e) { $this->catchExeption($e); } //Так положено return $arParams; } /** * Главный исполняймый метод */ final public function executeComponent() { try { if($this->arParams['NO_CLASS_INIT'] !== 'Y' && !$this->inDeveloping()) { return false; } $this->executeComponentEx(); //don't remove if($this->isAjaxResponse)//Если аякс то выплёвываем json { $this->ajaxResponseSend(); require($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/main/include/epilog_after.php"); exit; } $this->includeComponentTemplate(); }catch (\Exception $e) { $this->catchExeption($e); } unset($this->data['arVariables']); return $this->data; } abstract public function executeComponentEx(); private function catchExeption(\Exception $e) { if($this->isAjaxResponse) { $this->setErrMesExption($e); $this->Response['success'] = false; $this->ajaxResponseSend(); exit; } $errorMsg = '<span style="color:red">System failure!'; if($e->getCode()>0) { $errorMsg .= ' Code:'.$e->getCode(); } $errorMsg .= '</span>'; echo $errorMsg; throw $e; } final private function inDeveloping() { if(!is_object($this->eventObj) || !method_exists($this->eventObj, $this->entryPointPrefix.$this->data['arVariables']['METHOD'])) { in_developing();//Заглушка return false; } return true; } private function setErrMesExption(\Exception $e) { if($ex = $e->getPrevious()) { $this->setErrMesExption($ex); } $arConfig = Main\Config\Configuration::getValue('exception_handling'); if($e instanceof Olsc\Exception\MessagesForUser || $arConfig['debug']) { $this->Response['error']['message'][] = $e->getMessage().' , '.'Code: '.$e->getCode(); } else { $this->Response['error']['message'][] = 'Code: '.$e->getCode(); } } final private function setVariablesSef(&$arParams) { if (!($arParams['SEF_MODE'] === 'Y')) { $this->data['arVariables'] = $arParams['arVariables']; } else { //тут магия копипасты с форума битрикса. Что тут происходит - никому не известно.))) $arDefaultUrlTemplates404 = array(); $arDefaultVariableAliases404 = array(); $arVariables = array('METHOD' => 'default'); if (!empty($arParams['DEFAULT_ROUTE'])) { $arVariables['CLASS'] = $arParams['DEFAULT_ROUTE']; } $arComponentVariables = array('CLASS', "METHOD"); $arUrlTemplates = \CComponentEngine::MakeComponentUrlTemplates( $arDefaultUrlTemplates404, $arParams["SEF_URL_TEMPLATES"] ); $arVariableAliases = \CComponentEngine::MakeComponentVariableAliases( $arDefaultVariableAliases404, $arParams["VARIABLE_ALIASES"] ); $componentPage = \CComponentEngine::ParseComponentPath( $arParams['SEF_FOLDER'], $arUrlTemplates, $arVariables ); \CComponentEngine::InitComponentVariables( $componentPage, $arComponentVariables, $arVariableAliases, $arVariables ); $this->data['arVariables'] = $arVariables; } } final private function getPostJsonFromInput() { global $HTTP_RAW_POST_DATA; return json_decode($HTTP_RAW_POST_DATA, true); } /** * Метод собирает и отправляет Response */ final private function ajaxResponseSend() { if(!is_bool($this->Response['success'])) { $this->Response['success'] = false; } header('Content-Type: text/x-json; charset=' . LANG_CHARSET, true); //echo \CUtil::PhpToJSObject($this->Response); $data = $this->ajaxObjectToString($this->Response); // Преобразуем DateTime в string echo json_encode($data); } /** * Преобразование спец. данных Битрикс в строку методом toString * @data array $data Массив данных для преобразования * * @param $data * * @return array Массив данных с преобразованными данными */ final private function ajaxObjectToString($data) { foreach ($data as $k => $v) { if (is_array($v)) { $data[$k] = $this->ajaxObjectToString($v); } else if (is_object($v) && method_exists($v, 'toString')) { $data[$k] = $v->toString(); } } return $data; } /** * Инициализация вспомогательного объекта формы * * @param string $className массив классов из папки /components/*/component/class.route/ * * @throws \Bitrix\Main\NotImplementedException * @return Olsc\Component\Events */ final private function initClassForm($className) { $classRoutePath = Main\IO\Path::convertSiteRelativeToAbsolute( array( $this->getPath(), 'class.route' ) ); $subClass = '*\*\Component\Events'; $classPath = $classRoutePath.IO\Path::DIRECTORY_SEPARATOR.strtolower($className).'.php'; $classPath = IO\Path::normalize($classPath); $className = get_called_class().'\\'.$className; $this->includeFormClass($classPath); if (!is_subclass_of($className, $subClass)) { throw new Main\NotImplementedException($className.' not subclass of '.$subClass); } return new $className($this); } /** * Метод подключает файл * * @param $file * * @return mixed * @return mixed * @throws \Bitrix\Main\IO\FileNotFoundException */ final private function includeFormClass($file) { if(!Main\IO\File::isFileExists($file)) { throw new Main\IO\FileNotFoundException($file); } return require_once($file); } /** * Вызов событий */ final protected function evalEvent($evalName, &$param = null) { $method = $this->entryPointPrefix.$evalName; if(method_exists($this->eventObj, $method)) { $this->eventObj->$method($param); } } final public function getGlobalApplication() { return $this->globalApplication; } final public function getPostJson() { return $this->postJson; } final public function isAjax() { return $this->isAjaxResponse; } final public function execEventMethod($class, $method) { $obj = $this->initClassForm($class); $method = $this->entryPointPrefix.$method; if(method_exists($obj, $method)) { $arParams = $this->arParams; $obj->onPrepareComponentParams($arParams); return $obj->$method(); //return call_user_func(array($obj, $method)); } return false; } } |