<categoryname>general.page.seo</categoryname>
<optiontype>boolean</optiontype>
<defaultvalue>0</defaultvalue>
+ <enableoptions>!url_controller_replacement</enableoptions>
</option>
<option name="url_omit_index_php">
<categoryname>general.page.seo</categoryname>
<optiontype>boolean</optiontype>
<defaultvalue>0</defaultvalue>
</option>
- <option name="url_to_lowercase">
+ <option name="url_controller_replacement">
<categoryname>general.page.seo</categoryname>
- <optiontype>boolean</optiontype>
- <defaultvalue>1</defaultvalue>
+ <optiontype>urlControllerReplacement</optiontype>
</option>
<option name="url_title_component_replacement">
<categoryname>general.page.seo</categoryname>
<delete>
<option name="cache_source_memcached_use_pconnect" />
<option name="http_gzip_level" />
+ <option name="url_to_lowercase" />
</delete>
</data>
$controllers = array();
$path .= $type . '/';
- $files = glob($path . '*' . ucfirst($type) . '.class.php');
+ $type = ucfirst($type);
+ $files = glob($path . '*' . $type . '.class.php');
if ($files === false) {
return array();
}
foreach ($files as $file) {
$file = basename($file);
- if (preg_match('~^([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)(Action|Form|Page)\.class\.php$~', $file, $match)) {
+ if (preg_match('~^([A-Z][A-Za-z0-9]*)' . $type . '\.class\.php$~', $file, $match)) {
if ($match[1] === 'I') {
continue;
}
$controller = mb_strtolower($match[1]);
- $fqn = '\\' . $abbreviation . '\\' . ($isACP ? 'acp\\' : '') . $type . '\\' . $match[1] . $match[2];
+ $fqn = '\\' . $abbreviation . '\\' . ($isACP ? 'acp\\' : '') . $type . '\\' . $match[1] . $type;
$controllers[$controller] = $fqn;
}
--- /dev/null
+<?php
+namespace wcf\system\option;
+use wcf\data\option\Option;
+use wcf\util\StringUtil;
+use wcf\system\exception\UserInputException;
+use wcf\system\WCF;
+use wcf\system\cache\builder\ControllerCacheBuilder;
+
+/**
+ * Option type implementation for URL controller replacements.
+ *
+ * @author Alexander Ebert
+ * @copyright 2001-2015 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.wcf
+ * @subpackage system.option
+ * @category Community Framework
+ */
+class UrlControllerReplacementOptionType extends TextareaOptionType {
+ /**
+ * list of known controllers grouped by application
+ * @var array<array>
+ */
+ protected $controllers = null;
+
+ /**
+ * @see \wcf\system\option\IOptionType::getData()
+ */
+ public function getData(Option $option, $newValue) {
+ return $this->cleanup($newValue);
+ }
+
+ /**
+ * @see \wcf\system\option\IOptionType::validate()
+ */
+ public function validate(Option $option, $newValue) {
+ $newValue = $this->cleanup($newValue);
+ if (!empty($newValue)) {
+ $lines = explode("\n", $newValue);
+
+ $aliases = array();
+ $controllers = array();
+ for ($i = 0, $length = count($lines); $i < $length; $i++) {
+ $line = $lines[$i];
+ if (preg_match('~^(?P<controller>[a-z0-9\-]+)=(?P<alias>[a-z0-9\-]+)$~', $line, $matches)) {
+ // check if there is already a replacement for given controller
+ if (in_array($matches['controller'], $controllers)) {
+ WCF::getTPL()->assign('urlControllerReplacementError', $matches['controller']);
+ throw new UserInputException($option->optionName, 'controllerReplacementDuplicateController', array('controller' => $matches['controller']));
+ }
+
+ // check if there is already the same alias for a different controller
+ if (in_array($matches['alias'], $aliases)) {
+ WCF::getTPL()->assign('urlControllerReplacementError', $matches['alias']);
+ throw new UserInputException($option->optionName, 'controllerReplacementDuplicateAlias', array('alias' => $matches['alias']));
+ }
+
+ $aliases[] = $matches['alias'];
+ $controllers[] = $matches['controller'];
+
+ // check if controller exists
+ if (!$this->isKnownController($matches['controller'])) {
+ WCF::getTPL()->assign('urlControllerReplacementError', $matches['controller']);
+ throw new UserInputException($option->optionName, 'controllerReplacementUnknown', array('controller' => $matches['controller']));
+ }
+
+ // check if alias collides with an existing controller name
+ if ($this->isKnownController($matches['alias'])) {
+ WCF::getTPL()->assign('urlControllerReplacementError', $matches['alias']);
+ throw new UserInputException($option->optionName, 'controllerReplacementCollision', array('alias' => $matches['alias']));
+ }
+ }
+ else {
+ throw new UserInputException($option->optionName, 'controllerReplacementInvalidFormat', array('line' => $line));
+ }
+ }
+ }
+ }
+
+ /**
+ * Cleans up newlines and converts input to lower-case.
+ *
+ * @param string $newValue
+ * @return string
+ */
+ protected function cleanup($newValue) {
+ $newValue = StringUtil::unifyNewlines($newValue);
+ $newValue = trim($newValue);
+ $newValue = preg_replace('~\n+~', "\n", $newValue);
+ $newValue = mb_strtolower($newValue);
+
+ return $newValue;
+ }
+
+ /**
+ * Returns true if given controller name is known to the system, used to
+ * prevent aliases colliding with existing ones.
+ *
+ * @param string $controller
+ * @return boolean
+ */
+ protected function isKnownController($controller) {
+ if ($this->controllers === null) {
+ $this->controllers = ControllerCacheBuilder::getInstance()->getData(array(
+ 'environment' => 'user'
+ ));
+ }
+
+ $controller = str_replace('-', '', $controller);
+ foreach ($this->controllers as $types) {
+ foreach ($types as $controllers) {
+ if (isset($controllers[$controller])) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+}
--- /dev/null
+<?php
+namespace wcf\system\request;
+use wcf\system\application\ApplicationHandler;
+use wcf\system\menu\page\PageMenu;
+
+/**
+ * Flexible route implementation to resolve HTTP requests.
+ *
+ * Inspired by routing mechanism used by ASP.NET MVC and released under the terms of
+ * the Microsoft Public License (MS-PL) http://www.opensource.org/licenses/ms-pl.html
+ *
+ * @author Alexander Ebert
+ * @copyright 2001-2015 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.wcf
+ * @subpackage system.request
+ * @category Community Framework
+ */
+class FlexibleRoute implements IRoute {
+ /**
+ * schema for outgoing links
+ * @var array<array>
+ */
+ protected $buildSchema = array();
+
+ /**
+ * route is restricted to ACP
+ * @var boolean
+ */
+ protected $isACP = false;
+
+ /**
+ * pattern for incoming requests
+ * @var string
+ */
+ protected $pattern = '';
+
+ /**
+ * list of required components
+ * @var array<string>
+ */
+ protected $requireComponents = array();
+
+ /**
+ * parsed request data
+ * @var array<mixed>
+ */
+ protected $routeData = array();
+
+ /**
+ * cached list of transformed controller names
+ * @var array<string>
+ */
+ protected static $controllerNames = array();
+
+ /**
+ * Creates a new flexible route instace.
+ *
+ * @param boolean $isACP
+ */
+ public function __construct($isACP) {
+ $this->isACP = $isACP;
+
+ $this->pattern = '~
+ /?
+ (?:
+ (?P<controller>[A-Za-z0-9\-]+)
+ (?:
+ /
+ (?P<id>\d+)
+ )?
+ )?
+ ~x';
+ $this->setBuildSchema('/{controller}/{id}-{title}/');
+ }
+
+ /**
+ * Sets the build schema used to build outgoing links.
+ *
+ * @param string $buildSchema
+ */
+ public function setBuildSchema($buildSchema) {
+ $this->buildSchema = array();
+
+ $buildSchema = ltrim($buildSchema, '/');
+ $components = preg_split('~{([a-z]+)}~', $buildSchema, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
+ $delimiters = array('/', '-', '.', '_');
+
+ foreach ($components as $component) {
+ $type = 'component';
+ if (in_array($component, $delimiters)) {
+ $type = 'separator';
+ }
+
+ $this->buildSchema[] = array(
+ 'type' => $type,
+ 'value' => $component
+ );
+ }
+ }
+
+ /**
+ * Sets the route pattern used to evaluate an incoming request.
+ *
+ * @param string $pattern
+ */
+ public function setPattern($pattern) {
+ $this->pattern = $pattern;
+ }
+
+ /**
+ * Sets the list of required components.
+ *
+ * @param array<string> $requiredComponents
+ */
+ public function setRequiredComponents(array $requiredComponents) {
+ $this->requireComponents = $requiredComponents;
+ }
+
+ /**
+ * @see \wcf\system\request\IRoute::buildLink()
+ */
+ public function buildLink(array $components) {
+ $application = (isset($components['application'])) ? $components['application'] : null;
+
+ // drop application component to avoid being appended as query string
+ unset($components['application']);
+
+ $link = '';
+
+ // handle default values for controller
+ $buildRoute = true;
+ if (count($components) == 1 && isset($components['controller'])) {
+ $ignoreController = false;
+
+ if (!RequestHandler::getInstance()->isACPRequest()) {
+ $landingPage = PageMenu::getInstance()->getLandingPage();
+ if ($landingPage !== null && strcasecmp($landingPage->getController(), $components['controller']) == 0) {
+ $ignoreController = true;
+ }
+
+ // check if this is the default controller of the requested application
+ if (!$ignoreController && $application !== null) {
+ if (RouteHandler::getInstance()->getDefaultController($application) == $components['controller']) {
+ // check if this is the primary application and the landing page originates to the same application
+ $primaryApplication = ApplicationHandler::getInstance()->getPrimaryApplication();
+ $abbreviation = ApplicationHandler::getInstance()->getAbbreviation($primaryApplication->packageID);
+ if ($abbreviation != $application || $landingPage === null || $landingPage->getApplication() != 'wcf') {
+ $ignoreController = true;
+ }
+ }
+ }
+ }
+
+ // drops controller from route
+ if ($ignoreController) {
+ $buildRoute = false;
+
+ // unset the controller, since it would otherwise be added with http_build_query()
+ unset($components['controller']);
+ }
+ }
+
+ if ($buildRoute) {
+ $lastSeparator = null;
+ foreach ($this->buildSchema as $component) {
+ $value = $component['value'];
+
+ if ($component['type'] === 'separator') {
+ $lastSeparator = $value;
+ }
+ else {
+ // routes are build from left-to-right
+ if (empty($components[$value])) {
+ break;
+ }
+
+ if ($lastSeparator !== null) {
+ $link .= $lastSeparator;
+ $lastSeparator = null;
+ }
+
+ // handle controller names
+ if ($value === 'controller') {
+ $components[$value] = $this->getControllerName($application, $components[$value]);
+ }
+
+ $link .= $components[$value];
+ unset($components[$value]);
+ }
+ }
+
+ if (!empty($link)) {
+ $link .= '/';
+ }
+ }
+
+ if ($this->isACP || !URL_OMIT_INDEX_PHP) {
+ if (!empty($link)) {
+ $link = 'index.php?' . $link;
+ }
+ }
+
+ if (!empty($components)) {
+ if (strpos($link, '?') === false) $link .= '?';
+ else $link .= '&';
+
+ $link .= http_build_query($components, '', '&');
+ }
+
+ return $link;
+ }
+
+ /**
+ * @see \wcf\system\request\IRoute::canHandle()
+ */
+ public function canHandle(array $components) {
+ if (!empty($this->requireComponents)) {
+ foreach ($this->requireComponents as $component => $pattern) {
+ if (empty($components[$component])) {
+ return false;
+ }
+
+ if ($pattern && !preg_match($pattern, $components[$component])) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * @see \wcf\system\request\IRoute::getRouteData()
+ */
+ public function getRouteData() {
+ return $this->routeData;
+ }
+
+ /**
+ * @see \wcf\system\request\IRoute::isACP()
+ */
+ public function isACP() {
+ return $this->isACP;
+ }
+
+ /**
+ * @see \wcf\system\request\IRoute::matches()
+ */
+ public function matches($requestURL) {
+ if (preg_match($this->pattern, $requestURL, $matches)) {
+ foreach ($matches as $key => $value) {
+ if (!is_numeric($key)) {
+ $this->routeData[$key] = $value;
+ }
+ }
+
+ $this->routeData['isDefaultController'] = (!isset($this->routeData['controller']));
+
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Returns the transformed controller name.
+ *
+ * @param string $application
+ * @param string $controller
+ * @return string
+ */
+ protected function getControllerName($application, $controller) {
+ if (!isset(self::$controllerNames[$controller])) {
+ $parts = preg_split('~([A-Z][a-z0-9]+)~', $controller, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
+ $controllerName = '';
+ for ($i = 0, $length = count($parts); $i < $length; $i++) {
+ if (!empty($controllerName)) $controllerName .= '-';
+ $controllerName .= strtolower($parts[$i]);
+ }
+
+ $alias = RequestHandler::getInstance()->getAliasByController($controllerName);
+
+ self::$controllerNames[$controller] = ($alias) ?: $controllerName;
+ }
+
+ return self::$controllerNames[$controller];
+ }
+}
--- /dev/null
+<?php
+namespace wcf\system\request;
+
+/**
+ * Default interface for route implementations.
+ *
+ * @author Alexander Ebert
+ * @copyright 2001-2015 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.wcf
+ * @subpackage system.request
+ * @category Community Framework
+ */
+interface IRoute {
+ /**
+ * Builds a link upon route components.
+ *
+ * @param array $components
+ * @return string
+ */
+ public function buildLink(array $components);
+
+ /**
+ * Returns true if current route can handle the build request.
+ *
+ * @param array $components
+ * @return boolean
+ */
+ public function canHandle(array $components);
+
+ /**
+ * Returns parsed route data.
+ *
+ * @return array
+ */
+ public function getRouteData();
+
+ /**
+ * Returns true if route applies for ACP.
+ *
+ * @return boolean
+ */
+ public function isACP();
+
+ /**
+ * Returns true if given request url matches this route.
+ *
+ * @param string $requestURL
+ * @return boolean
+ */
+ public function matches($requestURL);
+}
* Handles relative links within the wcf.
*
* @author Marcel Werk
- * @copyright 2001-2014 WoltLab GmbH
+ * @copyright 2001-2015 WoltLab GmbH
* @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
* @package com.woltlab.wcf
* @subpackage system.request
// trim to 80 characters
$parameters['title'] = rtrim(mb_substr($parameters['title'], 0, 80), '-');
- if (URL_TO_LOWERCASE) {
+ if (!URL_LEGACY_MODE) {
$parameters['title'] = mb_strtolower($parameters['title']);
}
if ($encodeTitle) $parameters['title'] = rawurlencode($parameters['title']);
}
- $parameters['controller'] = (URL_TO_LOWERCASE) ? mb_strtolower($controller) : $controller;
+ $parameters['controller'] = $controller;
$routeURL = RouteHandler::getInstance()->buildRoute($parameters, $isACP);
if (!$isRaw && !empty($url)) {
$routeURL .= (strpos($routeURL, '?') === false) ? '?' : '&';
* Handles http requests.
*
* @author Marcel Werk
- * @copyright 2001-2014 WoltLab GmbH
+ * @copyright 2001-2015 WoltLab GmbH
* @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
* @package com.woltlab.wcf
* @subpackage system.request
*/
protected $controllers = null;
+ /**
+ * list of controller aliases
+ * @var array<string>
+ */
+ protected $controllerAliases = array();
+
/**
* true, if current domain mismatch any known domain
* @var boolean
$this->controllers = ControllerCacheBuilder::getInstance()->getData(array(
'environment' => ($this->isACPRequest ? 'admin' : 'user')
));
+
+ if (!URL_LEGACY_MODE && URL_CONTROLLER_REPLACEMENT) {
+ $controllerAliases = explode("\n", URL_CONTROLLER_REPLACEMENT);
+ for ($i = 0, $length = count($controllerAliases); $i < $length; $i++) {
+ $tmp = explode('=', $controllerAliases[$i]);
+ $this->controllerAliases[$tmp[0]] = $tmp[1];
+ }
+ }
}
}
exit;
}
}
+
+ // handle controller aliasing
+ if (!URL_LEGACY_MODE && isset($routeData['controller'])) {
+ // aliased controller, pretend it does not exist
+ if ($this->getAliasByController($routeData['controller']) !== null) {
+ throw new IllegalLinkException();
+ }
+
+ $controller = $this->getControllerByAlias($routeData['controller']);
+ if ($controller !== null) {
+ $routeData['controller'] = $controller;
+ }
+ }
+ }
+ else if (empty($routeData['controller'])) {
+ $routeData['controller'] = 'Index';
}
$controller = $routeData['controller'];
// validate class name
- if (!preg_match('~^[a-z0-9_]+$~i', $controller)) {
+ if (!preg_match('~^[a-z0-9' . (URL_LEGACY_MODE ? '' : '\-') . ']+$~i', $controller)) {
throw new SystemException("Illegal class name '".$controller."'");
}
*/
protected function getClassData($controller, $pageType, $application) {
$className = false;
-
if ($this->controllers !== null) {
$className = $this->lookupController($controller, $pageType, $application);
if ($className === false && $application != 'wcf') {
protected function lookupController($controller, $pageType, $application) {
if (isset($this->controllers[$application]) && isset($this->controllers[$application][$pageType])) {
$ciController = mb_strtolower($controller);
+ if (!URL_LEGACY_MODE) $ciController = str_replace('-', '', $ciController);
+
if (isset($this->controllers[$application][$pageType][$ciController])) {
return $this->controllers[$application][$pageType][$ciController];
}
public function inRescueMode() {
return $this->inRescueMode;
}
+
+ /**
+ * Returns the alias by controller or null if there is no match.
+ *
+ * @param string $controller
+ * @return string
+ */
+ public function getAliasByController($controller) {
+ if (isset($this->controllerAliases[$controller])) {
+ return $this->controllerAliases[$controller];
+ }
+
+ return null;
+ }
+
+ /**
+ * Returns the controller by alias or null if there is no match.
+ *
+ * @param string $alias
+ * @return string
+ */
+ public function getControllerByAlias($alias) {
+ $controller = array_search($alias, $this->controllerAliases);
+ if ($controller !== false) {
+ return $controller;
+ }
+
+ return null;
+ }
}
* the Microsoft Public License (MS-PL) http://www.opensource.org/licenses/ms-pl.html
*
* @author Alexander Ebert
- * @copyright 2001-2014 WoltLab GmbH
+ * @copyright 2001-2015 WoltLab GmbH
* @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
* @package com.woltlab.wcf
* @subpackage system.request
* @category Community Framework
*/
-class Route {
+class Route implements IRoute {
/**
* route controller if controller is no part of the route schema
* @var string
}
/**
- * Returns true if given request url matches this route.
- *
- * @param string $requestURL
- * @return boolean
+ * @see \wcf\system\request\IRoute::matches()
*/
public function matches($requestURL) {
$urlParts = $this->getParts($requestURL);
}
/**
- * Returns parsed route data.
- *
- * @return array
+ * @see \wcf\system\request\IRoute::getRouteData()
*/
public function getRouteData() {
return $this->routeData;
}
/**
- * Returns true if current route can handle the build request.
- *
- * @param array $components
- * @return boolean
+ * @see \wcf\system\request\IRoute::canHandle()
*/
public function canHandle(array $components) {
foreach ($this->routeSchema as $schemaPart) {
}
/**
- * Builds a link upon route components.
- *
- * @param array $components
- * @return string
+ * @see \wcf\system\request\IRoute::buildLink()
*/
public function buildLink(array $components) {
$application = (isset($components['application'])) ? $components['application'] : null;
}
/**
- * Returns true if route applies for ACP.
- *
- * @return boolean
+ * @see \wcf\system\request\IRoute::isACP()
*/
public function isACP() {
return $this->isACP;
<?php
namespace wcf\system\request;
+use wcf\system\application\ApplicationHandler;
use wcf\system\event\EventHandler;
use wcf\system\exception\SystemException;
use wcf\system\SingletonFactory;
+use wcf\system\WCF;
use wcf\util\FileUtil;
/**
* the Microsoft Public License (MS-PL) http://www.opensource.org/licenses/ms-pl.html
*
* @author Alexander Ebert
- * @copyright 2001-2014 WoltLab GmbH
+ * @copyright 2001-2015 WoltLab GmbH
* @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
* @package com.woltlab.wcf
* @subpackage system.request
*/
protected static $secure = null;
+ /**
+ * list of application abbreviation and default controller name
+ * @var array<string>
+ */
+ protected $defaultControllers = null;
+
/**
* true, if default controller is used (support for custom landing page)
* @var boolean
/**
* list of available routes
- * @var array<\wcf\system\request\Route>
+ * @var array<\wcf\system\request\IRoute>
*/
protected $routes = array();
* Adds default routes.
*/
protected function addDefaultRoutes() {
- $acpRoute = new Route('ACP_default', true);
- $acpRoute->setSchema('/{controller}/{id}');
- $acpRoute->setParameterOption('controller', 'Index', null, true);
- $acpRoute->setParameterOption('id', null, '\d+', true);
- $this->addRoute($acpRoute);
-
- $defaultRoute = new Route('default');
- $defaultRoute->setSchema('/{controller}/{id}');
- $defaultRoute->setParameterOption('controller', null, null, true);
- $defaultRoute->setParameterOption('id', null, '\d+', true);
- $this->addRoute($defaultRoute);
+ if (URL_LEGACY_MODE) {
+ $acpRoute = new Route('ACP_default', true);
+ $acpRoute->setSchema('/{controller}/{id}');
+ $acpRoute->setParameterOption('controller', 'Index', null, true);
+ $acpRoute->setParameterOption('id', null, '\d+', true);
+ $this->addRoute($acpRoute);
+
+ $defaultRoute = new Route('default');
+ $defaultRoute->setSchema('/{controller}/{id}');
+ $defaultRoute->setParameterOption('controller', null, null, true);
+ $defaultRoute->setParameterOption('id', null, '\d+', true);
+ $this->addRoute($defaultRoute);
+ }
+ else {
+ $acpRoute = new FlexibleRoute(true);
+ $this->addRoute($acpRoute);
+
+ $defaultRoute = new FlexibleRoute(false);
+ $this->addRoute($defaultRoute);
+ }
}
/**
* Adds a new route to the beginning of all routes.
*
- * @param \wcf\system\request\Route $route
+ * @param \wcf\system\request\IRoute $route
*/
- public function addRoute(Route $route) {
+ public function addRoute(IRoute $route) {
array_unshift($this->routes, $route);
}
/**
* Returns all registered routes.
*
- * @return array<\wcf\system\request\Route>
+ * @return array<\wcf\system\request\IRoute>
**/
public function getRoutes() {
return $this->routes;
return self::$pathInfo;
}
+
+ /**
+ * Returns the default controller name for given application.
+ *
+ * @param string $application
+ * @return string
+ */
+ public function getDefaultController($application) {
+ $this->loadDefaultControllers();
+
+ if (isset($this->defaultControllers[$application])) {
+ return $this->defaultControllers[$application];
+ }
+
+ return '';
+ }
+
+ /**
+ * Loads the default controllers for each active application.
+ */
+ protected function loadDefaultControllers() {
+ if ($this->defaultControllers === null) {
+ $this->defaultControllers = array();
+
+ foreach (ApplicationHandler::getInstance()->getApplications() as $application) {
+ $app = WCF::getApplicationObject($application);
+
+ if (!$app) {
+ continue;
+ }
+
+ $controller = $app->getPrimaryController();
+
+ if (!$controller) {
+ continue;
+ }
+
+ $controller = explode('\\', $controller);
+ $controllerName = preg_replace('~(Action|Form|Page)$~', '', array_pop($controller));
+
+ $this->defaultControllers[$controller[0]] = $controllerName;
+ }
+ }
+ }
}
<item name="wcf.acp.option.cookie_path"><![CDATA[Cookiepfad]]></item>
<item name="wcf.acp.option.cookie_path.description"><![CDATA[Der Cookiepfad wird absolut zum Document Root angegeben - also z.B. "/forum" für http://www.woltlab.de/forum.]]></item>
<item name="wcf.acp.option.cookie_prefix"><![CDATA[Präfix für Cookienamen]]></item>
+ <item name="wcf.acp.option.error.controllerReplacementCollision"><![CDATA[Das Alias „{$urlControllerReplacementError}“ kollidiert mit einem real existierenden Controller und ist daher unzulässig.]]></item>
+ <item name="wcf.acp.option.error.controllerReplacementDuplicateAlias"><![CDATA[Das Alias „{$urlControllerReplacementError}“ wird bereits verwendet.]]></item>
+ <item name="wcf.acp.option.error.controllerReplacementDuplicateController"><![CDATA[Dem Controller „{$urlControllerReplacementError}“ wurde bereits ein Alias zugewiesen.]]></item>
+ <item name="wcf.acp.option.error.controllerReplacementDuplicateUnknown"><![CDATA[Der Controller „{$urlControllerReplacementError}“ ist unbekannt.]]></item>
<item name="wcf.acp.option.error.tooHigh"><![CDATA[Der angegebene Wert ist zu hoch.{if $option->maxvalue !== null} Der maximale Wert ist {#$option->maxvalue}.{/if}]]></item>
<item name="wcf.acp.option.error.tooLow"><![CDATA[Der angegebene Wert ist zu gering.{if $option->minvalue !== null} Der minimale Wert ist {#$option->minvalue}.{/if}]]></item>
<item name="wcf.acp.option.export"><![CDATA[Optionen sichern]]></item>
Beispiele:<br />
WBB=WoltLab Burning Board<br />
GmbH=Gesellschaft mit beschränkter Haftung]]></item>
+ <item name="wcf.acp.option.url_controller_replacement"><![CDATA[Controller-Umbenennung]]></item>
+ <item name="wcf.acp.option.url_controller_replacement.description"><![CDATA[Sie können die Controller umbenennen und diesen so eine neue Bezeichnung zuweisen, pro Zeile können Sie einen Alias definieren. Die Angabe muss im Format „realer-name=neuer-name“ erfolgen und darf aus Kompatibilitätsgründen nur aus den Kleinbuchstaben a-z, den Zahlen 0-9 sowie Bindestrichen bestehen. Beispiele:
+<ul class="nativeList">
+ <li>„board-list=forums“, der Link „http://example.com/index.php?board-list/“ wird zu „http://example.com/index.php?forums/“</li>
+ <li>„members-list=profile“, der Link „http://example.com/index.php?members-list/“ wird zu „http://example.com/index.php?profile/“</li>
+</ul>]]></item>
<item name="wcf.acp.option.users_online_record_no_guests"><![CDATA[Nur registrierte Benutzer im Benutzer-Online-Rekord zählen]]></item>
<item name="wcf.acp.option.users_online_enable_legend"><![CDATA[Legende der Benutzergruppen anzeigen]]></item>
<item name="wcf.acp.option.category.general.system.googleMaps"><![CDATA[Google Maps]]></item>
<item name="wcf.acp.option.module_cookie_policy_page"><![CDATA[Erklärung zum „Einsatz von Cookies“ aktivieren]]></item>
<item name="wcf.acp.option.module_cookie_policy_page.description"><![CDATA[Weist Besucher beim ersten Aufruf der Seite gemäß EU-Richtlinie 2009/136/EG auf den Einsatz von Cookies hin.]]></item>
<item name="wcf.acp.option.url_omit_index_php"><![CDATA[Link-Umschreibungen aktivieren]]></item>
- <item name="wcf.acp.option.url_omit_index_php.description"><![CDATA[Wandelt Links in eine vereinfachte Form um, aus „http://example.com/?Thread/1-Dies-ist-ein-Test/“ wird „http://example.com/thread/1-dies-ist-ein-test/“ und vergleichbar. Achtung: Die Aktivierung der Link-Umschreibungen erfordert Rewrite-Unterstützung in Ihrem Webserver sowie eine entsprechende Konfiguration. Fehlerhafte Einstellungen können hier dazu führen, dass Links nicht mehr aufrufbar sind.]]></item>
+ <item name="wcf.acp.option.url_omit_index_php.description"><![CDATA[Wandelt Links in eine vereinfachte Form um, aus „http://example.com/index.php?thread/1-dies-ist-ein-test/“ wird „http://example.com/thread/1-dies-ist-ein-test/“ und vergleichbar. Achtung: Die Aktivierung der Link-Umschreibungen erfordert Rewrite-Unterstützung in Ihrem Webserver sowie eine entsprechende Konfiguration. Fehlerhafte Einstellungen können hier dazu führen, dass Links nicht mehr aufrufbar sind.]]></item>
<item name="wcf.acp.option.url_legacy_mode"><![CDATA[Kompatibilitätsmodus für Links aktivieren]]></item>
<item name="wcf.acp.option.url_legacy_mode.description"><![CDATA[Die Aktivierung dieses Modus erzwingt die URL-Struktur von WoltLab Community Framework 2.0 und sollte nur aus Kompatibilitätsgründen zur Beibehaltung der Link-Gültigkeit aktiviert werden:
<ul class="nativeList">
<li>WCF 2.0: „index.php/Thread/123-Title/“</li>
- <li>WCF 2.1+: „?Thread/123-Title/“</li>
+ <li>WCF 2.1+: „index.php?thread/123-title/“</li>
</ul>]]></item>
- <item name="wcf.acp.option.url_to_lowercase"><![CDATA[Durchgehende Kleinschreibung in Links aktivieren]]></item>
- <item name="wcf.acp.option.url_to_lowercase.description"><![CDATA[Links verwenden keine Großbuchstaben mehr, aus „Thread/1-Dies-ist-ein-Test/“ wird „thread/1-dies-ist-ein-test/“.]]></item>
<item name="wcf.acp.option.module_wcf_ad"><![CDATA[Werbung]]></item>
<item name="wcf.acp.option.module_wcf_ad.description"><![CDATA[Aktiviert die <a href="{link controller='AdList'}{/link}">Verwaltung von Werbe-Anzeigen</a>.]]></item>
<item name="wcf.acp.option.captcha_type"><![CDATA[Captcha-Art]]></item>
<item name="wcf.acp.option.cookie_path"><![CDATA[Cookie Path]]></item>
<item name="wcf.acp.option.cookie_path.description"><![CDATA[Value should be absolute to Document Root, e.g. “/forum” for “http://www.woltlab.com/forum”.]]></item>
<item name="wcf.acp.option.cookie_prefix"><![CDATA[Cookie Prefix]]></item>
+ <item name="wcf.acp.option.error.controllerReplacementCollision"><![CDATA[The alias “{$urlControllerReplacementError}” equals an existing controller and cannot be used.]]></item>
+ <item name="wcf.acp.option.error.controllerReplacementDuplicateAlias"><![CDATA[The alias “{$urlControllerReplacementError}” is already in use.]]></item>
+ <item name="wcf.acp.option.error.controllerReplacementDuplicateController"><![CDATA[The controller “{$urlControllerReplacementError}” has already been aliased.]]></item>
+ <item name="wcf.acp.option.error.controllerReplacementDuplicateUnknown"><![CDATA[The controller “{$urlControllerReplacementError}” is unknown.]]></item>
<item name="wcf.acp.option.error.tooHigh"><![CDATA[Exceeds the maximum value{if $option->maxvalue !== null} of {#$option->maxvalue}{/if}.]]></item>
<item name="wcf.acp.option.error.tooLow"><![CDATA[Below the minimum value{if $option->minvalue !== null} of {#$option->minvalue}{/if}.]]></item>
<item name="wcf.acp.option.export"><![CDATA[Download Options]]></item>
Examples:<br />
WBB=WoltLab Burning Board<br />
GmbH=Gesellschaft mit beschränkter Haftung]]></item>
+ <item name="wcf.acp.option.url_controller_replacement"><![CDATA[Controller Aliasing]]></item>
+ <item name="wcf.acp.option.url_controller_replacement.description"><![CDATA[You can rename controllers by assigning an alias to them, please provide only one alias per line. Aliases must be defined as “real-name=custom-name” and contain only lower-case a-z, the numbers 0-9 and the dash for compatibility reasons. Examples:
+<ul class="nativeList">
+ <li>“board-list=forums”, the link “http://example.com/index.php?board-list/” will turn into “http://example.com/index.php?forums/”</li>
+ <li>“members-list=profiles”, the link “http://example.com/index.php?members-list/” will turn into “http://example.com/index.php?profiles/”</li>
+</ul>]]></item>
<item name="wcf.acp.option.users_online_enable_legend"><![CDATA[Display legend for “Users Online” list]]></item>
<item name="wcf.acp.option.category.general.system.googleMaps"><![CDATA[Google Maps]]></item>
<item name="wcf.acp.option.google_maps_zoom"><![CDATA[Map Zoom]]></item>
<item name="wcf.acp.option.module_cookie_policy_page"><![CDATA[Enable explanation on “Cookie Usage”]]></item>
<item name="wcf.acp.option.module_cookie_policy_page.description"><![CDATA[Displays a notice on cookie usage according to EU Directive 2009/136/EG upon first visit.]]></item>
<item name="wcf.acp.option.url_omit_index_php"><![CDATA[Enable URL-Rewrite]]></item>
- <item name="wcf.acp.option.url_omit_index_php.description"><![CDATA[Rewrites URLs into a better readable representation, turning links like “http://example.com/?Thread/1-Hello-I-am-John-Doe/” into “http://example.com/thread/1-hello-i-am-john-doe/” and similar. Heads up! This option requires a rewrite module installed on your webserver and an appropriate configuration; It will not work without any prior configuration applied by you!]]></item>
+ <item name="wcf.acp.option.url_omit_index_php.description"><![CDATA[Rewrites URLs into a better readable representation, turning links like “http://example.com/index.php?thread/1-hello-i-am-john-doe/” into “http://example.com/thread/1-hello-i-am-john-doe/” and similar. Heads up! This option requires a rewrite module installed on your webserver and an appropriate configuration; It will not work without any prior configuration applied by you!]]></item>
<item name="wcf.acp.option.url_legacy_mode"><![CDATA[Enable link compatibility mode]]></item>
<item name="wcf.acp.option.url_legacy_mode.description"><![CDATA[Enabling this option forces the system to use WoltLab Community Framework 2.0-compilant URLs and should only be used to ensure compatibility with legacy URLs:
<ul class="nativeList">
<li>WCF 2.0: “index.php/Thread/123-Title/”</li>
- <li>WCF 2.1+: “?Thread/123-Title/”</li>
+ <li>WCF 2.1+: “index.php?thread/123-title/”</li>
</ul>]]></item>
- <item name="wcf.acp.option.url_to_lowercase"><![CDATA[Force lower-case links]]></item>
- <item name="wcf.acp.option.url_to_lowercase.description"><![CDATA[Links will no longer contain uppercase letters turning links like “Thread/1-Hello-I-am-John-Doe/” into “thread/1-hello-i-am-john-doe/”.]]></item>
<item name="wcf.acp.option.module_wcf_ad"><![CDATA[Ads]]></item>
<item name="wcf.acp.option.module_wcf_ad.description"><![CDATA[Enables the <a href="{link controller='AdList'}{/link}">advertisement management</a>.]]></item>
<item name="wcf.acp.option.captcha_type"><![CDATA[Captcha Type]]></item>