silverstripe-cms/code/Controllers/CMSSiteTreeFilter.php

239 lines
6.0 KiB
PHP
Raw Normal View History

<?php
2016-07-22 01:32:32 +02:00
namespace SilverStripe\CMS\Controllers;
use SilverStripe\Admin\LeftAndMain_SearchFilter;
2016-08-10 06:08:39 +02:00
use SilverStripe\CMS\Model\SiteTree;
use SilverStripe\Core\ClassInfo;
use SilverStripe\Core\Object;
use SilverStripe\Forms\DateField;
2016-08-10 06:08:39 +02:00
use SilverStripe\ORM\DataList;
use SilverStripe\ORM\SS_List;
use SilverStripe\ORM\Versioning\Versioned;
/**
* Base class for filtering the subtree for certain node statuses.
2016-03-08 21:50:55 +01:00
*
* The simplest way of building a CMSSiteTreeFilter is to create a pagesToBeShown() method that
* returns an Iterator of maps, each entry containing the 'ID' and 'ParentID' of the pages to be
* included in the tree. The result of a DB::query() can then be returned directly.
*
* If you wish to make a more complex tree, you can overload includeInTree($page) to return true/
* false depending on whether the given page should be included. Note that you will need to include
* parent helper pages yourself.
*/
abstract class CMSSiteTreeFilter extends Object implements LeftAndMain_SearchFilter {
/**
2016-08-10 06:08:39 +02:00
* Search parameters, mostly properties on {@link SiteTree}.
* Caution: Unescaped data.
2016-08-10 06:08:39 +02:00
*
* @var array
*/
protected $params = array();
2016-03-08 21:50:55 +01:00
/**
* List of filtered items and all their parents
2016-03-08 21:50:55 +01:00
*
* @var array
*/
protected $_cache_ids = null;
/**
* Subset of $_cache_ids which include only items that appear directly in search results.
* When highlighting these, item IDs in this subset should be visually distinguished from
* others in the complete set.
*
* @var array
*/
protected $_cache_highlight_ids = null;
2016-03-08 21:50:55 +01:00
/**
2016-08-10 06:08:39 +02:00
* @var array
*/
protected $_cache_expanded = array();
2016-03-08 21:50:55 +01:00
/**
2016-03-08 21:50:55 +01:00
* @var string
*/
protected $childrenMethod = null;
/**
* @var string
*/
protected $numChildrenMethod = 'numChildren';
/**
* Returns a sorted array of all implementators of CMSSiteTreeFilter, suitable for use in a dropdown.
2016-03-08 21:50:55 +01:00
*
* @return array
*/
public static function get_all_filters() {
// get all filter instances
2016-07-22 01:32:32 +02:00
$filters = ClassInfo::subclassesFor('SilverStripe\\CMS\\Controllers\\CMSSiteTreeFilter');
2016-03-08 21:50:55 +01:00
// remove abstract CMSSiteTreeFilter class
array_shift($filters);
2016-03-08 21:50:55 +01:00
// add filters to map
$filterMap = array();
foreach($filters as $filter) {
$filterMap[$filter] = $filter::title();
}
2016-03-08 21:50:55 +01:00
// Ensure that 'all pages' filter is on top position and everything else is sorted alphabetically
uasort($filterMap, function($a, $b) {
return ($a === CMSSiteTreeFilter_Search::title())
? -1
: strcasecmp($a, $b);
});
2016-03-08 21:50:55 +01:00
return $filterMap;
}
2016-03-08 21:50:55 +01:00
public function __construct($params = null) {
if($params) $this->params = $params;
2016-03-08 21:50:55 +01:00
parent::__construct();
}
2016-03-08 21:50:55 +01:00
public function getChildrenMethod() {
return $this->childrenMethod;
}
public function getNumChildrenMethod() {
return $this->numChildrenMethod;
}
public function getPageClasses($page) {
if($this->_cache_ids === NULL) {
$this->populateIDs();
}
// If directly selected via filter, apply highlighting
if(!empty($this->_cache_highlight_ids[$page->ID])) {
return 'filtered-item';
}
2016-08-10 06:08:39 +02:00
return null;
}
/**
* Gets the list of filtered pages
*
* @see {@link SiteTree::getStatusFlags()}
* @return SS_List
*/
abstract public function getFilteredPages();
/**
* @return array Map of Page IDs to their respective ParentID values.
*/
public function pagesIncluded() {
return $this->mapIDs($this->getFilteredPages());
}
2016-03-08 21:50:55 +01:00
/**
* Populate the IDs of the pages returned by pagesIncluded(), also including
* the necessary parent helper pages.
*/
protected function populateIDs() {
$parents = array();
$this->_cache_ids = array();
$this->_cache_highlight_ids = array();
2016-03-08 21:50:55 +01:00
if($pages = $this->pagesIncluded()) {
2016-03-08 21:50:55 +01:00
// And keep a record of parents we don't need to get
// parents of themselves, as well as IDs to mark
foreach($pages as $pageArr) {
$parents[$pageArr['ParentID']] = true;
$this->_cache_ids[$pageArr['ID']] = true;
$this->_cache_highlight_ids[$pageArr['ID']] = true;
}
while(!empty($parents)) {
2016-07-22 01:32:32 +02:00
$q = Versioned::get_including_deleted('SilverStripe\\CMS\\Model\\SiteTree', '"RecordID" in ('.implode(',',array_keys($parents)).')');
$list = $q->map('ID', 'ParentID');
$parents = array();
foreach($list as $id => $parentID) {
if ($parentID) $parents[$parentID] = true;
$this->_cache_ids[$id] = true;
$this->_cache_expanded[$id] = true;
}
}
}
}
2016-03-08 21:50:55 +01:00
public function isPageIncluded($page) {
if($this->_cache_ids === NULL) {
$this->populateIDs();
}
return !empty($this->_cache_ids[$page->ID]);
}
2016-03-08 21:50:55 +01:00
/**
* Applies the default filters to a specified DataList of pages
2016-03-08 21:50:55 +01:00
*
* @param DataList $query Unfiltered query
* @return DataList Filtered query
*/
protected function applyDefaultFilters($query) {
2016-08-10 06:08:39 +02:00
$sng = SiteTree::singleton();
foreach($this->params as $name => $val) {
if(empty($val)) continue;
switch($name) {
case 'Term':
$query = $query->filterAny(array(
'URLSegment:PartialMatch' => $val,
'Title:PartialMatch' => $val,
'MenuTitle:PartialMatch' => $val,
'Content:PartialMatch' => $val
));
break;
case 'LastEditedFrom':
$fromDate = new DateField(null, null, $val);
$query = $query->filter("LastEdited:GreaterThanOrEqual", $fromDate->dataValue().' 00:00:00');
break;
case 'LastEditedTo':
$toDate = new DateField(null, null, $val);
$query = $query->filter("LastEdited:LessThanOrEqual", $toDate->dataValue().' 23:59:59');
break;
case 'ClassName':
if($val != 'All') {
$query = $query->filter('ClassName', $val);
}
break;
default:
if($sng->hasDatabaseField($name)) {
$filter = $sng->dbObject($name)->defaultSearchFilter();
$filter->setValue($val);
$query = $query->alterDataQuery(array($filter, 'apply'));
}
}
}
return $query;
}
2016-03-08 21:50:55 +01:00
/**
* Maps a list of pages to an array of associative arrays with ID and ParentID keys
2016-03-08 21:50:55 +01:00
*
2016-08-10 06:08:39 +02:00
* @param SS_List $pages
* @return array
*/
protected function mapIDs($pages) {
$ids = array();
if($pages) foreach($pages as $page) {
$ids[] = array('ID' => $page->ID, 'ParentID' => $page->ParentID);
}
return $ids;
}
}