Commit 34ef2fa3 authored by Bastian Waidelich's avatar Bastian Waidelich
Browse files

[+FEATURE] Extbase (Configuration): Configuration is available in Backend...

[+FEATURE] Extbase (Configuration): Configuration is available in Backend modules now! Depending on TYPO3_MODE the dispatcher now creates an instance of Frontend- or BackendConfigurationManager. TypoScriptSource has been adjusted to support Backend mode. This resolves #4418
[~TASK] Extbase (Configuration): Moved Configuration Source Interface from Classes/Configuration to Classes/Configuration/Source
[+TASK] Extbase (MVC): AbstractController::redirectToURI() prepends 'typo3/' to the absolute URI when in Backend mode
[+FEATURE] Extbase (MVC): added a call to t3lib_div::getFileAbsFileName() for templateRootPath to allow notations like "EXT:extension/path" and to validate the template path
[+FEATURE] Extbase (MVC): settings are now assigned to the view in AbstractController::resolveView. Now settings are available in your template as {settings}!
[+FEATURE] Extbase (MVC): UriBuilder can now create absolute URIs in Backend mode too
[+BUGFIX] Extbase (Persistence): added t3lib_BEfunc::deleteClause() call to enableFieldsStatement in Backend mode. Otherwise deleted records would be selected in BE
parent 2622b2bf
......@@ -23,15 +23,13 @@
***************************************************************/
/**
* A general purpose configuration manager
*
* Should NOT be singleton, as a new configuration manager is needed per plugin.
* Abstract base class for a general purpose configuration manager
*
* @package Extbase
* @subpackage Configuration
* @version $ID:$
*/
class Tx_Extbase_Configuration_Manager {
abstract class Tx_Extbase_Configuration_AbstractConfigurationManager {
/**
* Default backend storage PID
......@@ -84,25 +82,6 @@ class Tx_Extbase_Configuration_Manager {
return $this->settings[$extensionName];
}
/**
* Loads the settings defined in the specified extensions and merges them with
* those potentially existing in the global configuration folders.
*
* The result is stored in the configuration manager's settings registry
* and can be retrieved with the getSettings() method.
*
* @param string $extensionName
* @return void
* @see getSettings()
*/
protected function loadSettings($extensionName) {
$settings = array();
foreach ($this->configurationSources as $configurationSource) {
$settings = t3lib_div::array_merge_recursive_overrule($settings, $configurationSource->load($extensionName));
}
$this->settings[$extensionName] = $settings;
}
/**
* Loads the Extbase Framework configuration.
*
......@@ -110,21 +89,22 @@ class Tx_Extbase_Configuration_Manager {
* Framework configuration is, in contrast to normal settings, needed for the Extbase framework to operate correctly.
*
* @param array $pluginConfiguration The current incoming extbase configuration
* @param tslib_cObj $cObj The current Content Object
* @return array the Extbase framework configuration
*/
public function getFrameworkConfiguration($pluginConfiguration, $cObj) {
public function getFrameworkConfiguration($pluginConfiguration) {
$frameworkConfiguration = array();
$frameworkConfiguration['persistence']['storagePid'] = $this->getDefaultStoragePageId($cObj);
$frameworkConfiguration['contentObjectData'] = $cObj->data;
$frameworkConfiguration['persistence']['storagePid'] = self::DEFAULT_BACKEND_STORAGE_PID;
// TODO Support BE modules by parsing the file "manually" and all files EXT:myext/Configuration/Objects/setup.txt
$extbaseConfiguration = $GLOBALS['TSFE']->tmpl->setup['config.']['tx_extbase.'];
$setup = $this->loadTypoScriptSetup();
$extbaseConfiguration = $setup['config.']['tx_extbase.'];
if (is_array($extbaseConfiguration)) {
$extbaseConfiguration = Tx_Extbase_Utility_TypoScript::convertTypoScriptArrayToPlainArray($extbaseConfiguration);
$frameworkConfiguration = t3lib_div::array_merge_recursive_overrule($frameworkConfiguration, $extbaseConfiguration);
}
if (isset($pluginConfiguration['settings'])) {
$pluginConfiguration = $this->resolveTyposcriptReference($pluginConfiguration, 'settings');
}
if (isset($pluginConfiguration['persistence'])) {
$pluginConfiguration = $this->resolveTyposcriptReference($pluginConfiguration, 'persistence');
}
......@@ -132,9 +112,17 @@ class Tx_Extbase_Configuration_Manager {
$pluginConfiguration = $this->resolveTyposcriptReference($pluginConfiguration, 'view');
}
$frameworkConfiguration = t3lib_div::array_merge_recursive_overrule($frameworkConfiguration, Tx_Extbase_Utility_TypoScript::convertTypoScriptArrayToPlainArray($pluginConfiguration));
return $frameworkConfiguration;
}
/**
* Returns TypoScript Setup array from current Environment.
*
* @return array the TypoScript setup
*/
abstract public function loadTypoScriptSetup();
/**
* Resolves the TypoScript reference for $pluginConfiguration[$setting].
* In case the setting is a string and starts with "<", we know that this is a TypoScript reference which
......@@ -147,7 +135,8 @@ class Tx_Extbase_Configuration_Manager {
protected function resolveTyposcriptReference($pluginConfiguration, $setting) {
if (is_string($pluginConfiguration[$setting]) && substr($pluginConfiguration[$setting], 0, 1) === '<') {
$key = trim(substr($pluginConfiguration[$setting], 1));
list(, $newValue) = $this->typoScriptParser->getVal($key, $GLOBALS['TSFE']->tmpl->setup);
$setup = $this->loadTypoScriptSetup();
list(, $newValue) = $this->typoScriptParser->getVal($key, $setup);
unset($pluginConfiguration[$setting]);
$pluginConfiguration[$setting . '.'] = $newValue;
......@@ -156,57 +145,24 @@ class Tx_Extbase_Configuration_Manager {
}
/**
* Extracts the default storage PID from $this->cObj->data['pages'].
* If this one is empty, tries to use $this->cObj->data['storage_pid'].
* If this one is empty, tries to use $this->cObj->parentRecord->data['storage_pid'].
* If all three are empty, uses getStorageSiterootPids() in FE, and 0 in BE.
* Loads the settings defined in the specified extensions and merges them with
* those potentially existing in the global configuration folders.
*
* @param tslib_cObj $cObj The current Content Object
* @return string a comma separated list of integers to be used to fetch records from.
* The result is stored in the configuration manager's settings registry
* and can be retrieved with the getSettings() method.
*
* @param string $extensionName
* @return void
* @see getSettings()
*/
protected function getDefaultStoragePageId($cObj) {
if (is_string($cObj->data['pages']) && strlen($cObj->data['pages']) > 0) {
return $cObj->data['pages'];
}
if ($cObj->data['storage_pid'] > 0) {
return $cObj->data['storage_pid'];
}
if ($cObj->parentRecord->data['storage_pid'] > 0) {
return $cObj->parentRecord->data['storage_pid'];
}
if (TYPO3_MODE === 'FE') {
$storageSiterootPids = $GLOBALS['TSFE']->getStorageSiterootPids();
if (isset($storageSiterootPids['_STORAGE_PID'])) {
return $storageSiterootPids['_STORAGE_PID'];
}
protected function loadSettings($extensionName) {
$settings = array();
foreach ($this->configurationSources as $configurationSource) {
$settings = t3lib_div::array_merge_recursive_overrule($settings, $configurationSource->load($extensionName));
}
return self::DEFAULT_BACKEND_STORAGE_PID;
$this->settings[$extensionName] = $settings;
}
// /**
// * Scans all configuration directories in the extension directories.
// *
// * @return void
// */
// protected function scanAvailableTyposcriptConfigurations() {
// foreach (new DirectoryIterator(t3lib_extMgm::) as $parentFileInfo) {
// $parentFilename = $parentFileInfo->getFilename();
// if ($parentFilename[0] === '.' || !$parentFileInfo->isDir()) continue;
//
// foreach (new DirectoryIterator($parentFileInfo->getPathname()) as $childFileInfo) {
// $childFilename = $childFileInfo->getFilename();
// if ($childFilename[0] !== '.' && $childFilename !== 'FLOW3') {
// $packagePath = \F3\FLOW3\Utility\Files::getUnixStylePath($childFileInfo->getPathName()) . '/';
// $this->packages[$childFilename] = $this->objectFactory->create('F3\FLOW3\Package\Package', $childFilename, $packagePath);
// }
// }
// }
// foreach (array_keys($this->packages) as $upperCamelCasedPackageKey) {
// $this->packageKeys[strtolower($upperCamelCasedPackageKey)] = $upperCamelCasedPackageKey;
// }
// }
}
?>
\ No newline at end of file
?>
<?php
/***************************************************************
* Copyright notice
*
* (c) 2009 Jochen Rau <jochen.rau@typoplanet.de>
* 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.
*
* 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!
***************************************************************/
/**
* A general purpose configuration manager used in backend mode.
*
* @package Extbase
* @subpackage Configuration
* @version $ID:$
*/
class Tx_Extbase_Configuration_BackendConfigurationManager extends Tx_Extbase_Configuration_AbstractConfigurationManager implements t3lib_Singleton {
/**
* @var array
*/
protected $typoScriptSetupCache = NULL;
/**
* Returns TypoScript Setup array from current Environment.
*
* @return array the TypoScript setup
*/
public function loadTypoScriptSetup() {
if ($this->typoScriptSetupCache === NULL) {
$template = t3lib_div::makeInstance('t3lib_TStemplate');
// do not log time-performance information
$template->tt_track = 0;
$template->init();
// Get the root line
$sysPage = t3lib_div::makeInstance('t3lib_pageSelect');
// get the rootline for the current page
$rootline = $sysPage->getRootLine($this->getCurrentPageId());
// This generates the constants/config + hierarchy info for the template.
$template->runThroughTemplates($rootline, 0);
$template->generateConfig();
$this->typoScriptSetupCache = $template->setup;
}
return $this->typoScriptSetupCache;
}
/**
* Returns the page uid of the current page.
* If no page is selected, we'll return the uid of the first root page.
*
* @return integer current page id. If no page is selected current root page id is returned
*/
protected function getCurrentPageId() {
$pageId = (integer)t3lib_div::_GP('id');
if ($pageId > 0) {
return $pageId;
}
// get root template
$rootTemplates = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows('pid', 'sys_template', 'deleted=0 AND hidden=0 AND root=1', '', '', '1');
if (count($rootTemplates) > 0) {
return $rootTemplates[0]['pid'];
}
// get current site root
$rootPages = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows('uid', 'pages', 'deleted=0 AND hidden=0 AND is_siteroot=1', '', '', '1');
if (count($rootPages) > 0) {
return $rootPages[0]['uid'];
}
// fallback
return self::DEFAULT_BACKEND_STORAGE_PID;
}
}
?>
<?php
/***************************************************************
* Copyright notice
*
* (c) 2009 Jochen Rau <jochen.rau@typoplanet.de>
* 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.
*
* 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!
***************************************************************/
/**
* A general purpose configuration manager used in frontend mode.
*
* Should NOT be singleton, as a new configuration manager is needed per plugin.
*
* @package Extbase
* @subpackage Configuration
* @version $ID:$
*/
class Tx_Extbase_Configuration_FrontendConfigurationManager extends Tx_Extbase_Configuration_AbstractConfigurationManager {
/**
* @var tslib_cObj
*/
protected $contentObject;
/**
* @param tslib_cObj $contentObject
* @return void
*/
public function setContentObject(tslib_cObj $contentObject) {
$this->contentObject = $contentObject;
}
/**
* Returns TypoScript Setup array from current Environment.
*
* @return array the TypoScript setup
*/
public function loadTypoScriptSetup() {
return $GLOBALS['TSFE']->tmpl->setup;
}
}
?>
......@@ -32,7 +32,7 @@
* @subpackage Configuration\Source
* @version $ID:$
*/
class Tx_Extbase_Configuration_Source_FlexFormSource implements Tx_Extbase_Configuration_SourceInterface {
class Tx_Extbase_Configuration_Source_FlexFormSource implements Tx_Extbase_Configuration_Source_SourceInterface {
/**
* XML FlexForm content
......
......@@ -32,7 +32,7 @@
* @subpackage Configuration
* @version $ID:$
*/
interface Tx_Extbase_Configuration_SourceInterface {
interface Tx_Extbase_Configuration_Source_SourceInterface {
/**
* Loads the specified configuration file and returns its content in a
......@@ -43,4 +43,4 @@ interface Tx_Extbase_Configuration_SourceInterface {
*/
public function load($extensionName);
}
?>
\ No newline at end of file
?>
......@@ -32,7 +32,7 @@
* @subpackage Configuration\Source
* @version $ID:$
*/
class Tx_Extbase_Configuration_Source_TypoScriptSource implements Tx_Extbase_Configuration_SourceInterface {
class Tx_Extbase_Configuration_Source_TypoScriptSource implements Tx_Extbase_Configuration_Source_SourceInterface {
/**
* Loads the specified TypoScript configuration file and returns its content in a
......@@ -42,9 +42,12 @@ class Tx_Extbase_Configuration_Source_TypoScriptSource implements Tx_Extbase_Con
* @param string $extensionName The extension name
* @return array The settings as array without trailing dots
*/
public function load($extensionName) {
// TODO Needs a FE (does actually not work with BE or CLI)
$settings = $GLOBALS['TSFE']->tmpl->setup['plugin.']['tx_' . strtolower($extensionName) . '.']['settings.'];
public function load($extensionName) {
if (TYPO3_MODE === 'FE') {
$settings = $this->loadFrontendSettings($extensionName);
} else {
$settings = $this->loadBackendSettings($extensionName);
}
if (is_array($settings)) {
$settings = Tx_Extbase_Utility_TypoScript::convertTypoScriptArrayToPlainArray($settings);
} else {
......@@ -53,5 +56,27 @@ class Tx_Extbase_Configuration_Source_TypoScriptSource implements Tx_Extbase_Con
return $settings;
}
/**
* Loads the specified TypoScript configuration.
*
* @param string $extensionName The extension name
* @return array The settings as array without trailing dots
*/
protected function loadFrontendSettings($extensionName) {
return $GLOBALS['TSFE']->tmpl->setup['plugin.']['tx_' . strtolower($extensionName) . '.']['settings.'];
}
/**
* Loads the specified TypoScript configuration.
*
* @param string $extensionName The extension name
* @return array The settings as array without trailing dots
*/
protected function loadBackendSettings($extensionName) {
$configurationManager = t3lib_div::makeInstance('Tx_Extbase_Configuration_BackendConfigurationManager');
$typoScriptSetup = $configurationManager->loadTypoScriptSetup();
return $typoScriptSetup['module.']['tx_' . strtolower($extensionName) . '.']['settings.'];
}
}
?>
\ No newline at end of file
......@@ -33,13 +33,21 @@
*/
class Tx_Extbase_Dispatcher {
/**
* Back reference to the parent content object
* This has to be public as it is set directly from TYPO3
*
* @var tslib_cObj
*/
public $cObj;
/**
* @var Tx_Extbase_Utility_ClassLoader
*/
protected $classLoader;
/**
* @var Tx_Extbase_Configuration_Manager
* @var Tx_Extbase_Configuration_AbstractConfigurationManager
*/
protected static $configurationManager;
......@@ -71,7 +79,7 @@ class Tx_Extbase_Dispatcher {
* Creates a request an dispatches it to a controller.
*
* @param string $content The content
* @param array|NULL $configuration The TS configuration array
* @param array $configuration The TS configuration array
* @return string $content The processed content
*/
public function dispatch($content, $configuration) {
......@@ -113,7 +121,7 @@ class Tx_Extbase_Dispatcher {
$response->sendHeaders();
return $response->getContent();
}
/**
* Initializes the autoload mechanism of Extbase. This is supplement to the core autoloader.
*
......@@ -137,13 +145,18 @@ class Tx_Extbase_Dispatcher {
protected function initializeConfigurationManagerAndFrameworkConfiguration($configuration) {
$configurationSources = array();
$configurationSources[] = t3lib_div::makeInstance('Tx_Extbase_Configuration_Source_TypoScriptSource');
if (!empty($this->cObj->data['pi_flexform'])) {
$configurationSource = t3lib_div::makeInstance('Tx_Extbase_Configuration_Source_FlexFormSource');
$configurationSource->setFlexFormContent($this->cObj->data['pi_flexform']);
$configurationSources[] = $configurationSource;
if (TYPO3_MODE === 'FE') {
if (!empty($this->cObj->data['pi_flexform'])) {
$configurationSource = t3lib_div::makeInstance('Tx_Extbase_Configuration_Source_FlexFormSource');
$configurationSource->setFlexFormContent($this->cObj->data['pi_flexform']);
$configurationSources[] = $configurationSource;
}
self::$configurationManager = t3lib_div::makeInstance('Tx_Extbase_Configuration_FrontendConfigurationManager', $configurationSources);
self::$configurationManager->setContentObject($this->cObj);
} else {
self::$configurationManager = t3lib_div::makeInstance('Tx_Extbase_Configuration_BackendConfigurationManager', $configurationSources);
}
self::$configurationManager = t3lib_div::makeInstance('Tx_Extbase_Configuration_Manager', $configurationSources);
self::$extbaseFrameworkConfiguration = self::$configurationManager->getFrameworkConfiguration($configuration, $this->cObj);
self::$extbaseFrameworkConfiguration = self::$configurationManager->getFrameworkConfiguration($configuration);
}
/**
......@@ -201,7 +214,7 @@ class Tx_Extbase_Dispatcher {
$storageBackend->injectDataMapper($dataMapper);
$qomFactory = t3lib_div::makeInstance('Tx_Extbase_Persistence_QOM_QueryObjectModelFactory', $storageBackend, $dataMapper);
$persistenceSession = t3lib_div::makeInstance('Tx_Extbase_Persistence_Session'); // singleton
$persistenceBackend = t3lib_div::makeInstance('Tx_Extbase_Persistence_Backend', $persistenceSession, $storageBackend); // singleton
......@@ -212,12 +225,12 @@ class Tx_Extbase_Dispatcher {
$persistenceBackend->injectValueFactory(t3lib_div::makeInstance('Tx_Extbase_Persistence_ValueFactory'));
$objectManager = t3lib_div::makeInstance('Tx_Extbase_Object_Manager'); // singleton
$persistenceManager = t3lib_div::makeInstance('Tx_Extbase_Persistence_Manager'); // singleton
$persistenceManager->injectBackend($persistenceBackend);
$persistenceManager->injectSession($persistenceSession);
$persistenceManager->injectObjectManager($objectManager);
self::$persistenceManager = $persistenceManager;
}
......@@ -293,7 +306,7 @@ class Tx_Extbase_Dispatcher {
$dispatcherControllerAction = $this->getDispatcherControllerAction($configuration, $dispatcherParameters);
// Extract module function settings from request
$moduleFunctionControllerAction = $this->getModuleFunctionControllerAction($module, $fallbackControllerAction['controllerName']);
$moduleFunctionControllerAction = $this->getModuleFunctionControllerAction($module, $fallbackControllerAction['controllerName']);
// Dispatcher controller/action has precedence over default controller/action
$controllerAction = t3lib_div::array_merge_recursive_overrule($fallbackControllerAction, $dispatcherControllerAction, FALSE, FALSE);
......@@ -305,7 +318,7 @@ class Tx_Extbase_Dispatcher {
/**
* Returns the fallback controller/action pair to be used when request does not contain
* any controller/action to be used or the provided parameters are not valid.
* any controller/action to be used or the provided parameters are not valid.
*
* @param array $configuration The module configuration
* @return array The controller/action pair
......@@ -417,37 +430,39 @@ class Tx_Extbase_Dispatcher {
* @return string The module rendered view
*/
protected function transfer($module, $controller, $action) {
$config = $GLOBALS['TBE_MODULES'][$module];
$extbaseConfiguration = array(
$config = $GLOBALS['TBE_MODULES'][$module];
$extbaseConfiguration = array(
'userFunc' => 'tx_extbase_dispatcher->dispatch',
'pluginName' => $module,
'extensionName' => $config['extensionName'],
'controller' => $controller,
'action' => $action,
'switchableControllerActions.' => array(),
'persistence' => '< plugin.tx_' . strtolower($config['extensionName']) . '.persistence',
'settings' => '< module.tx_' . strtolower($config['extensionName']) . '.settings',
'persistence' => '< module.tx_' . strtolower($config['extensionName']) . '.persistence',
'view' => '< module.tx_' . strtolower($config['extensionName']) . '.view',
);
$i = 1;
foreach ($config['controllerActions'] as $controller => $actions) {
// Add an "extObj" action for the default controller to handle external
// SCbase modules which add function menu entries
if ($i == 1) {
$actions .= ',extObj';
$actions .= ',extObj';
}
$extbaseConfiguration['switchableControllerActions.'][$i++ . '.'] = array(
'controller' => $controller,
'actions' => $actions,
);
}
// BACK_PATH is the path from the typo3/ directory from within the
// directory containing the controller file. We are using mod.php dispatcher
// and thus we are already within typo3/ because we call typo3/mod.php
$GLOBALS['BACK_PATH'] = '';
return $this->dispatch('', $extbaseConfiguration);
}
}
?>
\ No newline at end of file
......@@ -285,7 +285,11 @@ abstract class Tx_Extbase_MVC_Controller_AbstractController implements Tx_Extbas
protected function redirectToURI($uri, $delay = 0, $statusCode = 303) {
if (!$this->request instanceof Tx_Extbase_MVC_Web_Request) throw new Tx_Extbase_MVC_Exception_UnsupportedRequestType('redirect() only supports web requests.', 1220539734);
$uri = $this->request->getBaseURI() . (string)$uri;
$baseUri = $this->request->getBaseURI();
if (TYPO3_MODE === 'BE') {
$baseUri .= TYPO3_mainDir;
}
$uri = $baseUri . (string)$uri;
$escapedUri = htmlentities($uri, ENT_QUOTES, 'utf-8');
$this->response->setContent('<html><head><meta http-equiv="refresh" content="' . intval($delay) . ';url=' . $escapedUri . '"/></head></html>');
$this->response->setStatus($statusCode);
......
......@@ -256,11 +256,11 @@ class Tx_Extbase_MVC_Controller_ActionController extends Tx_Extbase_MVC_Controll
$view = $this->objectManager->getObject('Tx_Fluid_View_TemplateView');
$controllerContext = $this->buildControllerContext();
$view->setControllerContext($controllerContext);
// Template Path Override
$extbaseFrameworkConfiguration = Tx_Extbase_Dispatcher::getExtbaseFrameworkConfiguration();
if (isset($extbaseFrameworkConfiguration['view']['templateRootPath']) && $extbaseFrameworkConfiguration['view']['templateRootPath']) {
$view->setTemplateRootPath($extbaseFrameworkConfiguration['view']['templateRootPath']);
$view->setTemplateRootPath(t3lib_div::getFileAbsFileName($extbaseFrameworkConfiguration['view']['templateRootPath']));
}
if ($view->hasTemplate() === FALSE) {
......@@ -274,6 +274,7 @@ class Tx_Extbase_MVC_Controller_ActionController extends Tx_Extbase_MVC_Controll
}
$view->initializeView(); // In FLOW3, solved through Object Lifecycle methods, we need to call it explicitely.
$view->assign('flashMessages', $this->popFlashMessages());
$view->assign('settings', $this->settings);
return $view;
}