<acpmenuitem name="wcf.acp.menu.link.community">
<showorder>5</showorder>
</acpmenuitem>
+
+ <!-- lantia -->
+ <acpmenuitem name="wcf.acp.menu.link.cms">
+ <parent>wcf.acp.menu.link.content</parent>
+ <showorder>1</showorder>
+ </acpmenuitem>
+
+ <acpmenuitem name="wcf.acp.menu.link.cms.page.list">
+ <controller><![CDATA[wcf\acp\page\PageListPage]]></controller>
+ <parent>wcf.acp.menu.link.cms</parent>
+ <permissions>admin.content.cms.canManagePage</permissions>
+ </acpmenuitem>
</import>
</data>
<admindefaultvalue>1</admindefaultvalue>
<usersonly>1</usersonly>
</option>
+
+ <option name="admin.content.cms.canManagePage">
+ <categoryname>admin.content</categoryname>
+ <optiontype>boolean</optiontype>
+ <defaultvalue>0</defaultvalue>
+ <admindefaultvalue>1</admindefaultvalue>
+ <usersonly>1</usersonly>
+ </option>
<!-- user.message -->
<option name="user.message.canUseSmilies">
--- /dev/null
+{include file='header' pageTitle='wcf.acp.page.'|concat:$action}
+
+<script data-relocate="true">
+ $(function() {
+ $('#isLandingPage').change(function(event) {
+ if ($('#isLandingPage')[0].checked) {
+ $('#isDisabled')[0].checked = false;
+ $('#isDisabled')[0].disabled = true;
+ }
+ else {
+ $('#isDisabled')[0].disabled = false;
+ }
+ }).trigger('change');
+
+ $('#isDisabled').change(function(event) {
+ if ($('#isDisabled')[0].checked) {
+ $('#isLandingPage')[0].checked = false;
+ $('#isLandingPage')[0].disabled = true;
+ }
+ else {
+ $('#isLandingPage')[0].disabled = false;
+ }
+ }).trigger('change');
+ });
+</script>
+
+<header class="boxHeadline">
+ <h1>{if $action == 'add'}{if $isMultilingual}{lang}wcf.acp.page.addMultilingual{/lang}{else}{lang}wcf.acp.page.add{/lang}{/if}{else}{lang}wcf.acp.page.edit{/lang}{/if}</h1>
+</header>
+
+{include file='formError'}
+
+{if $success|isset}
+ <p class="success">{lang}wcf.global.success.{$action}{/lang}</p>
+{/if}
+
+<div class="contentNavigation">
+ <nav>
+ <ul>
+ <li><a href="{link controller='PageList'}{/link}" class="button"><span class="icon icon16 icon-list"></span> <span>{lang}wcf.acp.menu.link.cms.page.list{/lang}</span></a></li>
+
+ {event name='contentNavigationButtons'}
+ </ul>
+ </nav>
+</div>
+
+<form method="post" action="{if $action == 'add'}{link controller='PageAdd'}{/link}{else}{link controller='PageEdit' id=$pageID}{/link}{/if}">
+ <div class="container containerPadding marginTop">
+ <fieldset>
+ <legend>{lang}wcf.global.form.data{/lang}</legend>
+
+ <dl{if $errorField == 'displayName'} class="formError"{/if}>
+ <dt><label for="displayName">{lang}wcf.global.name{/lang}</label></dt>
+ <dd>
+ <input type="text" id="displayName" name="displayName" value="{$displayName}" required="required" autofocus="autofocus" class="long" />
+ {if $errorField == 'displayName'}
+ <small class="innerError">
+ {if $errorType == 'empty'}
+ {lang}wcf.global.form.error.empty{/lang}
+ {else}
+ {lang}wcf.acp.page.displayName.error.{@$errorType}{/lang}
+ {/if}
+ </small>
+ {/if}
+ </dd>
+ </dl>
+
+ {if $action == 'add' || !$page->controller}
+ <dl{if $errorField == 'parentPageID'} class="formError"{/if}>
+ <dt><label for="parentPageID">{lang}wcf.acp.page.parentPageID{/lang}</label></dt>
+ <dd>
+ <select name="parentPageID" id="parentPageID">
+ <option value="0">{lang}wcf.acp.page.parentPageID.noParentPage{/lang}</option>
+
+ {foreach from=$pageNodeList item=pageNode}
+ <option value="{@$pageNode->getPage()->pageID}"{if $pageNode->getPage()->pageID == $parentPageID} selected="selected"{/if}>{if $pageNode->getDepth() > 1}{@" "|str_repeat:($pageNode->getDepth() - 1)}{/if}{$pageNode->getPage()->displayName}</option>
+ {/foreach}
+ </select>
+ {if $errorField == 'parentPageID'}
+ <small class="innerError">
+ {if $errorType == 'empty'}
+ {lang}wcf.global.form.error.empty{/lang}
+ {else}
+ {lang}wcf.acp.page.parentPageID.error.{@$errorType}{/lang}
+ {/if}
+ </small>
+ {/if}
+ </dd>
+ </dl>
+
+ <dl{if $errorField == 'packageID'} class="formError"{/if}>
+ <dt><label for="packageID">{lang}wcf.acp.page.packageID{/lang}</label></dt>
+ <dd>
+ <select name="packageID" id="packageID">
+ {foreach from=$availableApplications item=availableApplication}
+ <option value="{@$availableApplication->packageID}"{if $availableApplication->packageID == $packageID} selected="selected"{/if}>{$availableApplication->domainName}{$availableApplication->domainPath}</option>
+ {/foreach}
+ </select>
+ {if $errorField == 'parentPageID'}
+ <small class="innerError">
+ {if $errorType == 'empty'}
+ {lang}wcf.global.form.error.empty{/lang}
+ {else}
+ {lang}wcf.acp.page.packageID.error.{@$errorType}{/lang}
+ {/if}
+ </small>
+ {/if}
+ </dd>
+ </dl>
+ {/if}
+
+ {if !$isMultilingual}
+ <dl{if $errorField == 'customURL'} 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'}
+ <small class="innerError">
+ {if $errorType == 'empty'}
+ {lang}wcf.global.form.error.empty{/lang}
+ {else}
+ {lang}wcf.acp.page.customURL.error.{@$errorType}{/lang}
+ {/if}
+ </small>
+ {/if}
+ </dd>
+ </dl>
+ {/if}
+
+ <dl>
+ <dt></dt>
+ <dd>
+ <label><input type="checkbox" id="isLandingPage" name="isLandingPage" value="1" {if $isLandingPage}checked="checked" {/if}{if $action == 'edit' && $page->isLandingPage}disabled="disabled" {/if}/> {lang}wcf.acp.page.isLandingPage{/lang}</label>
+ </dd>
+ </dl>
+
+ <dl>
+ <dt></dt>
+ <dd>
+ <label><input type="checkbox" id="isDisabled" name="isDisabled" value="1" {if $isDisabled}checked="checked" {/if}/> {lang}wcf.acp.page.isDisabled{/lang}</label>
+ </dd>
+ </dl>
+
+ {event name='dataFields'}
+ </fieldset>
+
+ {if $action == 'add' || !$page->controller}
+ {if !$isMultilingual}
+ <fieldset>
+ <legend>content</legend>
+
+ <dl{if $errorField == 'title'} class="formError"{/if}>
+ <dt><label for="title">{lang}wcf.acp.page.title{/lang}</label></dt>
+ <dd>
+ <input type="text" id="title" name="title[0]" value="{if !$title[0]|empty}{$title[0]}{/if}" class="long" />
+ {if $errorField == 'title'}
+ <small class="innerError">
+ {if $errorType == 'empty'}
+ {lang}wcf.global.form.error.empty{/lang}
+ {else}
+ {lang}wcf.acp.page.title.error.{@$errorType}{/lang}
+ {/if}
+ </small>
+ {/if}
+ </dd>
+ </dl>
+
+ <dl{if $errorField == 'content'} class="formError"{/if}>
+ <dt><label for="content0">{lang}wcf.acp.page.content{/lang}</label></dt>
+ <dd>
+ <textarea name="content[0]" id="content0">{if !$content[0]|empty}{$content[0]}{/if}</textarea>
+ {if $errorField == 'content'}
+ <small class="innerError">
+ {if $errorType == 'empty'}
+ {lang}wcf.global.form.error.empty{/lang}
+ {else}
+ {lang}wcf.acp.page.content.error.{@$errorType}{/lang}
+ {/if}
+ </small>
+ {/if}
+ </dd>
+ </dl>
+
+ <dl{if $errorField == 'metaKeywords'} class="formError"{/if}>
+ <dt><label for="metaKeywords">{lang}wcf.acp.page.metaKeywords{/lang}</label></dt>
+ <dd>
+ <textarea name="metaKeywords[0]" id="metaKeywords">{if !$metaKeywords[0]|empty}{$metaKeywords[0]}{/if}</textarea>
+ {if $errorField == 'metaKeywords'}
+ <small class="innerError">
+ {if $errorType == 'empty'}
+ {lang}wcf.global.form.error.empty{/lang}
+ {else}
+ {lang}wcf.acp.page.metaKeywords.error.{@$errorType}{/lang}
+ {/if}
+ </small>
+ {/if}
+ </dd>
+ </dl>
+
+ <dl{if $errorField == 'metaDescription'} class="formError"{/if}>
+ <dt><label for="metaDescription">{lang}wcf.acp.page.metaDescription{/lang}</label></dt>
+ <dd>
+ <textarea name="metaDescription[0]" id="metaDescription">{if !$metaDescription[0]|empty}{$metaDescription[0]}{/if}</textarea>
+ {if $errorField == 'metaDescription'}
+ <small class="innerError">
+ {if $errorType == 'empty'}
+ {lang}wcf.global.form.error.empty{/lang}
+ {else}
+ {lang}wcf.acp.page.metaDescription.error.{@$errorType}{/lang}
+ {/if}
+ </small>
+ {/if}
+ </dd>
+ </dl>
+ </fieldset>
+ {else}
+ <div class="tabMenuContainer">
+ <nav class="tabMenu">
+ <ul>
+ {foreach from=$availableLanguages item=availableLanguage}
+ {assign var='containerID' value='language'|concat:$availableLanguage->languageID}
+ <li><a href="{@$__wcf->getAnchor($containerID)}">{$availableLanguage->languageName}</a></li>
+ {/foreach}
+ </ul>
+ </nav>
+
+ {foreach from=$availableLanguages item=availableLanguage}
+ <div id="language{@$availableLanguage->languageID}" class="container containerPadding tabMenuContent">
+ <fieldset>
+ <dl{if $errorField == 'customURL'} class="formError"{/if}>
+ <dt><label for="customURL{@$availableLanguage->languageID}">{lang}wcf.acp.page.customURL{/lang}</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'}
+ <small class="innerError">
+ {if $errorType == 'empty'}
+ {lang}wcf.global.form.error.empty{/lang}
+ {else}
+ {lang}wcf.acp.page.customURL.error.{@$errorType}{/lang}
+ {/if}
+ </small>
+ {/if}
+ </dd>
+ </dl>
+
+ <dl{if $errorField == 'title'} class="formError"{/if}>
+ <dt><label for="title{@$availableLanguage->languageID}">{lang}wcf.acp.page.title{/lang}</label></dt>
+ <dd>
+ <input type="text" id="title{@$availableLanguage->languageID}" name="title[{@$availableLanguage->languageID}]" value="{if !$title[$availableLanguage->languageID]|empty}{$title[$availableLanguage->languageID]}{/if}" class="long" />
+ {if $errorField == 'title'}
+ <small class="innerError">
+ {if $errorType == 'empty'}
+ {lang}wcf.global.form.error.empty{/lang}
+ {else}
+ {lang}wcf.acp.page.title.error.{@$errorType}{/lang}
+ {/if}
+ </small>
+ {/if}
+ </dd>
+ </dl>
+
+ <dl{if $errorField == 'content'} class="formError"{/if}>
+ <dt><label for="content{@$availableLanguage->languageID}">{lang}wcf.acp.page.content{/lang}</label></dt>
+ <dd>
+ <textarea name="content[{@$availableLanguage->languageID}]" id="content{@$availableLanguage->languageID}">{if !$content[$availableLanguage->languageID]|empty}{$content[$availableLanguage->languageID]}{/if}</textarea>
+ {if $errorField == 'content'}
+ <small class="innerError">
+ {if $errorType == 'empty'}
+ {lang}wcf.global.form.error.empty{/lang}
+ {else}
+ {lang}wcf.acp.page.content.error.{@$errorType}{/lang}
+ {/if}
+ </small>
+ {/if}
+ </dd>
+ </dl>
+
+ <dl{if $errorField == 'metaKeywords'} class="formError"{/if}>
+ <dt><label for="metaKeywords{@$availableLanguage->languageID}">{lang}wcf.acp.page.metaKeywords{/lang}</label></dt>
+ <dd>
+ <textarea name="metaKeywords[{@$availableLanguage->languageID}]" id="metaKeywords{@$availableLanguage->languageID}">{if !$metaKeywords[$availableLanguage->languageID]|empty}{$metaKeywords[$availableLanguage->languageID]}{/if}</textarea>
+ {if $errorField == 'metaKeywords'}
+ <small class="innerError">
+ {if $errorType == 'empty'}
+ {lang}wcf.global.form.error.empty{/lang}
+ {else}
+ {lang}wcf.acp.page.metaKeywords.error.{@$errorType}{/lang}
+ {/if}
+ </small>
+ {/if}
+ </dd>
+ </dl>
+
+ <dl{if $errorField == 'metaDescription'} class="formError"{/if}>
+ <dt><label for="metaDescription{@$availableLanguage->languageID}">{lang}wcf.acp.page.metaDescription{/lang}</label></dt>
+ <dd>
+ <textarea name="metaDescription[{@$availableLanguage->languageID}]" id="metaDescription{@$availableLanguage->languageID}">{if !$metaDescription[$availableLanguage->languageID]|empty}{$metaDescription[$availableLanguage->languageID]}{/if}</textarea>
+ {if $errorField == 'metaDescription'}
+ <small class="innerError">
+ {if $errorType == 'empty'}
+ {lang}wcf.global.form.error.empty{/lang}
+ {else}
+ {lang}wcf.acp.page.metaDescription.error.{@$errorType}{/lang}
+ {/if}
+ </small>
+ {/if}
+ </dd>
+ </dl>
+ </fieldset>
+ </div>
+ {/foreach}
+ </div>
+ {/if}
+ {/if}
+
+ {event name='fieldsets'}
+ </div>
+
+ <div class="formSubmit">
+ <input type="submit" value="{lang}wcf.global.button.submit{/lang}" accesskey="s" />
+ <input type="hidden" name="isMultilingual" value="{@$isMultilingual}" />
+ {@SECURITY_TOKEN_INPUT_TAG}
+ </div>
+</form>
+
+{include file='footer'}
--- /dev/null
+{include file='header' pageTitle='wcf.acp.page.list'}
+
+<script data-relocate="true">
+ //<![CDATA[
+ $(function() {
+ new WCF.Action.Delete('wcf\\data\\page\\PageAction', '.jsPageRow');
+ new WCF.Action.Toggle('wcf\\data\\page\\PageAction', '.jsPageRow');
+ });
+ //]]>
+</script>
+
+<header class="boxHeadline">
+ <h1>{lang}wcf.acp.page.list{/lang}</h1>
+</header>
+
+<div class="contentNavigation">
+ {pages print=true assign=pagesLinks controller="PageList" link="pageNo=%d&sortField=$sortField&sortOrder=$sortOrder"}
+
+ <nav>
+ <ul>
+ <li><a href="{link controller='PageAdd'}{/link}" class="button"><span class="icon icon16 icon-plus"></span> <span>{lang}wcf.acp.page.add{/lang}</span></a></li>
+ <li><a href="{link controller='PageAdd'}isMultilingual=1{/link}" class="button"><span class="icon icon16 icon-plus"></span> <span>{lang}wcf.acp.page.addMultilingual{/lang}</span></a></li>
+
+ {event name='contentNavigationButtonsTop'}
+ </ul>
+ </nav>
+</div>
+
+{if $objects|count}
+ <div class="tabularBox tabularBoxTitle marginTop">
+ <header>
+ <h2>{lang}wcf.acp.page.list{/lang} <span class="badge badgeInverse">{#$items}</span></h2>
+ </header>
+
+ <table class="table">
+ <thead>
+ <tr>
+ <th class="columnPageID{if $sortField == 'pageID'} active {@$sortOrder}{/if}" colspan="2"><a href="{link controller='PageList'}pageNo={@$pageNo}&sortField=pageID&sortOrder={if $sortField == 'pageID' && $sortOrder == 'ASC'}DESC{else}ASC{/if}{/link}">{lang}wcf.global.objectID{/lang}</a></th>
+ <th class="columnTitle columnName{if $sortField == 'displayName'} active {@$sortOrder}{/if}"><a href="{link controller='PageList'}pageNo={@$pageNo}&sortField=displayName&sortOrder={if $sortField == 'displayName' && $sortOrder == 'ASC'}DESC{else}ASC{/if}{/link}">{lang}wcf.global.name{/lang}</a></th>
+ <th class="columnText columnCustomURL{if $sortField == 'customURL'} active {@$sortOrder}{/if}"><a href="{link controller='PageList'}pageNo={@$pageNo}&sortField=customURL&sortOrder={if $sortField == 'customURL' && $sortOrder == 'ASC'}DESC{else}ASC{/if}{/link}">{lang}wcf.acp.page.customURL{/lang}</a></th>
+ <th class="columnDate columnLastUpdateTime{if $sortField == 'lastUpdateTime'} active {@$sortOrder}{/if}"><a href="{link controller='PageList'}pageNo={@$pageNo}&sortField=lastUpdateTime&sortOrder={if $sortField == 'lastUpdateTime' && $sortOrder == 'ASC'}DESC{else}ASC{/if}{/link}">{lang}wcf.acp.page.lastUpdateTime{/lang}</a></th>
+
+ {event name='columnHeads'}
+ </tr>
+ </thead>
+
+ <tbody>
+ {foreach from=$objects item=page}
+ <tr class="jsPageRow">
+ <td class="columnIcon">
+ {if $page->canDisable()}
+ <span class="icon icon16 icon-check{if $page->isDisabled}-empty{/if} jsToggleButton jsTooltip pointer" title="{lang}wcf.global.button.{if !$page->isDisabled}disable{else}enable{/if}{/lang}" data-object-id="{@$page->pageID}"></span>
+ {else}
+ <span class="icon icon16 icon-check{if $page->isDisabled}-empty{/if} disabled" title="{lang}wcf.global.button.{if !$page->isDisabled}disable{else}enable{/if}{/lang}"></span>
+ {/if}
+ <a href="{link controller='PageEdit' id=$page->pageID}{/link}" title="{lang}wcf.global.button.edit{/lang}" class="jsTooltip"><span class="icon icon16 icon-pencil"></span></a>
+ {if $page->canDelete()}
+ <span class="icon icon16 icon-remove jsDeleteButton jsTooltip pointer" title="{lang}wcf.global.button.delete{/lang}" data-object-id="{@$page->pageID}" data-confirm-message="{lang}wcf.acp.page.delete.confirmMessage{/lang}"></span>
+ {else}
+ <span class="icon icon16 icon-remove disabled" title="{lang}wcf.global.button.delete{/lang}"></span>
+ {/if}
+
+ {event name='rowButtons'}
+ </td>
+ <td class="columnID columnPageID">{@$page->pageID}</td>
+ <td class="columnTitle columnName"><a href="{link controller='PageEdit' id=$page->pageID}{/link}">{$page->displayName}</a></td>
+ <td class="columnText columnCustomURL">{$page->customURL}</td>
+ <td class="columnDate columnLastUpdateTime">{@$page->lastUpdateTime|time}</td>
+
+ {event name='columns'}
+ </tr>
+ {/foreach}
+ </tbody>
+ </table>
+ </div>
+
+ <div class="contentNavigation">
+ {@$pagesLinks}
+
+
+ <nav>
+ <ul>
+ <li><a href="{link controller='PageAdd'}{/link}" class="button"><span class="icon icon16 icon-plus"></span> <span>{lang}wcf.acp.page.add{/lang}</span></a></li>
+ <li><a href="{link controller='PageAdd'}isMultilingual=1{/link}" class="button"><span class="icon icon16 icon-plus"></span> <span>{lang}wcf.acp.page.addMultilingual{/lang}</span></a></li>
+
+ {event name='contentNavigationButtonsBottom'}
+ </ul>
+ </nav>
+ </div>
+{/if}
+
+{include file='footer'}
--- /dev/null
+<?php
+namespace wcf\acp\form;
+use wcf\data\application\ApplicationList;
+use wcf\data\page\PageAction;
+use wcf\data\page\PageEditor;
+use wcf\data\page\PageNodeTree;
+use wcf\data\page\Page;
+use wcf\form\AbstractForm;
+use wcf\system\exception\UserInputException;
+use wcf\system\language\LanguageFactory;
+use wcf\system\WCF;
+use wcf\util\ArrayUtil;
+use wcf\util\StringUtil;
+
+/**
+ * Shows the page add form.
+ *
+ * @author Marcel Werk
+ * @copyright 2001-2015 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.wcf
+ * @subpackage acp.form
+ * @category Community Framework
+ */
+class PageAddForm extends AbstractForm {
+ /**
+ * @see \wcf\page\AbstractPage::$activeMenuItem
+ */
+ public $activeMenuItem = 'wcf.acp.menu.link.cms.page.list';
+
+ /**
+ * @see \wcf\page\AbstractPage::$neededPermissions
+ */
+ public $neededPermissions = array('admin.content.cms.canManagePage');
+
+ /**
+ * true if created page is multi-lingual
+ * @var boolean
+ */
+ public $isMultilingual = 0;
+
+ /**
+ * parent page id
+ * @var integer
+ */
+ public $parentPageID = 0;
+
+ /**
+ * page's display name
+ * @var string
+ */
+ public $displayName = '';
+
+ /**
+ * true if page is disabled
+ * @var boolean
+ */
+ public $isDisabled = 0;
+
+ /**
+ * true if page is landing page
+ * @var boolean
+ */
+ public $isLandingPage = 0;
+
+ /**
+ * package id of the page
+ * @var integer
+ */
+ public $packageID = 1;
+
+ /**
+ * list of available applications (standalone packages)
+ * @var array<\wcf\data\application\Application>
+ */
+ public $availableApplications = array();
+
+ /**
+ * page custom URL
+ * @var array<string>
+ */
+ public $customURL = array();
+
+ /**
+ * page titles
+ * @var array<string>
+ */
+ public $title = array();
+
+ /**
+ * page contents
+ * @var array<string>
+ */
+ public $content = array();
+
+ /**
+ * page meta descriptions
+ * @var array<string>
+ */
+ public $metaDescription = array();
+
+ /**
+ * page meta keywords
+ * @var array<string>
+ */
+ public $metaKeywords = array();
+
+ /**
+ * @see \wcf\page\IPage::readParameters()
+ */
+ public function readParameters() {
+ parent::readParameters();
+
+ if (!empty($_REQUEST['isMultilingual'])) $this->isMultilingual = 1;
+
+ // get available applications
+ $applicationList = new ApplicationList();
+ $applicationList->readObjects();
+ $this->availableApplications = $applicationList->getObjects();
+ }
+
+ /**
+ * @see \wcf\form\IForm::readFormParameters()
+ */
+ public function readFormParameters() {
+ parent::readFormParameters();
+
+ if (isset($_POST['parentPageID'])) $this->parentPageID = intval($_POST['parentPageID']);
+ if (isset($_POST['displayName'])) $this->displayName = StringUtil::trim($_POST['displayName']);
+ if (isset($_POST['isDisabled'])) $this->isDisabled = 1;
+ if (isset($_POST['isLandingPage'])) $this->isLandingPage = 1;
+ if (isset($_POST['packageID'])) $this->packageID = intval($_POST['packageID']);
+
+ if (isset($_POST['customURL']) && is_array($_POST['customURL'])) $this->customURL = ArrayUtil::trim($_POST['customURL']);
+ if (isset($_POST['title']) && is_array($_POST['title'])) $this->title = ArrayUtil::trim($_POST['title']);
+ if (isset($_POST['content']) && is_array($_POST['content'])) $this->content = ArrayUtil::trim($_POST['content']);
+ if (isset($_POST['metaDescription']) && is_array($_POST['metaDescription'])) $this->metaDescription = ArrayUtil::trim($_POST['metaDescription']);
+ if (isset($_POST['metaKeywords']) && is_array($_POST['metaKeywords'])) $this->metaKeywords = ArrayUtil::trim($_POST['metaKeywords']);
+ }
+
+ /**
+ * @see \wcf\form\IForm::validate()
+ */
+ public function validate() {
+ parent::validate();
+
+ $this->validateDisplayName();
+
+ $this->validateParentPageID();
+
+ $this->validatePackageID();
+ }
+
+ protected function validateDisplayName() {
+ if (empty($this->displayName)) {
+ throw new UserInputException('displayName');
+ }
+ if (Page::getPageByDisplayName($this->displayName)) {
+ throw new UserInputException('displayName', 'notUnique');
+ }
+ }
+
+ protected function validateParentPageID() {
+ if ($this->parentPageID) {
+ $page = new Page($this->parentPageID);
+ if (!$page->pageID) {
+ throw new UserInputException('parentPageID', 'invalid');
+ }
+ }
+ }
+
+ protected function validatePackageID() {
+ if (!isset($this->availableApplications[$this->packageID])) {
+ throw new UserInputException('packageID', 'invalid');
+ }
+ }
+
+ /**
+ * @see \wcf\form\IForm::save()
+ */
+ public function save() {
+ parent::save();
+
+ $content = array();
+ if ($this->isMultilingual) {
+ foreach (LanguageFactory::getInstance()->getLanguages() as $language) {
+ $content[$language->languageID] = array(
+ 'customURL' => (!empty($_POST['customURL'][$language->languageID]) ? $_POST['customURL'][$language->languageID] : ''),
+ 'title' => (!empty($_POST['title'][$language->languageID]) ? $_POST['title'][$language->languageID] : ''),
+ 'content' => (!empty($_POST['content'][$language->languageID]) ? $_POST['content'][$language->languageID] : ''),
+ 'metaDescription' => (!empty($_POST['metaDescription'][$language->languageID]) ? $_POST['metaDescription'][$language->languageID] : ''),
+ 'metaKeywords' => (!empty($_POST['metaKeywords'][$language->languageID]) ? $_POST['metaKeywords'][$language->languageID] : '')
+ );
+ }
+ }
+ else {
+ $content[0] = array(
+ 'customURL' => (!empty($_POST['customURL'][0]) ? $_POST['customURL'][0] : ''),
+ 'title' => (!empty($_POST['title'][0]) ? $_POST['title'][0] : ''),
+ 'content' => (!empty($_POST['content'][0]) ? $_POST['content'][0] : ''),
+ 'metaDescription' => (!empty($_POST['metaDescription'][0]) ? $_POST['metaDescription'][0] : ''),
+ 'metaKeywords' => (!empty($_POST['metaKeywords'][0]) ? $_POST['metaKeywords'][0] : '')
+ );
+ }
+
+ $this->objectAction = new PageAction(array(), 'create', array('data' => array_merge($this->additionalFields, array(
+ 'parentPageID' => ($this->parentPageID ?: null),
+ 'displayName' => $this->displayName,
+ 'isDisabled' => ($this->isDisabled) ? 1 : 0,
+ 'isLandingPage' => ($this->isLandingPage) ? 1 : 0,
+ 'packageID' => ($this->packageID ?: null),
+ 'lastUpdateTime' => TIME_NOW,
+ 'isMultilingual' => $this->isMultilingual,
+ 'name' => ''
+ )), 'content' => $content));
+ $returnValues = $this->objectAction->executeAction();
+ // set generic page name
+ $pageEditor = new PageEditor($returnValues['returnValues']);
+ $pageEditor->update(array(
+ 'name' => 'com.woltlab.wcf.generic'.$pageEditor->pageID
+ ));
+
+ // call saved event
+ $this->saved();
+
+ // show success
+ WCF::getTPL()->assign('success', true);
+
+ // reset variables
+ $this->parentPageID = $this->isDisabled = $this->isLandingPage = 0;
+ $this->packageID = 1;
+ $this->displayName = '';
+ $this->customURL = $this->title = $this->content = $this->metaDescription = $this->metaKeywords = array();
+ }
+
+ /**
+ * @see \wcf\page\IPage::assignVariables()
+ */
+ public function assignVariables() {
+ parent::assignVariables();
+
+ $pageNodeList = new PageNodeTree();
+
+ WCF::getTPL()->assign(array(
+ 'action' => 'add',
+ 'parentPageID' => $this->parentPageID,
+ 'displayName' => $this->displayName,
+ 'isDisabled' => $this->isDisabled,
+ 'isLandingPage' => $this->isLandingPage,
+ 'isMultilingual' => $this->isMultilingual,
+ 'packageID' => $this->packageID,
+ 'customURL' => $this->customURL,
+ 'title' => $this->title,
+ 'content' => $this->content,
+ 'metaDescription' => $this->metaDescription,
+ 'metaKeywords' => $this->metaKeywords,
+ 'availableApplications' => $this->availableApplications,
+ 'availableLanguages' => LanguageFactory::getInstance()->getLanguages(),
+ 'pageNodeList' => $pageNodeList->getNodeList()
+ ));
+ }
+}
--- /dev/null
+<?php
+namespace wcf\acp\form;
+use wcf\data\page\PageAction;
+use wcf\data\page\Page;
+use wcf\form\AbstractForm;
+use wcf\system\exception\IllegalLinkException;
+use wcf\system\exception\UserInputException;
+use wcf\system\language\LanguageFactory;
+use wcf\system\WCF;
+
+/**
+ * Shows the page add form.
+ *
+ * @author Marcel Werk
+ * @copyright 2001-2015 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.wcf
+ * @subpackage acp.form
+ * @category Community Framework
+ */
+class PageEditForm extends PageAddForm {
+ /**
+ * page id
+ * @var integer
+ */
+ public $pageID = 0;
+
+ /**
+ * page object
+ * @var \wcf\data\page\Page
+ */
+ public $page = null;
+
+ /**
+ * @see \wcf\page\IPage::readParameters()
+ */
+ public function readParameters() {
+ parent::readParameters();
+
+ if (isset($_REQUEST['id'])) $this->pageID = intval($_REQUEST['id']);
+ $this->page = new Page($this->pageID);
+ if (!$this->page->pageID) {
+ throw new IllegalLinkException();
+ }
+ if ($this->page->isMultilingual) $this->isMultilingual = 1;
+ }
+
+ /**
+ * @see \wcf\acp\form\PageAddForm::validateDisplayName()
+ */
+ protected function validateDisplayName() {
+ if ($this->displayName != $this->page->displayName) {
+ parent::validateDisplayName();
+ }
+ }
+
+ /**
+ * @see \wcf\acp\form\PageAddForm::validateParentPageID()
+ */
+ protected function validateParentPageID() {
+ if (!$this->page->controller && $this->parentPageID) {
+ $page = new Page($this->parentPageID);
+ if (!$page->pageID) {
+ throw new UserInputException('parentPageID', 'invalid');
+ }
+ }
+ }
+
+ /**
+ * @see \wcf\acp\form\PageAddForm::validatePackageID()
+ */
+ protected function validatePackageID() {
+ if (!$this->page->controller) {
+ parent::validatePackageID();
+ }
+ }
+
+ /**
+ * @see \wcf\form\IForm::save()
+ */
+ public function save() {
+ AbstractForm::save();
+
+ if ($this->page->controller) {
+ $this->objectAction = new PageAction(array($this->page), 'update', array('data' => array_merge($this->additionalFields, array(
+ 'displayName' => $this->displayName,
+ 'isDisabled' => ($this->isDisabled) ? 1 : 0,
+ 'isLandingPage' => ($this->isLandingPage) ? 1 : 0,
+ 'controllerCustomURL' => (!empty($_POST['customURL'][0]) ? $_POST['customURL'][0] : ''),
+ 'lastUpdateTime' => TIME_NOW
+ ))));
+ $this->objectAction->executeAction();
+ }
+ else {
+ $content = array();
+ if ($this->isMultilingual) {
+ foreach (LanguageFactory::getInstance()->getLanguages() as $language) {
+ $content[$language->languageID] = array(
+ 'customURL' => (!empty($_POST['customURL'][$language->languageID]) ? $_POST['customURL'][$language->languageID] : ''),
+ 'title' => (!empty($_POST['title'][$language->languageID]) ? $_POST['title'][$language->languageID] : ''),
+ 'content' => (!empty($_POST['content'][$language->languageID]) ? $_POST['content'][$language->languageID] : ''),
+ 'metaDescription' => (!empty($_POST['metaDescription'][$language->languageID]) ? $_POST['metaDescription'][$language->languageID] : ''),
+ 'metaKeywords' => (!empty($_POST['metaKeywords'][$language->languageID]) ? $_POST['metaKeywords'][$language->languageID] : '')
+ );
+ }
+ }
+ else {
+ $content[0] = array(
+ 'customURL' => (!empty($_POST['customURL'][0]) ? $_POST['customURL'][0] : ''),
+ 'title' => (!empty($_POST['title'][0]) ? $_POST['title'][0] : ''),
+ 'content' => (!empty($_POST['content'][0]) ? $_POST['content'][0] : ''),
+ 'metaDescription' => (!empty($_POST['metaDescription'][0]) ? $_POST['metaDescription'][0] : ''),
+ 'metaKeywords' => (!empty($_POST['metaKeywords'][0]) ? $_POST['metaKeywords'][0] : '')
+ );
+ }
+
+ $this->objectAction = new PageAction(array($this->page), 'update', array('data' => array_merge($this->additionalFields, array(
+ 'parentPageID' => ($this->parentPageID ?: null),
+ 'displayName' => $this->displayName,
+ 'isDisabled' => ($this->isDisabled) ? 1 : 0,
+ 'isLandingPage' => ($this->isLandingPage) ? 1 : 0,
+ 'packageID' => ($this->packageID ?: null),
+ 'lastUpdateTime' => TIME_NOW,
+ 'isMultilingual' => $this->isMultilingual
+ )), 'content' => $content));
+ $this->objectAction->executeAction();
+ }
+
+ // call saved event
+ $this->saved();
+
+ // show success
+ WCF::getTPL()->assign('success', true);
+ }
+
+ /**
+ * @see \wcf\page\IPage::readData()
+ */
+ public function readData() {
+ parent::readData();
+
+ if (empty($_POST)) {
+ $this->displayName = $this->page->displayName;
+ $this->parentPageID = $this->page->parentPageID;
+ $this->packageID = $this->page->packageID;
+ if ($this->page->isLandingPage) $this->isLandingPage = 1;
+ if ($this->page->isDiabled) $this->isDisabled = 1;
+
+ foreach ($this->page->getPageContent() as $languageID => $content) {
+ $this->title[$languageID] = $content['title'];
+ $this->content[$languageID] = $content['content'];
+ $this->metaDescription[$languageID] = $content['metaDescription'];
+ $this->metaKeywords[$languageID] = $content['metaKeywords'];
+ $this->customURL[$languageID] = $content['customURL'];
+ }
+ }
+ }
+
+ /**
+ * @see \wcf\page\IPage::assignVariables()
+ */
+ public function assignVariables() {
+ parent::assignVariables();
+
+ WCF::getTPL()->assign(array(
+ 'action' => 'edit',
+ 'pageID' => $this->pageID,
+ 'page' => $this->page
+ ));
+ }
+}
--- /dev/null
+<?php
+namespace wcf\acp\page;
+use wcf\page\SortablePage;
+
+/**
+ * Shows a list of pages.
+ *
+ * @author Marcel Werk
+ * @copyright 2001-2015 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.wcf
+ * @subpackage acp.page
+ * @category Community Framework
+ */
+class PageListPage extends SortablePage {
+ /**
+ * @see \wcf\page\AbstractPage::$activeMenuItem
+ */
+ public $activeMenuItem = 'wcf.acp.menu.link.cms.page.list';
+
+ /**
+ * @see \wcf\page\MultipleLinkPage::$objectListClassName
+ */
+ public $objectListClassName = 'wcf\data\page\PageList';
+
+ /**
+ * @see \wcf\page\AbstractPage::$neededPermissions
+ */
+ public $neededPermissions = array('admin.content.cms.canManagePage');
+
+ /**
+ * @see \wcf\page\SortablePage::$defaultSortField
+ */
+ public $defaultSortField = 'displayName';
+
+ /**
+ * @see \wcf\page\SortablePage::$validSortFields
+ */
+ public $validSortFields = array('pageID', 'displayName', 'customURL', 'lastUpdateTime');
+}
--- /dev/null
+<?php
+namespace wcf\data\page;
+use wcf\data\DatabaseObject;
+use wcf\system\WCF;
+
+/**
+ * Represents a page.
+ *
+ * @author Marcel Werk
+ * @copyright 2001-2015 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.wcf
+ * @subpackage data.page
+ * @category Community Framework
+ */
+class Page extends DatabaseObject {
+ /**
+ * @see \wcf\data\DatabaseObject::$databaseTableName
+ */
+ protected static $databaseTableName = 'page';
+
+ /**
+ * @see \wcf\data\DatabaseObject::$databaseTableIndexName
+ */
+ protected static $databaseTableIndexName = 'pageID';
+
+ /**
+ * Returns true if the active user can delete this page.
+ *
+ * @return boolean
+ */
+ public function canDelete() {
+ if (WCF::getSession()->getPermission('admin.content.cms.canManagePage') && !$this->originIsSystem && !$this->isLandingPage) {
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Returns true if the active user can disable this page.
+ *
+ * @return boolean
+ */
+ public function canDisable() {
+ if (WCF::getSession()->getPermission('admin.content.cms.canManagePage') && !$this->originIsSystem && !$this->isLandingPage) {
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Returns the page content.
+ *
+ * @return array
+ */
+ public function getPageContent() {
+ $content = array();
+ $sql = "SELECT *
+ FROM wcf".WCF_N."_page_content
+ WHERE pageID = ?";
+ $statement = WCF::getDB()->prepareStatement($sql);
+ $statement->execute(array($this->pageID));
+ while ($row = $statement->fetchArray()) {
+ $content[($row['languageID'] ?: 0)] = array(
+ 'title' => $row['title'],
+ 'content' => $row['content'],
+ 'metaDescription' => $row['metaDescription'],
+ 'metaKeywords' => $row['metaKeywords'],
+ 'customURL' => $row['customURL']
+ );
+ }
+
+ return $content;
+ }
+
+ /**
+ * Returns the page with the given display name.
+ *
+ * @param string $name
+ * @return \wcf\data\page\Page
+ */
+ public static function getPageByDisplayName($name) {
+ $sql = "SELECT *
+ FROM wcf".WCF_N."_page
+ WHERE displayName = ?";
+ $statement = WCF::getDB()->prepareStatement($sql);
+ $statement->execute(array($name));
+ $row = $statement->fetchArray();
+ if ($row !== false) return new Page(null, $row);
+
+ return null;
+ }
+}
--- /dev/null
+<?php
+namespace wcf\data\page;
+use wcf\data\AbstractDatabaseObjectAction;
+use wcf\data\IToggleAction;
+use wcf\system\exception\PermissionDeniedException;
+use wcf\system\WCF;
+
+/**
+ * Executes page related actions.
+ *
+ * @author Marcel Werk
+ * @copyright 2001-2015 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.wcf
+ * @subpackage data.page
+ * @category Community Framework
+ */
+class PageAction extends AbstractDatabaseObjectAction implements IToggleAction {
+ /**
+ * @see \wcf\data\AbstractDatabaseObjectAction::$className
+ */
+ protected $className = 'wcf\data\page\PageEditor';
+
+ /**
+ * @see \wcf\data\AbstractDatabaseObjectAction::$permissionsCreate
+ */
+ protected $permissionsCreate = array('admin.content.cms.canManagePage');
+
+ /**
+ * @see \wcf\data\AbstractDatabaseObjectAction::$permissionsDelete
+ */
+ protected $permissionsDelete = array('admin.content.cms.canManagePage');
+
+ /**
+ * @see \wcf\data\AbstractDatabaseObjectAction::$permissionsUpdate
+ */
+ protected $permissionsUpdate = array('admin.content.cms.canManagePage');
+
+ /**
+ * @see \wcf\data\AbstractDatabaseObjectAction::$requireACP
+ */
+ protected $requireACP = array('create', 'delete', 'toggle', 'update');
+
+ /**
+ * @see \wcf\data\AbstractDatabaseObjectAction::create()
+ */
+ public function create() {
+ $page = parent::create();
+
+ // save page content
+ if (!empty($this->parameters['content'])) {
+ $sql = "INSERT INTO wcf".WCF_N."_page_content
+ (pageID, languageID, title, content, metaDescription, metaKeywords, customURL)
+ VALUES (?, ?, ?, ?, ?, ?, ?)";
+ $statement = WCF::getDB()->prepareStatement($sql);
+
+ foreach ($this->parameters['content'] as $languageID => $content) {
+ $statement->execute(array(
+ $page->pageID,
+ ($languageID ?: null),
+ $content['title'],
+ $content['content'],
+ $content['metaDescription'],
+ $content['metaKeywords'],
+ $content['customURL']
+ ));
+ }
+ }
+
+ return $page;
+ }
+
+ /**
+ * @see \wcf\data\AbstractDatabaseObjectAction::update()
+ */
+ public function update() {
+ parent::update();
+
+ // update page content
+ if (!empty($this->parameters['content'])) {
+ $sql = "DELETE FROM wcf".WCF_N."_page_content
+ WHERE pageID = ?";
+ $deleteStatement = WCF::getDB()->prepareStatement($sql);
+
+ $sql = "INSERT INTO wcf".WCF_N."_page_content
+ (pageID, languageID, title, content, metaDescription, metaKeywords, customURL)
+ VALUES (?, ?, ?, ?, ?, ?, ?)";
+ $insertStatement = WCF::getDB()->prepareStatement($sql);
+
+ foreach ($this->objects as $page) {
+ $deleteStatement->execute(array($page->pageID));
+
+ foreach ($this->parameters['content'] as $languageID => $content) {
+ $insertStatement->execute(array(
+ $page->pageID,
+ ($languageID ?: null),
+ $content['title'],
+ $content['content'],
+ $content['metaDescription'],
+ $content['metaKeywords'],
+ $content['customURL']
+ ));
+ }
+ }
+ }
+
+ return $page;
+ }
+
+ /**
+ * @see \wcf\data\AbstractDatabaseObjectAction::validateDelete()
+ */
+ public function validateDelete() {
+ parent::validateDelete();
+
+ foreach ($this->objects as $object) {
+ if (!$object->canDelete()) {
+ throw new PermissionDeniedException();
+ }
+ }
+ }
+
+ /**
+ * @see \wcf\data\IToggleAction::validateToggle()
+ */
+ public function validateToggle() {
+ parent::validateUpdate();
+
+ foreach ($this->objects as $object) {
+ if (!$object->canDisable()) {
+ throw new PermissionDeniedException();
+ }
+ }
+ }
+
+ /**
+ * @see \wcf\data\IToggleAction::toggle()
+ */
+ public function toggle() {
+ foreach ($this->objects as $object) {
+ $object->update(array('isDisabled' => ($object->isDisabled) ? 0 : 1));
+ }
+ }
+}
--- /dev/null
+<?php
+namespace wcf\data\page;
+use wcf\data\DatabaseObjectEditor;
+
+/**
+ * Provides functions to edit pages.
+ *
+ * @author Marcel Werk
+ * @copyright 2001-2015 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.wcf
+ * @subpackage data.page
+ * @category Community Framework
+ */
+class PageEditor extends DatabaseObjectEditor {
+ /**
+ * @see \wcf\data\DatabaseObjectDecorator::$baseClass
+ */
+ protected static $baseClass = 'wcf\data\page\Page';
+}
--- /dev/null
+<?php
+namespace wcf\data\page;
+use wcf\data\DatabaseObjectList;
+
+/**
+ * Represents a list of pages.
+ *
+ * @author Marcel Werk
+ * @copyright 2001-2015 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.wcf
+ * @subpackage data.page
+ * @category Community Framework
+ */
+class PageList extends DatabaseObjectList {
+ /**
+ * @see \wcf\data\DatabaseObjectList::$className
+ */
+ public $className = 'wcf\data\page\Page';
+}
--- /dev/null
+<?php
+namespace wcf\data\page;
+
+/**
+ * Represents a page node element.
+ *
+ * @author Marcel Werk
+ * @copyright 2001-2015 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.wcf
+ * @subpackage data.page
+ * @category Community Framework
+ */
+class PageNode implements \Countable, \RecursiveIterator {
+ /**
+ * parent node
+ * @var \wcf\data\page\PageNode
+ */
+ protected $parentNode = null;
+
+ /**
+ * children of this node
+ * @var array<\wcf\data\page\PageNode>
+ */
+ protected $children = array();
+
+ /**
+ * page object
+ * @var \wcf\data\page\Page
+ */
+ protected $page = null;
+
+ /**
+ * node depth
+ * @var integer
+ */
+ protected $depth = 0;
+
+ /**
+ * iterator position
+ * @var integer
+ */
+ private $position = 0;
+
+ /**
+ * Creates a new PageNode object.
+ *
+ * @param \wcf\data\page\PageNode $parentNode
+ * @param \wcf\data\page\Page $page
+ * @param integer $depth
+ */
+ public function __construct($parentNode = null, Page $page = null, $depth = 0) {
+ $this->parentNode = $parentNode;
+ $this->page = $page;
+ $this->depth = $depth;
+ }
+
+ /**
+ * Sets the children of this node.
+ *
+ * @param array<\wcf\data\page\PageNode> $children
+ */
+ public function setChildren(array $children) {
+ $this->children = $children;
+ }
+
+ /**
+ * Returns the parent node
+ *
+ * @return \wcf\data\page\PageNode
+ */
+ public function getParentNode() {
+ return $this->parentNode;
+ }
+
+ /**
+ * Returns the page object of this node
+ *
+ * @return \wcf\data\page\Page
+ */
+ public function getPage() {
+ return $this->page;
+ }
+
+ /**
+ * Returns the number of children.
+ *
+ * @return integer
+ */
+ public function count() {
+ return count($this->children);
+ }
+
+ /**
+ * @see \Iterator::rewind()
+ */
+ public function rewind() {
+ $this->position = 0;
+ }
+
+ /**
+ * @see \Iterator::valid()
+ */
+ public function valid() {
+ return isset($this->children[$this->position]);
+ }
+
+ /**
+ * @see \Iterator::next()
+ */
+ public function next() {
+ $this->position++;
+ }
+
+ /**
+ * @see \Iterator::current()
+ */
+ public function current() {
+ return $this->children[$this->position];
+ }
+
+ /**
+ * @see \Iterator::key()
+ */
+ public function key() {
+ return $this->position;
+ }
+
+ /**
+ * @see \RecursiveIterator::getChildren()
+ */
+ public function getChildren() {
+ return $this->children[$this->position];
+ }
+
+ /**
+ * @see \RecursiveIterator::hasChildren()
+ */
+ public function hasChildren() {
+ return count($this->children) > 0;
+ }
+
+ /**
+ * Returns node depth.
+ *
+ * @return integer
+ */
+ public function getDepth() {
+ return $this->depth;
+ }
+}
--- /dev/null
+<?php
+namespace wcf\data\page;
+
+/**
+ * Represents a page node tree.
+ *
+ * @author Marcel Werk
+ * @copyright 2001-2015 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.wcf
+ * @subpackage data.page
+ * @category Community Framework
+ */
+class PageNodeTree {
+ /**
+ * parent page id
+ * @var integer
+ */
+ public $parentID = null;
+
+ /**
+ * start depth
+ * @var integer
+ */
+ public $startDepth = 0;
+
+ /**
+ * list of pages
+ * @var array<\wcf\data\page\Page>
+ */
+ public $pages = array();
+
+ /**
+ * page structure
+ * @var array<array>
+ */
+ public $pageStructure = array();
+
+ /**
+ * root node
+ * @var \wcf\data\page\PageNode
+ */
+ public $node = null;
+
+ /**
+ * Creates a new PageNodeTree object.
+ *
+ * @param integer $parentID
+ * @param integer $startDepth
+ */
+ public function __construct($parentID = null, $startDepth = 0) {
+ $this->parentID = $parentID;
+ $this->startDepth = $startDepth;
+
+ // load pages
+ $pageList = new PageList();
+ $pageList->sqlOrderBy = "page.displayName";
+ $pageList->readObjects();
+
+ foreach ($pageList as $page) {
+ $this->pages[$page->pageID] = $page;
+
+ if (!isset($this->pageStructure[$page->parentPageID])) {
+ $this->pageStructure[$page->parentPageID] = array();
+ }
+ $this->pageStructure[$page->parentPageID][] = $page->pageID;
+ }
+
+ // generate node tree
+ $this->node = new PageNode(null, null, $startDepth);
+ $this->node->setChildren($this->generateNodeTree($parentID, $this->node));
+ }
+
+ /**
+ * Generates the node tree recursively
+ *
+ * @param integer $parentID
+ * @param \wcf\data\page\PageNode $parentNode
+ * @param array<integer> $filter
+ * @return array<\wcf\data\page\PageNode>
+ */
+ protected function generateNodeTree($parentID, PageNode $parentNode = null) {
+ $nodes = array();
+
+ $pageIDs = (isset($this->pageStructure[$parentID]) ? $this->pageStructure[$parentID] : array());
+ foreach ($pageIDs as $pageID) {
+ $page = $this->pages[$pageID];
+ $node = new PageNode($parentNode, $page, ($parentNode !== null ? ($parentNode->getDepth() + 1) : 0));
+ $nodes[] = $node;
+
+ // get children
+ $node->setChildren($this->generateNodeTree($pageID, $node));
+ }
+
+ return $nodes;
+ }
+
+ /**
+ * Returns the page node tree.
+ *
+ * @return array<\wcf\data\page\PageNode>
+ */
+ public function getNodeTree() {
+ return $this->node->getChildren();
+ }
+
+ /**
+ * Returns the iteratable node list
+ *
+ * @return \RecursiveIteratorIterator
+ */
+ public function getNodeList() {
+ return new \RecursiveIteratorIterator($this->node, \RecursiveIteratorIterator::SELF_FIRST);
+ }
+}
UNIQUE KEY packageUpdateID (packageUpdateID, packageVersion)
);
+DROP TABLE IF EXISTS wcf1_page;
+CREATE TABLE wcf1_page (
+ pageID INT(10) NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ parentPageID INT(10),
+ name VARCHAR(255) NOT NULL,
+ displayName VARCHAR(255) NOT NULL,
+ isDisabled TINYINT(1) NOT NULL DEFAULT 0,
+ isLandingPage TINYINT(1) NOT NULL DEFAULT 0,
+ isMultilingual TINYINT(1) NOT NULL DEFAULT 0,
+ originIsSystem TINYINT(1) NOT NULL DEFAULT 0,
+ packageID INT(10) NOT NULL,
+ controller VARCHAR(255) NOT NULL DEFAULT '',
+ controllerCustomURL VARCHAR(255) NOT NULL DEFAULT '',
+ lastUpdateTime INT(10) NOT NULL DEFAULT 0
+);
+
+DROP TABLE IF EXISTS wcf1_page_content;
+CREATE TABLE wcf1_page_content (
+ pageID INT(10) NOT NULL,
+ languageID INT(10),
+ title VARCHAR(255) NOT NULL,
+ content MEDIUMTEXT,
+ metaDescription TEXT,
+ metaKeywords TEXT,
+ customURL VARCHAR(255) NOT NULL,
+
+ KEY (pageID, languageID)
+);
+
DROP TABLE IF EXISTS wcf1_page_menu_item;
CREATE TABLE wcf1_page_menu_item (
menuItemID INT(10) NOT NULL AUTO_INCREMENT PRIMARY KEY,
ALTER TABLE wcf1_paid_subscription_transaction_log ADD FOREIGN KEY (subscriptionID) REFERENCES wcf1_paid_subscription (subscriptionID) ON DELETE SET NULL;
ALTER TABLE wcf1_paid_subscription_transaction_log ADD FOREIGN KEY (paymentMethodObjectTypeID) REFERENCES wcf1_object_type (objectTypeID) ON DELETE CASCADE;
+ALTER TABLE wcf1_page ADD FOREIGN KEY (parentPageID) REFERENCES wcf1_page (pageID) ON DELETE SET NULL;
+ALTER TABLE wcf1_page ADD FOREIGN KEY (packageID) REFERENCES wcf1_package (packageID) ON DELETE CASCADE;
+
+ALTER TABLE wcf1_page_content ADD FOREIGN KEY (pageID) REFERENCES wcf1_page (pageID) ON DELETE CASCADE;
+ALTER TABLE wcf1_page_content ADD FOREIGN KEY (languageID) REFERENCES wcf1_language (languageID) ON DELETE CASCADE;
+
ALTER TABLE wcf1_page_menu_item ADD FOREIGN KEY (packageID) REFERENCES wcf1_package (packageID) ON DELETE CASCADE;
ALTER TABLE wcf1_search ADD FOREIGN KEY (userID) REFERENCES wcf1_user (userID) ON DELETE CASCADE;