From: Steffen Kamper Date: Mon, 25 Jan 2010 22:58:29 +0000 (+0000) Subject: Added feature #13313: ExtDirect API (thanks to Stefan Galinski and the T3UXW09 team) X-Git-Tag: TYPO3_4-4-0alpha1~101 X-Git-Url: http://git.typo3.org/Packages/TYPO3.CMS.git/commitdiff_plain/1f233047cc40352c43968fa832ab839385e1947c Added feature #13313: ExtDirect API (thanks to Stefan Galinski and the T3UXW09 team) git-svn-id: https://svn.typo3.org/TYPO3v4/Core/trunk@6818 709f56b5-9817-0410-a4d7-c38de5d9e867 --- diff --git a/ChangeLog b/ChangeLog index 6ddadb7a7f01..24d830afa6f4 100755 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2010-01-25 Steffen Kamper + + * Added feature #13313: ExtDirect API (thanks to Stefan Galinski and the T3UXW09 team) + 2010-01-24 Steffen Kamper * Fixed bug #13090: 4.4.0 trunk: version warning with CSS styled content diff --git a/t3lib/class.t3lib_pagerenderer.php b/t3lib/class.t3lib_pagerenderer.php index 034e8a4f55df..6d8d7d49e910 100644 --- a/t3lib/class.t3lib_pagerenderer.php +++ b/t3lib/class.t3lib_pagerenderer.php @@ -687,12 +687,17 @@ class t3lib_PageRenderer implements t3lib_Singleton { /** * Adds Ext.onready code, which will be wrapped in Ext.onReady(function() {...}); * - * @param string $block + * @param string $block javascript code + * @param boolean $forceOnTop position of the javascript code (TRUE for putting it on top, default is FALSE = bottom) * @return void */ - public function addExtOnReadyCode($block) { + public function addExtOnReadyCode($block, $forceOnTop = FALSE) { if (!in_array($block, $this->extOnReadyCode)) { - $this->extOnReadyCode[] = $block; + if ($forceOnTop) { + array_unshift($this->extOnReadyCode, $block); + } else { + $this->extOnReadyCode[] = $block; + } } } diff --git a/t3lib/config_default.php b/t3lib/config_default.php index 3cc6fca18b18..1376a906e085 100644 --- a/t3lib/config_default.php +++ b/t3lib/config_default.php @@ -279,8 +279,11 @@ $TYPO3_CONF_VARS = array( 'BackendLogin::isTimedOut' => 'typo3/classes/class.ajaxlogin.php:AjaxLogin->isTimedOut', 'BackendLogin::getChallenge' => 'typo3/classes/class.ajaxlogin.php:AjaxLogin->getChallenge', 'WorkspaceMenu::toggleWorkspacePreview' => 'typo3/classes/class.workspaceselector.php:WorkspaceSelector->toggleWorkspacePreview', - 'WorkspaceMenu::setWorkspace' => 'typo3/classes/class.workspaceselector.php:WorkspaceSelector->setWorkspace' + 'WorkspaceMenu::setWorkspace' => 'typo3/classes/class.workspaceselector.php:WorkspaceSelector->setWorkspace', + 'ExtDirect::getAPI' => 't3lib/extjs/class.t3lib_extjs_extdirectapi.php:t3lib_ExtJs_ExtDirectAPI->getAPI', + 'ExtDirect::route' => 't3lib/extjs/class.t3lib_extjs_extdirectrouter.php:t3lib_ExtJs_ExtDirectRouter->route', ), + 'ExtDirect' => array(), // array of key value pairs (provider -> location:className) that holds the classes for the ExtDirect functionality 'XCLASS' => array(), // See 'Inside TYPO3' document for more information. ), 'FE' => array( // Configuration for the TypoScript frontend (FE). Nothing here relates to the administration backend! diff --git a/t3lib/extjs/class.t3lib_extjs_extdirectapi.php b/t3lib/extjs/class.t3lib_extjs_extdirectapi.php new file mode 100644 index 000000000000..30232c8c49bb --- /dev/null +++ b/t3lib/extjs/class.t3lib_extjs_extdirectapi.php @@ -0,0 +1,105 @@ + +* All rights reserved +* +* This script is part of the TYPO3 project. The TYPO3 project is +* free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* The GNU General Public License can be found at +* http://www.gnu.org/copyleft/gpl.html. +* A copy is found in the textfile GPL.txt and important notices to the license +* from the author is found in LICENSE.txt distributed with these scripts. +* +* +* This script is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* This copyright notice MUST APPEAR in all copies of the script! +***************************************************************/ + +/** + * Ext Direct API Generator + * + * @author Sebastian Kurfuerst + * @author Stefan Galinski + * @package TYPO3 + */ +class t3lib_ExtJs_ExtDirectAPI { + /** + * Parses the ExtDirect configuration array "$GLOBALS['TYPO3_CONF_VARS']['BE']['ExtDirect']" + * and feeds the given typo3ajax instance with the resulting informations. The get parameter + * "namespace" will be used to filter the configuration. + * + * This method makes usage of the reflection mechanism to fetch the methods inside the + * defined classes together with their amount of parameters. This informations are building + * the API and are required by ExtDirect. + * + * @param array $ajaxParams ajax parameters + * @param TYPO3AJAX $ajaxObj typo3ajax instance + * @return void + */ + public function getAPI($ajaxParams, TYPO3AJAX $ajaxObj) { + $filterNamespace = t3lib_div::_GET('namespace'); + + $javascriptNamespaces = array(); + if (is_array($GLOBALS['TYPO3_CONF_VARS']['BE']['ExtDirect'])) { + foreach ($GLOBALS['TYPO3_CONF_VARS']['BE']['ExtDirect'] as $javascriptName => $className) { + $splittedJavascriptName = explode('.', $javascriptName); + $javascriptObjectName = array_pop($splittedJavascriptName); + $javascriptNamespace = implode('.', $splittedJavascriptName); + + // only items inside the wanted namespace + if (strpos($javascriptNamespace, $filterNamespace) !== 0) { + continue; + } + + if (!isset($javascriptNamespaces[$javascriptNamespace])) { + $javascriptNamespaces[$javascriptNamespace] = array( + 'url' => 'ajax.php?ajaxID=ExtDirect::route&namespace=' . rawurlencode($javascriptNamespace), + 'type' => 'remoting', + 'actions' => array(), + 'namespace' => $javascriptNamespace + ); + } + + $serverObject = t3lib_div::getUserObj($className, FALSE); + $javascriptNamespaces[$javascriptNamespace]['actions'][$javascriptObjectName] = array(); + foreach (get_class_methods($serverObject) as $methodName) { + $reflectionMethod = new ReflectionMethod($serverObject, $methodName); + $numberOfParameters = $reflectionMethod->getNumberOfParameters(); + + $javascriptNamespaces[$javascriptNamespace]['actions'][$javascriptObjectName][] = array( + 'name' => $methodName, + 'len' => $numberOfParameters + ); + } + } + } + + if (count($javascriptNamespaces)) { + $setup = ' + if (typeof Ext.app.ExtDirectAPI != "object") { + Ext.app.ExtDirectAPI = {}; + } + '; + + $ajaxObj->setContent($javascriptNamespaces); + $ajaxObj->setContentFormat('javascript'); + $ajaxObj->setJavascriptCallbackWrap($setup . 'Ext.app.ExtDirectAPI = Object.extend(Ext.app.ExtDirectAPI, |);'); + } + } +} + +if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_extjs_extdirectapi.php']) { + include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_extjs_extdirectapi.php']); +} + +?> diff --git a/t3lib/extjs/class.t3lib_extjs_extdirectrouter.php b/t3lib/extjs/class.t3lib_extjs_extdirectrouter.php new file mode 100644 index 000000000000..cb25f76ea776 --- /dev/null +++ b/t3lib/extjs/class.t3lib_extjs_extdirectrouter.php @@ -0,0 +1,131 @@ + +* All rights reserved +* +* This script is part of the TYPO3 project. The TYPO3 project is +* free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* The GNU General Public License can be found at +* http://www.gnu.org/copyleft/gpl.html. +* A copy is found in the textfile GPL.txt and important notices to the license +* from the author is found in LICENSE.txt distributed with these scripts. +* +* +* This script is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* This copyright notice MUST APPEAR in all copies of the script! +***************************************************************/ + +/** + * Ext Direct Router + * + * @author Sebastian Kurfuerst + * @author Stefan Galinski + * @package TYPO3 + */ +class t3lib_ExtJs_ExtDirectRouter { + /** + * Dispatches the incoming calls to methods about the ExtDirect API. + * + * @param aray $ajaxParams ajax parameters + * @param TYPO3AJAX $ajaxObj typo3ajax instance + * @return void + */ + public function route($ajaxParams, TYPO3AJAX $ajaxObj) { + try { + $isForm = false; + $isUpload = false; + $rawPostData = file_get_contents('php://input'); + $namespace = t3lib_div::_GET('namespace'); + + if (!empty($rawPostData)) { + $ajaxObj->setContentFormat('jsonbody'); + $request = json_decode($rawPostData); + } else { + throw new t3lib_error_Exception('ExtDirect: Missing Parameters!'); + } + + $response = null; + if (is_array($request)) { + $response = array(); + foreach ($request as $singleRequest) { + $response[] = $this->processRpc($singleRequest, $namespace); + } + } else { + $response = $this->processRpc($request, $namespace); + } + + } catch (t3lib_error_Exception $exception) { + $response = array( + 'type' => 'exception', + 'message' => $exception->getMessage(), + 'where' => $exception->getTraceAsString() + ); + } + + $ajaxObj->setContent($response); + } + + + /** + * Processes an incoming extDirect call by executing the defined method. The configuration + * array "$GLOBALS['TYPO3_CONF_VARS']['BE']['ExtDirect']" is taken to find the class/method + * information. + * + * @param object $singleRequest request object from extJS + * @param string $namespace namespace like TYPO3.Backend + * @return mixed return value of the called method + */ + protected function processRpc($singleRequest, $namespace) { + try { + $endpointName = $namespace . '.' . $singleRequest->action; + + // theoretically this can never happen, because of an javascript error on + // the client side due the missing namespace/endpoint + if (!isset($GLOBALS['TYPO3_CONF_VARS']['BE']['ExtDirect'][$endpointName])) { + throw new t3lib_error_Exception('ExtDirect: Call to undefined endpoint: ' . $endpointName); + } + + $response = array( + 'type' => 'rpc', + 'tid' => $singleRequest->tid, + 'action' => $singleRequest->action, + 'method' => $singleRequest->method + ); + + $endpointObject = t3lib_div::getUserObj( + $GLOBALS['TYPO3_CONF_VARS']['BE']['ExtDirect'][$endpointName], + FALSE + ); + + $response['result'] = call_user_func_array( + array($endpointObject, $singleRequest->method), + is_array($singleRequest->data) ? $singleRequest->data : array() + ); + + } catch (t3lib_error_Exception $exception) { + $response = array( + 'type' => 'exception', + 'message' => $exception->getMessage(), + 'where' => $exception->getTraceAsString() + ); + } + + return $response; + } +} + +if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_extjs_extdirectrouter.php']) { + include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_extjs_extdirectrouter.php']); +} + +?> diff --git a/typo3/backend.php b/typo3/backend.php index 3f846b222e9e..56e5f4f6044e 100644 --- a/typo3/backend.php +++ b/typo3/backend.php @@ -102,11 +102,13 @@ class TYPO3backend { 'js/modulemenu.js', 'js/iecompatibility.js', 'js/flashupload.js', - '../t3lib/jsfunc.evalfield.js' + '../t3lib/jsfunc.evalfield.js', + 'ajax.php?ajaxID=ExtDirect::getAPI&namespace=TYPO3.Backend' ); + $this->jsFilesAfterInline = array( 'js/backend.js', - 'js/loginrefresh.js', + 'js/loginrefresh.js', ); // add default BE css $this->css = ''; @@ -210,6 +212,16 @@ class TYPO3backend { $pageRenderer->loadScriptaculous('builder,effects,controls,dragdrop'); $pageRenderer->loadExtJS(); + // register the extDirect API providers + // Note: we need to iterate thru the object, because the addProvider method + // does this only with multiple arguments + $pageRenderer->addExtOnReadyCode( + 'for (var api in Ext.app.ExtDirectAPI) { + Ext.Direct.addProvider(Ext.app.ExtDirectAPI[api]); + }', + TRUE + ); + // remove duplicate entries $this->jsFiles = array_unique($this->jsFiles); diff --git a/typo3/classes/class.typo3ajax.php b/typo3/classes/class.typo3ajax.php index d94eaae42c3b..955d50ecc8de 100644 --- a/typo3/classes/class.typo3ajax.php +++ b/typo3/classes/class.typo3ajax.php @@ -41,6 +41,13 @@ class TYPO3AJAX { protected $contentFormat = 'plain'; protected $charset = 'utf-8'; protected $requestCharset = 'utf-8'; + protected $javascriptCallbackWrap = ' + + '; /** * sets the charset and the ID for the AJAX call @@ -138,7 +145,7 @@ class TYPO3AJAX { /** * sets the content format for the ajax call * - * @param string can be one of 'plain' (default), 'xml', 'json', 'jsonbody' or 'jsonhead' + * @param string can be one of 'plain' (default), 'xml', 'json', 'javascript', 'jsonbody' or 'jsonhead' * @return void */ public function setContentFormat($format) { @@ -147,6 +154,17 @@ class TYPO3AJAX { } } + /** + * Specifies the wrap to be used if contentFormat is "javascript". + * The wrap used by default stores the results in a variable "response" and + * adds '; + $content = str_replace('|', json_encode($this->content), $this->javascriptCallbackWrap); header('Content-type: text/html; charset=' . $this->requestCharset); echo $content;