</dl>
{if !$isMultilingual}
- <dl{if $errorField == 'customURL'} class="formError"{/if}>
+ <dl{if $errorField == 'customURL_0'} class="formError"{/if}>
<dt><label for="customURL">{lang}wcf.acp.page.customURL{/lang}</label></dt>
<dd>
<input type="text" id="customURL" name="customURL[0]" value="{if !$customURL[0]|empty}{$customURL[0]}{/if}" class="long" />
- {if $errorField == 'customURL'}
+ {if $errorField == 'customURL_0'}
<small class="innerError">
{if $errorType == 'empty'}
{lang}wcf.global.form.error.empty{/lang}
</dl>
{else}
{foreach from=$availableLanguages item=availableLanguage}
- <dl{if $errorField == 'customURL'} class="formError"{/if}>
+ {assign var='__errorFieldName' value='customURL_'|concat:$availableLanguage->languageID}
+ <dl{if $errorField == $__errorFieldName} class="formError"{/if}>
<dt><label for="customURL{@$availableLanguage->languageID}">{lang}wcf.acp.page.customURL{/lang} ({$availableLanguage->languageName})</label></dt>
<dd>
<input type="text" id="customURL{@$availableLanguage->languageID}" name="customURL[{@$availableLanguage->languageID}]" value="{if !$customURL[$availableLanguage->languageID]|empty}{$customURL[$availableLanguage->languageID]}{/if}" class="long" />
- {if $errorField == 'customURL'}
+ {if $errorField == $__errorFieldName}
<small class="innerError">
{if $errorType == 'empty'}
{lang}wcf.global.form.error.empty{/lang}
use wcf\data\application\ApplicationList;
use wcf\data\box\Box;
use wcf\data\box\BoxList;
+use wcf\data\language\Language;
use wcf\data\page\Page;
use wcf\data\page\PageAction;
use wcf\data\page\PageEditor;
*/
public $availableBoxes = [];
+ /**
+ * list of available languages
+ * @var Language[]
+ */
+ public $availableLanguages = [];
+
/**
* page custom URL
* @var string[]
$applicationList->readObjects();
$this->availableApplications = $applicationList->getObjects();
+ // get available languages
+ $this->availableLanguages = LanguageFactory::getInstance()->getLanguages();
+
// get boxes
$boxList = new BoxList();
$boxList->sqlOrderBy = 'box.name';
$this->validateApplicationPackageID();
- $this->validateCustomUrl();
+ $this->validateCustomUrls();
$this->validateBoxIDs();
}
*
* @throws UserInputException
*/
- protected function validateCustomUrl() {
- foreach ($this->customURL as $type => $customURL) {
- if (!empty($customURL) && !RouteHandler::isValidCustomUrl($customURL)) {
- throw new UserInputException('customURL_' . $type, 'invalid');
+ protected function validateCustomUrls() {
+ if (empty($this->customURL) && $this->pageType != 'system') {
+ if ($this->isMultilingual) {
+ $language1 = reset($this->availableLanguages);
+ throw new UserInputException('customURL_'.$language1->languageID);
+ }
+ else {
+ throw new UserInputException('customURL_0');
+ }
+ }
+
+ foreach ($this->customURL as $languageID => $customURL) {
+ $this->validateCustomUrl($languageID, $customURL);
+ }
+ }
+
+ /**
+ * Validates given custom url.
+ *
+ * @param integer $languageID
+ * @param string $customURL
+ *
+ * @throws UserInputException
+ */
+ protected function validateCustomUrl($languageID, $customURL) {
+ if (empty($customURL)) {
+ if ($this->pageType != 'system') {
+ throw new UserInputException('customURL_' . $languageID, 'invalid');
+ }
+ }
+ else if (!RouteHandler::isValidCustomUrl($customURL)) {
+ throw new UserInputException('customURL_' . $languageID, 'invalid');
+ }
+ else {
+ // check whether url is already in use
+ if (!PageEditor::isUniqueCustomUrl($customURL, $this->applicationPackageID)) {
+ throw new UserInputException('customURL_' . $languageID, 'notUnique');
+ }
+
+ foreach ($this->customURL as $languageID2 => $customURL2) {
+ if ($languageID != $languageID2 && $customURL = $customURL2) {
+ throw new UserInputException('customURL_' . $languageID, 'notUnique');
+ }
}
}
}
'metaKeywords' => $this->metaKeywords,
'boxIDs' => $this->boxIDs,
'availableApplications' => $this->availableApplications,
- 'availableLanguages' => LanguageFactory::getInstance()->getLanguages(),
+ 'availableLanguages' => $this->availableLanguages,
'availableBoxes' => $this->availableBoxes,
'pageNodeList' => (new PageNodeTree())->getNodeList()
]);
// type is immutable
}
+ /**
+ * @inheritDoc
+ */
+ protected function validateCustomUrl($languageID, $customURL) {
+ if ($this->pageType == 'system') {
+ if ($customURL != $this->page->controllerCustomURL) {
+ parent::validateCustomUrl($languageID, $customURL);
+ }
+ }
+ else {
+ if ($customURL != $this->page->getPageContent()[$languageID]) {
+ parent::validateCustomUrl($languageID, $customURL);
+ }
+ }
+ }
+
/**
* @inheritDoc
*/
namespace wcf\data\page;
use wcf\data\DatabaseObjectEditor;
use wcf\data\IEditableCachedObject;
+use wcf\data\package\PackageCache;
use wcf\system\cache\builder\PageCacheBuilder;
use wcf\system\cache\builder\RoutingCacheBuilder;
+use wcf\system\request\ControllerMap;
+use wcf\system\WCF;
+use wcf\util\FileUtil;
/**
* Provides functions to edit pages.
RoutingCacheBuilder::getInstance()->reset();
PageCacheBuilder::getInstance()->reset();
}
+
+ /**
+ * Returns true if given custom url is unique.
+ *
+ * @param string $customURL
+ * @param integer $packageID
+ *
+ * @return boolean
+ */
+ public static function isUniqueCustomUrl($customURL, $packageID = 1) {
+ // check controller
+ $package = PackageCache::getInstance()->getPackage($packageID);
+ $packageDir = FileUtil::addTrailingSlash(FileUtil::getRealPath(WCF_DIR.$package->packageDir));
+
+ $files = array_merge(glob($packageDir . 'lib/action/*.php'), glob($packageDir . 'lib/form/*.php'), glob($packageDir . 'lib/page/*.php'));
+ foreach ($files as $file) {
+ $filename = preg_replace('/(Action|Page|Form)(\.class)?\.php$/', '', basename($file));
+ if ($customURL == ControllerMap::transformController($filename)) {
+ return false;
+ }
+ }
+
+ // check custom controller urls
+ $sql = "SELECT COUNT(*) AS count
+ FROM wcf".WCF_N."_page
+ WHERE controllerCustomURL = ?
+ AND applicationPackageID = ?";
+ $statement = WCF::getDB()->prepareStatement($sql);
+ $statement->execute([$customURL, $packageID]);
+ if ($statement->fetchColumn()) {
+ return false;
+ }
+
+ // check custom urls
+ $sql = "SELECT COUNT(*) AS count
+ FROM wcf".WCF_N."_page_content
+ WHERE customURL = ?
+ AND pageID IN (
+ SELECT pageID
+ FROM wcf".WCF_N."_page
+ WHERE applicationPackageID = ?
+ )";
+ $statement = WCF::getDB()->prepareStatement($sql);
+ $statement->execute([$customURL, $packageID]);
+ if ($statement->fetchColumn()) {
+ return false;
+ }
+
+ return true;
+ }
}