--- /dev/null
+<?php
+namespace wcf\data\sitemap;
+use wcf\data\DatabaseObject;
+use wcf\system\exception\SystemException;
+use wcf\util\ClassUtil;
+
+/**
+ * Represents a sitemap entry.
+ *
+ * @author Alexander Ebert
+ * @copyright 2001-2012 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.wcf
+ * @subpackage data.sitemap
+ * @category Community Framework
+ */
+class Sitemap extends DatabaseObject {
+ /**
+ * ISitemapProvider object
+ * @var wcf\system\sitemap\ISitemapProvider
+ */
+ protected $sitemapObj = null;
+
+ /**
+ * @see wcf\data\DatabaseObject::$databaseTableIndexName
+ */
+ protected static $databaseTableIndexName = 'sitemapID';
+
+ /**
+ * Returns parsed template for current sitemap.
+ *
+ * @return string
+ */
+ public function getTemplate() {
+ if ($this->sitemapObj === null) {
+ if (empty($this->className) || !class_exists($this->className)) {
+ throw new SystemException("Unable to find class '".$this->className."' for sitemap '".$this->sitemapName."'");
+ }
+
+ if (!ClassUtil::isInstanceOf($this->className, 'wcf\system\sitemap\ISitemapProvider')) {
+ throw new SystemException("Class '".$this->className."' does not implement the interface 'wcf\system\sitemap\ISitemapProvider'");
+ }
+
+ $this->sitemapObj = new $this->className();
+ }
+
+ return $this->sitemapObj->getTemplate();
+ }
+}
--- /dev/null
+<?php
+namespace wcf\data\sitemap;
+use wcf\data\AbstractDatabaseObjectAction;
+use wcf\system\exception\SystemException;
+use wcf\system\sitemap\SitemapHandler;
+use wcf\system\WCF;
+
+/**
+ * Executes sitemap-related actions.
+ *
+ * @author Alexander Ebert
+ * @copyright 2001-2012 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.wcf
+ * @subpackage data.sitemap
+ * @category Community Framework
+ */
+class SitemapAction extends AbstractDatabaseObjectAction {
+ /**
+ * @see wcf\data\AbstractDatabaseObjectAction::$allowGuestAccess
+ */
+ protected $allowGuestAccess = array('getSitemap');
+
+ /**
+ * Does nothing.
+ */
+ public function validateGetSitemap() {
+ if (isset($this->parameters['sitemapName'])) {
+ SitemapHandler::getInstance()->validateSitemapName($this->parameters['sitemapName']);
+ }
+ }
+
+ /**
+ * Returns sitemap for active application group.
+ *
+ * @return array
+ */
+ public function getSitemap() {
+ if (isset($this->parameters['sitemapName'])) {
+ return array(
+ 'template' => SitemapHandler::getInstance()->getSitemap($this->parameters['sitemapName'])
+ );
+ }
+ else {
+ WCF::getTPL()->assign(array(
+ 'tree' => SitemapHandler::getInstance()->getTree(),
+ 'sitemap' => SitemapHandler::getInstance()->getSitemap()
+ ));
+
+ return array(
+ 'template' => WCF::getTPL()->fetch('sitemap')
+ );
+ }
+ }
+}
--- /dev/null
+<?php
+namespace wcf\data\sitemap;
+use wcf\data\DatabaseObjectEditor;
+
+/**
+ * Provides functions to edit sitemap entries.
+ *
+ * @author Alexander Ebert
+ * @copyright 2001-2012 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.wcf
+ * @subpackage data.sitemap
+ * @category Community Framework
+ */
+class SitemapEditor extends DatabaseObjectEditor {
+ /**
+ * @see wcf\data\DatabaseObjectDecorator::$baseClass
+ */
+ protected static $baseClass = 'wcf\data\sitemap\Sitemap';
+}
--- /dev/null
+<?php
+namespace wcf\data\sitemap;
+use wcf\data\DatabaseObjectList;
+
+/**
+ * Represents a list of sitemap entries.
+ *
+ * @author Alexander Ebert
+ * @copyright 2001-2012 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.wcf
+ * @subpackage data.sitemap
+ * @category Community Framework
+ */
+class SitemapList extends DatabaseObjectList { }
--- /dev/null
+<?php
+namespace wcf\system\cache\builder;
+use wcf\data\sitemap\SitemapList;
+use wcf\system\package\PackageDependencyHandler;
+
+/**
+ * Caches sitemap structure.
+ *
+ * @author Alexander Ebert
+ * @copyright 2001-2012 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.wcf
+ * @subpackage system.cache.builder
+ * @category Community Framework
+ */
+class SitemapCacheBuilder implements ICacheBuilder {
+ /**
+ * @see wcf\system\cache\ICacheBuilder::getData()
+ */
+ public function getData(array $cacheResource) {
+ $sitemapList = new SitemapList();
+ $sitemapList->getConditionBuilder()->add("sitemap.packageID IN (?)", array(PackageDependencyHandler::getInstance()->getPackageIDs()));
+ $sitemapList->sqlLimit = 0;
+ $sitemapList->readObjects();
+
+ return $sitemapList->getObjects();
+ }
+}
--- /dev/null
+<?php
+namespace wcf\system\package\plugin;
+use wcf\system\cache\CacheHandler;
+use wcf\system\WCF;
+
+/**
+ * This PIP installs, updates or deletes sitemaps.
+ *
+ * @author Alexander Ebert
+ * @copyright 2001-2012 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.wcf
+ * @subpackage system.package.plugin
+ * @category Community Framework
+ */
+class SitemapPackageInstallationPlugin extends AbstractXMLPackageInstallationPlugin {
+ /**
+ * @see wcf\system\package\plugin\AbstractXMLPackageInstallationPlugin::$className
+ */
+ public $className = 'wcf\data\sitemap\SitemapEditor';
+
+ /**
+ * @see wcf\system\package\plugin\AbstractPackageInstallationPlugin::$tableName
+ */
+ public $tableName = 'sitemap';
+
+ /**
+ * @see wcf\system\package\plugin\AbstractXMLPackageInstallationPlugin::$tagName
+ */
+ public $tagName = 'sitemap';
+
+ /**
+ * @see wcf\system\package\plugin\AbstractXMLPackageInstallationPlugin::handleDelete()
+ */
+ protected function handleDelete(array $items) {
+ $sql = "DELETE FROM wcf".WCF_N."_".$this->tableName."
+ WHERE sitemapName = ?
+ AND packageID = ?";
+ $statement = WCF::getDB()->prepareStatement($sql);
+ foreach ($items as $item) {
+ $statement->execute(array(
+ $item['attributes']['name'],
+ $this->installation->getPackageID()
+ ));
+ }
+ }
+
+ /**
+ * @see wcf\system\package\plugin\AbstractXMLPackageInstallationPlugin::prepareImport()
+ */
+ protected function prepareImport(array $data) {
+ return array(
+ 'sitemapName' => $data['attributes']['name'],
+ 'className' => $data['elements']['classname']
+ );
+ }
+
+ /**
+ * @see wcf\system\package\plugin\AbstractXMLPackageInstallationPlugin::findExistingItem()
+ */
+ protected function findExistingItem(array $data) {
+ $sql = "SELECT *
+ FROM wcf".WCF_N."_".$this->tableName."
+ WHERE sitemapName = ?
+ AND packageID = ?";
+ $parameters = array(
+ $data['sitemapName'],
+ $this->installation->getPackageID()
+ );
+
+ return array(
+ 'sql' => $sql,
+ 'parameters' => $parameters
+ );
+ }
+
+ /**
+ * @see wcf\system\package\plugin\AbstractXMLPackageInstallationPlugin::cleanup()
+ */
+ protected function cleanup() {
+ CacheHandler::getInstance()->clear(WCF_DIR.'cache', 'cache.sitemap-*.php');
+ }
+
+ /**
+ * @see wcf\system\package\plugin\IPackageInstallationPlugin::uninstall()
+ */
+ public function uninstall() {
+ parent::uninstall();
+
+ // clear cache immediately
+ CacheHandler::getInstance()->clear(WCF_DIR.'cache', 'cache.sitemap-*.php');
+ }
+}
--- /dev/null
+<?php
+namespace wcf\system\sitemap;
+
+/**
+ * Provides a general interface for all sitemap entries.
+ *
+ * @author Alexander Ebert
+ * @copyright 2001-2012 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.wcf
+ * @subpackage system.sitemap
+ * @category Community Framework
+ */
+interface ISitemapProvider {
+ /**
+ * Returns the parsed sitemap template.
+ *
+ * @return string
+ */
+ public function getTemplate();
+}
\ No newline at end of file
--- /dev/null
+<?php
+namespace wcf\system\sitemap;
+use wcf\system\application\ApplicationHandler;
+use wcf\system\cache\CacheHandler;
+use wcf\system\exception\SystemException;
+use wcf\system\SingletonFactory;
+
+/**
+ * Handles sitemap interactions.
+ *
+ * @author Alexander Ebert
+ * @copyright 2001-2012 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.wcf
+ * @subpackage sitemap.sitemap
+ * @category Community Framework
+ */
+class SitemapHandler extends SingletonFactory {
+ /**
+ * sitemap cache
+ * @var array<wcf\data\sitemap\Sitemap>
+ */
+ protected $cache = null;
+
+ /**
+ * @see \wcf\system\SingletonFactory::init()
+ */
+ protected function init() {
+ $application = ApplicationHandler::getInstance()->getPrimaryApplication();
+ $cacheName = 'sitemap-'.$application->packageID;
+
+ CacheHandler::getInstance()->addResource(
+ $cacheName,
+ WCF_DIR.'cache/cache.'.$cacheName.'.php',
+ 'wcf\system\cache\builder\SitemapCacheBuilder'
+ );
+ $this->cache = CacheHandler::getInstance()->get($cacheName);
+ }
+
+ /**
+ * Returns array of tree items or an empty array if only one sitemap is registered.
+ *
+ * @return array<wcf\data\sitemap\Sitemap>
+ */
+ public function getTree() {
+ $tree = array();
+
+ if (count($this->cache) > 0) {
+ foreach ($this->cache as $sitemap) {
+ $tree[] = $sitemap->sitemapName;
+ }
+ }
+
+ return $tree;
+ }
+
+ /**
+ * Returns sitemap for given sitemap name or falls back to active package id.
+ *
+ * @param string $sitemapName
+ * @return wcf\data\sitemap\Sitemap
+ */
+ public function getSitemap($sitemapName = '') {
+ if (empty($sitemapName)) {
+ foreach ($this->cache as $sitemap) {
+ if ($sitemap->packageID == PACKAGE_ID) {
+ $sitemapName = $sitemap->sitemapName;
+ }
+ }
+
+ if (empty($sitemapName)) {
+ $sitemap = reset($this->cache);
+ $sitemapName = $sitemap->sitemapName;
+ }
+ }
+
+ foreach ($this->cache as $sitemap) {
+ if ($sitemap->sitemapName == $sitemapName) {
+ return $sitemap->getTemplate();
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Validates sitemap name.
+ *
+ * @param string $sitemapName
+ */
+ public function validateSitemapName($sitemapName) {
+ if (empty($sitemapName)) {
+ throw new SystemException("Empty sitemap name provided");
+ }
+
+ $isValid = false;
+ foreach ($this->cache as $sitemap) {
+ if ($sitemap->sitemapName == $sitemapName) {
+ $isValid = true;
+ }
+ }
+
+ if (!$isValid) {
+ throw new SystemException("Sitemap name '".$sitemapName."' is unknown");
+ }
+ }
+}
\ No newline at end of file
KEY packageID (packageID, lastActivityTime, spiderID)
);
+DROP TABLE IF EXISTS wcf1_sitemap;
+CREATE TABLE wcf1_sitemap (
+ sitemapID INT(10) NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ packageID INT(10) NOT NULL,
+ sitemapName VARCHAR(80) NOT NULL DEFAULT '',
+ className VARCHAR(255) NOT NULL DEFAULT '',
+ UNIQUE KEY sitemapName (packageID, sitemapName)
+);
+
DROP TABLE IF EXISTS wcf1_spider;
CREATE TABLE wcf1_spider (
spiderID INT(10) NOT NULL AUTO_INCREMENT PRIMARY KEY,
ALTER TABLE wcf1_session ADD FOREIGN KEY (packageID) REFERENCES wcf1_package (packageID) ON DELETE CASCADE;
ALTER TABLE wcf1_session ADD FOREIGN KEY (userID) REFERENCES wcf1_user (userID) ON DELETE CASCADE;
+ALTER TABLE wcf1_sitemap ADD FOREIGN KEY (packageID) REFERENCES wcf1_package (packageID) ON DELETE CASCADE;
+
ALTER TABLE wcf1_user_storage ADD FOREIGN KEY (userID) REFERENCES wcf1_user (userID) ON DELETE CASCADE;
ALTER TABLE wcf1_user_storage ADD FOREIGN KEY (packageID) REFERENCES wcf1_package (packageID) ON DELETE CASCADE;