Enhanced ACP search, added user group option provider
authorAlexander Ebert <ebert@woltlab.com>
Sat, 18 Aug 2012 12:07:19 +0000 (14:07 +0200)
committerAlexander Ebert <ebert@woltlab.com>
Sat, 18 Aug 2012 12:07:19 +0000 (14:07 +0200)
com.woltlab.wcf/acpSearchProvider.xml
wcfsetup/install/files/lib/system/search/acp/AbstractACPSearchResultProvider.class.php [new file with mode: 0644]
wcfsetup/install/files/lib/system/search/acp/AbstractCategorizedACPSearchResultProvider.class.php [new file with mode: 0644]
wcfsetup/install/files/lib/system/search/acp/MenuItemACPSearchResultProvider.class.php
wcfsetup/install/files/lib/system/search/acp/OptionACPSearchResultProvider.class.php
wcfsetup/install/files/lib/system/search/acp/UserGroupOptionACPSearchResultProvider.class.php [new file with mode: 0644]

index 7b86ff031f49fa508c5b05a4dd9134ba5d68b5a1..ee011875068cf7d47a9700178cc63912a8fde47a 100644 (file)
@@ -9,5 +9,9 @@
                        <classname><![CDATA[wcf\system\search\acp\OptionACPSearchResultProvider]]></classname>
                        <showorder>2</showorder>
                </acpsearchprovider>
+               <acpsearchprovider name="userGroupOption">
+                       <classname><![CDATA[wcf\system\search\acp\UserGroupOptionACPSearchResultProvider]]></classname>
+                       <showorder>3</showorder>
+               </acpsearchprovider>
        </import>
 </data>
diff --git a/wcfsetup/install/files/lib/system/search/acp/AbstractACPSearchResultProvider.class.php b/wcfsetup/install/files/lib/system/search/acp/AbstractACPSearchResultProvider.class.php
new file mode 100644 (file)
index 0000000..0165ab3
--- /dev/null
@@ -0,0 +1,56 @@
+<?php
+namespace wcf\system\search\acp;
+use wcf\data\DatabaseObject;
+use wcf\system\WCF;
+
+/**
+ * Abstract class to validate options and permissions for a given object.
+ * 
+ * @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.search.acp
+ * @category   Community Framework
+ */
+abstract class AbstractACPSearchResultProvider {
+       /**
+        * Validates object options and permissions.
+        * 
+        * @param       wcf\data\DatabaseObject         $object
+        * @param       string                          $optionsColumnName
+        * @param       string                          $permissionsColumnName
+        * @return      boolean
+        */
+       protected function validate(DatabaseObject $object, $optionsColumnName = 'options', $permissionsColumnName = 'permissions') {
+               // check the options of this item
+               $hasEnabledOption = true;
+               if ($object->$optionsColumnName) {
+                       $hasEnabledOption = false;
+                       $options = explode(',', strtoupper($object->$optionsColumnName));
+                       foreach ($options as $option) {
+                               if (defined($option) && constant($option)) {
+                                       $hasEnabledOption = true;
+                                       break;
+                               }
+                       }
+               }
+               if (!$hasEnabledOption) return false;
+               
+               // check the permission of this item for the active user
+               $hasPermission = true;
+               if ($object->$permissionsColumnName) {
+                       $hasPermission = false;
+                       $permissions = explode(',', $object->$permissionsColumnName);
+                       foreach ($permissions as $permission) {
+                               if (WCF::getSession()->getPermission($permission)) {
+                                       $hasPermission = true;
+                                       break;
+                               }
+                       }
+               }
+               if (!$hasPermission) return false;
+               
+               return true;
+       }
+}
diff --git a/wcfsetup/install/files/lib/system/search/acp/AbstractCategorizedACPSearchResultProvider.class.php b/wcfsetup/install/files/lib/system/search/acp/AbstractCategorizedACPSearchResultProvider.class.php
new file mode 100644 (file)
index 0000000..4b09906
--- /dev/null
@@ -0,0 +1,134 @@
+<?php
+namespace wcf\system\search\acp;
+use wcf\system\exception\SystemException;
+use wcf\util\ClassUtil;
+
+/**
+ * Abstract class to handle nested categories.
+ * 
+ * @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.search.acp
+ * @category   Community Framework
+ */
+abstract class AbstractCategorizedACPSearchResultProvider extends AbstractACPSearchResultProvider {
+       /**
+        * list of categories
+        * @var array<wcf\data\DatabaseObject>
+        */
+       protected $categories = array();
+       
+       /**
+        * class name for category list
+        * @var string
+        */
+       protected $listClassName = '';
+       
+       /**
+        * list of top category names (level 1 and 2)
+        * @var array<string>
+        */
+       protected $topCategories = array();
+       
+       /**
+        * Creates a new categorized ACP search result provider.
+        */
+       public function __construct() {
+               $this->loadCategories();
+       }
+       
+       /**
+        * Returns a level 1 or 2 category id for given category name.
+        * 
+        * @param       string          $categoryName
+        * @return      integer
+        */
+       protected function getCategoryID($categoryName) {
+               $category = $this->getTopCategory($categoryName);
+               
+               return $category->categoryID;
+       }
+       
+       /**
+        * Returns a level 1 or 2 category name for given category name.
+        * 
+        * @param       string          $categoryName
+        * @return      string
+        */
+       protected function getCategoryName($categoryName) {
+               $category = $this->getTopCategory($categoryName);
+               
+               return $category->categoryName;
+       }
+       
+       /**
+        * Returns a level 1 or 2 category for given category name.
+        * 
+        * @param       string                  $categoryName
+        * @return      wcf\data\DatabaseObject
+        */
+       protected function getTopCategory($categoryName) {
+               if (!$this->isValid($categoryName)) {
+                       throw new SystemException("Category name '".$categoryName."' is unknown");
+               }
+               
+               // this is a top category
+               if (in_array($categoryName, $this->topCategories)) {
+                       return $this->categories[$categoryName];
+               }
+               
+               // check parent category
+               return $this->getTopCategory($this->categories[$categoryName]->parentCategoryName);
+       }
+       
+       /**
+        * Loads categories.
+        */
+       protected function loadCategories() {
+               // validate list class name
+               if (empty($this->listClassName) || !ClassUtil::isInstanceOf($this->listClassName, 'wcf\data\DatabaseObjectList')) {
+                       throw new SystemException("Given class '".$this->listClassName."' is empty or invalid");
+               }
+               
+               // read categories
+               $categoryList = new $this->listClassName();
+               $categoryList->sqlLimit = 0;
+               $categoryList->readObjects();
+               
+               foreach ($categoryList as $category) {
+                       // validate options and permissions
+                       if (!$this->validate($category)) {
+                               continue;
+                       }
+                       
+                       // save level 1 categories
+                       if ($category->parentCategoryName == '') {
+                               $this->topCategories[] = $category->categoryName;
+                       }
+                       
+                       $this->categories[$category->categoryName] = $category;
+               }
+               
+               // create level 2 categories
+               $topCategories = array();
+               foreach ($this->categories as $category) {
+                       if ($category->parentCategoryName && in_array($category->parentCategoryName, $this->topCategories)) {
+                               $topCategories[] = $category->categoryName;
+                       }
+               }
+               
+               $this->topCategories = array_merge($this->topCategories, $topCategories);
+       }
+       
+       /**
+        * Returns true, if given category is valid and accessible.
+        * 
+        * @param       string          $categoryName
+        * @return      boolean
+        */
+       protected function isValid($categoryName) {
+               return isset($this->categories[$categoryName]);
+       }
+}
index fc493d1318c4d5a7a47711aab4681748b91dd510..c7af47b1eee4dc7e148981792231259785fd2d02 100644 (file)
@@ -1,5 +1,6 @@
 <?php
 namespace wcf\system\search\acp;
+use wcf\data\acp\menu\item\ACPMenuItem;
 use wcf\system\database\util\PreparedStatementConditionBuilder;
 use wcf\system\package\PackageDependencyHandler;
 use wcf\system\request\LinkHandler;
@@ -15,7 +16,7 @@ use wcf\system\WCF;
  * @subpackage system.search.acp
  * @category   Community Framework
  */
-class MenuItemACPSearchResultProvider implements IACPSearchResultProvider {
+class MenuItemACPSearchResultProvider extends AbstractACPSearchResultProvider implements IACPSearchResultProvider {
        /**
         * @see wcf\system\search\acp\IACPSearchResultProvider::search()
         */
@@ -69,50 +70,15 @@ class MenuItemACPSearchResultProvider implements IACPSearchResultProvider {
                                break;
                        }
                        
-                       if ($this->checkMenuItem($row)) {
-                               $results[] = new ACPSearchResult($languageItems[$row['menuItem']], $row['menuItemLink'] . SID_ARG_1ST);
-                               $count++;
+                       $menuItem = new ACPMenuItem(null, $row);
+                       if (!$this->validate($menuItem)) {
+                               continue;
                        }
+                       
+                       $results[] = new ACPSearchResult($languageItems[$row['menuItem']], $row['menuItemLink'] . SID_ARG_1ST);
+                       $count++;
                }
                
                return $results;
        }
-       
-       /**
-        * Validates options and permissions for a given menu item.
-        * 
-        * @param       array           $row
-        * @return      boolean
-        */
-       protected function checkMenuItem(array $row) {
-               // check the options of this item
-               $hasEnabledOption = true;
-               if (!empty($row['options'])) {
-                       $hasEnabledOption = false;
-                       $options = explode(',', strtoupper($row['options']));
-                       foreach ($options as $option) {
-                               if (defined($option) && constant($option)) {
-                                       $hasEnabledOption = true;
-                                       break;
-                               }
-                       }
-               }
-               if (!$hasEnabledOption) return false;
-               
-               // check the permission of this item for the active user
-               $hasPermission = true;
-               if (!empty($row['permissions'])) {
-                       $hasPermission = false;
-                       $permissions = explode(',', $row['permissions']);
-                       foreach ($permissions as $permission) {
-                               if (WCF::getSession()->getPermission($permission)) {
-                                       $hasPermission = true;
-                                       break;
-                               }
-                       }
-               }
-               if (!$hasPermission) return false;
-               
-               return true;
-       }
 }
index fe4c39c738beec70454f8e3b1976983fbd0e2749..d7ef7ed330f3fb9966b86cd562a4f77917c36001 100644 (file)
@@ -1,5 +1,6 @@
 <?php
 namespace wcf\system\search\acp;
+use wcf\data\option\Option;
 use wcf\data\option\category\OptionCategoryList;
 use wcf\system\database\util\PreparedStatementConditionBuilder;
 use wcf\system\exception\SystemException;
@@ -17,18 +18,11 @@ use wcf\system\WCF;
  * @subpackage system.search.acp
  * @category   Community Framework
  */
-class OptionACPSearchResultProvider implements IACPSearchResultProvider {
+class OptionACPSearchResultProvider extends AbstractCategorizedACPSearchResultProvider implements IACPSearchResultProvider {
        /**
-        * list of option categories
-        * @var array<wcf\data\option\category\OptionCategory>
+        * @see wcf\system\search\acp\AbstractCategorizedACPSearchResultProvider::$listClassName
         */
-       protected $optionCategories = array();
-       
-       /**
-        * list of level 1 or 2 categories
-        * @var array<wcf\data\option\category\OptionCategory>
-        */
-       protected $topCategories = array();
+       protected $listClassName = 'wcf\data\option\category\OptionCategoryList';
        
        /**
         * @see wcf\system\search\acp\IACPSearchResultProvider::search()
@@ -74,94 +68,28 @@ class OptionACPSearchResultProvider implements IACPSearchResultProvider {
                $conditions = new PreparedStatementConditionBuilder();
                $conditions->add("optionName IN (?)", array($optionNames));
                
-               $sql = "SELECT  optionName, categoryName
+               $sql = "SELECT  optionName, categoryName, options, permissions
                        FROM    wcf".WCF_N."_option
                        ".$conditions;
                $statement = WCF::getDB()->prepareStatement($sql);
                $statement->execute($conditions->getParameters());
                
                while ($row = $statement->fetchArray()) {
-                       $link = LinkHandler::getInstance()->getLink('Option', array('id' => $this->getCategoryID($row['categoryName'])), 'optionName='.$row['optionName'].'#'.$this->getCategoryName($row['categoryName']));
-                       $results[] = new ACPSearchResult($languageItems[$row['optionName']], $link);
-               }
-               
-               return $results;
-       }
-       
-       /**
-        * Returns the primary category id for given category name.
-        * 
-        * @param       string          $categoryName
-        * @return      integer
-        */
-       protected function getCategoryID($categoryName) {
-               // get option categories
-               $this->loadCategories();
-               
-               if (!isset($this->optionCategories[$categoryName])) {
-                       throw new SystemException("Option category '".$categoryName."' is invalid");
-               }
-               
-               // use the category id of parent category
-               if ($this->optionCategories[$categoryName]->parentCategoryName != '') {
-                       return $this->getCategoryID($this->optionCategories[$categoryName]->parentCategoryName);
-               }
-               
-               return $this->optionCategories[$categoryName]->categoryID;
-       }
-       
-       /**
-        * Returns a level 1 or 2 category name.
-        * 
-        * @param       string          $categoryName
-        * @return      string
-        */
-       protected function getCategoryName($categoryName) {
-               // get option categories
-               $this->loadCategories();
-               
-               // load level 1
-               if (empty($this->topCategories)) {
-                       foreach ($this->optionCategories as $category) {
-                               if ($category->parentCategoryName == '') {
-                                       $this->topCategories[$category->categoryName] = $category;
-                               }
+                       // category is not accessible
+                       if (!$this->isValid($row['categoryName'])) {
+                               continue;
                        }
                        
-                       // load level 2
-                       $secondLevelCategories = array();
-                       foreach ($this->optionCategories as $category) {
-                               if ($category->parentCategoryName != '' && isset($this->topCategories[$category->parentCategoryName])) {
-                                       $secondLevelCategories[$category->categoryName] = $category;
-                               }
+                       // option is not accessible
+                       $option = new Option(null, $row);
+                       if (!$this->validate($option)) {
+                               continue;
                        }
                        
-                       $this->topCategories = array_merge($this->topCategories, $secondLevelCategories);
-               }
-               
-               if (!isset($this->optionCategories[$categoryName])) {
-                       throw new SystemException("Option category '".$categoryName."' is invalid");
-               }
-               
-               if (isset($this->topCategories[$categoryName])) {
-                       return $categoryName;
+                       $link = LinkHandler::getInstance()->getLink('Option', array('id' => $this->getCategoryID($row['categoryName'])), 'optionName='.$row['optionName'].'#'.$this->getCategoryName($row['categoryName']));
+                       $results[] = new ACPSearchResult($languageItems[$row['optionName']], $link);
                }
                
-               return $this->getCategoryName($this->optionCategories[$categoryName]->parentCategoryName);
-       }
-       
-       /**
-        * Loads option categories.
-        */
-       protected function loadCategories() {
-               if (empty($this->optionCategories)) {
-                       $categoryList = new OptionCategoryList();
-                       $categoryList->sqlLimit = 0;
-                       $categoryList->readObjects();
-                               
-                       foreach ($categoryList as $category) {
-                               $this->optionCategories[$category->categoryName] = $category;
-                       }
-               }
+               return $results;
        }
 }
diff --git a/wcfsetup/install/files/lib/system/search/acp/UserGroupOptionACPSearchResultProvider.class.php b/wcfsetup/install/files/lib/system/search/acp/UserGroupOptionACPSearchResultProvider.class.php
new file mode 100644 (file)
index 0000000..9fa9af9
--- /dev/null
@@ -0,0 +1,101 @@
+<?php
+namespace wcf\system\search\acp;
+use wcf\data\user\group\option\UserGroupOption;
+use wcf\system\database\util\PreparedStatementConditionBuilder;
+use wcf\system\package\PackageDependencyHandler;
+use wcf\system\request\LinkHandler;
+use wcf\system\WCF;
+
+/**
+ * ACP search provider for user group options.
+ * 
+ * @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.search.acp
+ * @category   Community Framework
+ */
+class UserGroupOptionACPSearchResultProvider extends AbstractCategorizedACPSearchResultProvider implements IACPSearchResultProvider {
+       /**
+        * @see wcf\system\search\acp\AbstractCategorizedACPSearchResultProvider::$listClassName
+        */
+       protected $listClassName = 'wcf\data\user\group\option\category\UserGroupOptionCategoryList';
+       
+       /**
+        * @see wcf\system\search\acp\IACPSearchResultProvider::search()
+        */
+       public function search($query, $limit = 5) {
+               $results = array();
+               
+               // search by language item
+               $conditions = new PreparedStatementConditionBuilder();
+               $conditions->add("languageID = ?", array(WCF::getLanguage()->languageID));
+               $conditions->add("languageItemValue LIKE ?", array($query.'%'));
+               $conditions->add("packageID IN (?)", array(PackageDependencyHandler::getInstance()->getDependencies()));
+               
+               // filter by language item
+               $languageItemsConditions = '';
+               $languageItemsParameters = array();
+               foreach (ACPSearchHandler::getInstance()->getAbbreviations('.acp.group.option.%') as $abbreviation) {
+                       if (!empty($languageItemsConditions)) $languageItemsConditions .= " OR ";
+                       $languageItemsConditions .= "languageItem LIKE ?";
+                       $languageItemsParameters[] = $abbreviation;
+               }
+               $conditions->add("(".$languageItemsConditions.")", $languageItemsParameters);
+               
+               $sql = "SELECT          languageItem, languageItemValue
+                       FROM            wcf".WCF_N."_language_item
+                       ".$conditions."
+                       ORDER BY        languageItemValue ASC";
+               $statement = WCF::getDB()->prepareStatement($sql); // don't use a limit here
+               $statement->execute($conditions->getParameters());
+               $languageItems = array();
+               while ($row = $statement->fetchArray()) {
+                       // ignore descriptions
+                       if (substr($row['languageItem'], -12) == '.description') {
+                               continue;
+                       }
+                       
+                       $itemName = preg_replace('~^([a-z]+)\.acp\.group\.option\.~', '', $row['languageItem']);
+                       $languageItems[$itemName] = $row['languageItemValue'];
+               }
+               
+               if (empty($languageItems)) {
+                       return array();
+               }
+               
+               $conditions = new PreparedStatementConditionBuilder();
+               $conditions->add("optionName IN (?)", array(array_keys($languageItems)));
+               
+               $sql = "SELECT  optionID, optionName, categoryName, permissions, options
+                       FROM    wcf".WCF_N."_user_group_option
+                       ".$conditions;
+               $statement = WCF::getDB()->prepareStatement($sql); // don't use a limit here
+               $statement->execute($conditions->getParameters());
+               
+               $count = 0;
+               while ($row = $statement->fetchArray()) {
+                       if ($count == $limit) {
+                               break;
+                       }
+                       
+                       // category is not accessible
+                       if (!$this->isValid($row['categoryName'])) {
+                               continue;
+                       }
+                       
+                       // option is not accessible
+                       $userGroupOption = new UserGroupOption(null, $row);
+                       if (!$this->validate($userGroupOption)) {
+                               continue;
+                       }
+                       
+                       $link = LinkHandler::getInstance()->getLink('UserGroupOption', array('id' => $row['optionID']));
+                       $results[] = new ACPSearchResult($languageItems[$row['optionName']], $link);
+                       $count++;
+               }
+               
+               return $results;
+       }
+}