ENHANCEMENT Unifying tree logic in most LeftAndMain subclasses: CMSMain, SecurityAdmin, AssetAdmin. Using a common LeftAndMainMarkingFilter. Allowing for custom node counts in SecurityAdmin and AssetAdmin.

API CHANGE Renamed CMSMain->getfilteredsubtree() to doSearchTree()

git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/cms/trunk@92848 467b73ca-7a2a-4603-9d3b-597d59a354a9
This commit is contained in:
Ingo Schommer 2009-11-21 03:21:00 +00:00
parent 1bc268e287
commit 9c3ecea1e7
5 changed files with 112 additions and 157 deletions

View File

@ -255,58 +255,14 @@ HTML;
return singleton('File');
}
}
/**
* Return the entire site tree as a nested UL.
* @return string HTML for site tree
*/
public function SiteTreeAsUL() {
$obj = singleton('Folder');
$obj->setMarkingFilter('ClassName', ClassInfo::subclassesFor('Folder'));
$obj->markPartialTree(30, null, "ChildFolders");
if($p = $this->currentPage()) $obj->markToExpose($p);
// getChildrenAsUL is a flexible and complex way of traversing the tree
$siteTreeList = $obj->getChildrenAsUL(
'',
'"<li id=\"record-$child->ID\" class=\"$child->class" . $child->markingClasses() . ($extraArg->isCurrentPage($child) ? " current" : "") . "\">" . ' .
'"<a href=\"" . Director::link(substr($extraArg->Link(),0,-1), "show", $child->ID) . "\" class=\"" . ($child->hasChildFolders() ? " contents" : "") . "\" >" . $child->TreeTitle . "</a>" ',
$this,
true,
"ChildFolders"
);
// Wrap the root if needs be
$rootLink = $this->Link() . 'show/root';
$baseUrl = Director::absoluteBaseURL() . "assets";
if(!isset($rootID)) {
$siteTree = "<ul id=\"sitetree\" class=\"tree unformatted\"><li id=\"record-root\" class=\"Root\"><a href=\"$rootLink\"><strong>{$baseUrl}</strong></a>"
. $siteTreeList . "</li></ul>";
}
return $siteTree;
}
/**
* Returns a subtree of items underneat the given folder.
*/
public function getsubtree() {
$obj = DataObject::get_by_id('Folder', $_REQUEST['ID']);
$obj->setMarkingFilter('ClassName', ClassInfo::subclassesFor('Folder'));
$obj->markPartialTree();
$results = $obj->getChildrenAsUL(
'',
'"<li id=\"record-$child->ID\" class=\"$child->class" . $child->markingClasses() . ($extraArg->isCurrentPage($child) ? " current" : "") . "\">" . ' .
'"<a href=\"" . Director::link(substr($extraArg->Link(),0,-1), "show", $child->ID) . "\" >" . $child->TreeTitle . "</a>" ',
$this,
true
);
return substr(trim($results), 4, -5);
return $this->getSiteTreeFor($this->stat('tree_class'), null, 'ChildFolders');
}
public function getCMSTreeTitle() {
return Director::absoluteBaseURL() . "assets";
}
//------------------------------------------------------------------------------------------//
@ -319,7 +275,8 @@ HTML;
$form = new Form(
$this,
'SyncForm',
new FieldSet(),
new FieldSet(
),
new FieldSet(
$btn = new FormAction('doSync', _t('FILESYSTEMSYNC','Look for new files'))
)

View File

@ -50,7 +50,6 @@ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionPr
'AddForm',
'SiteTreeAsUL',
'getshowdeletedsubtree',
'getfilteredsubtree',
'SearchTreeForm',
'ReportForm',
'LangForm',
@ -132,30 +131,11 @@ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionPr
Versioned::prepopulate_versionnumber_cache("SiteTree", "Stage");
Versioned::prepopulate_versionnumber_cache("SiteTree", "Live");
return $this->getSiteTreeFor("SiteTree");
return $this->getSiteTreeFor($this->stat('tree_class'));
}
/**
* Use a CMSSiteTreeFilter to only get certain nodes
*
* @return string
*/
public function getfilteredsubtree($data, $form) {
$params = $form->getData();
// Get the tree
$tree = $this->getSiteTreeFor(
$this->stat('tree_class'),
$data['ID'],
null,
array(new CMSMainMarkingFilter($params), 'mark')
);
// Trim off the outer tag
$tree = ereg_replace('^[ \t\r\n]*<ul[^>]*>','', $tree);
$tree = ereg_replace('</ul[^>]*>[ \t\r\n]*$','', $tree);
return $tree;
protected function getMarkingFilter($params) {
return new CMSMainMarkingFilter($params);
}
public function generateDataTreeHints() {
@ -186,7 +166,7 @@ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionPr
}
public function generateTreeStylingJS() {
$classes = ClassInfo::subclassesFor('SiteTree');
$classes = ClassInfo::subclassesFor($this->stat('tree_class'));
foreach($classes as $class) {
$obj = singleton($class);
if($obj instanceof HiddenClass) continue;
@ -1114,7 +1094,7 @@ JS;
_t('CMSMain_left.ss.CLEAR', 'Clear')
),
new FormAction(
'getfilteredsubtree',
'doSearchTree',
_t('CMSMain_left.ss.SEARCH', 'Search')
)
)
@ -1123,6 +1103,10 @@ JS;
return $form;
}
function doSearchTree($data, $form) {
return $this->getsubtree($this->request);
}
function publishall() {
ini_set("memory_limit", -1);
@ -1357,24 +1341,12 @@ JS;
}
}
class CMSMainMarkingFilter {
/**
* @var array Request params (unsanitized)
*/
protected $params = array();
/**
* @param array $params Request params (unsanitized)
*/
function __construct($params = null) {
$this->ids = array();
$this->expanded = array();
$this->params = $params;
class CMSMainMarkingFilter extends LeftAndMainMarkingFilter{
protected function getQuery($params) {
$where = array();
$SQL_params = Convert::raw2sql($this->params);
$SQL_params = Convert::raw2sql($params);
foreach($SQL_params as $name => $val) {
switch($name) {
// Match against URLSegment, Title, MenuTitle & Content
@ -1402,38 +1374,13 @@ class CMSMainMarkingFilter {
}
}
$where = empty($where) ? '' : 'WHERE (' . implode(') AND (',$where) . ')';
$parents = array();
/* Do the actual search */
$res = DB::query('SELECT "ParentID", "ID" FROM "SiteTree" '.$where);
if (!$res) return;
/* And keep a record of parents we don't need to get parents of themselves, as well as IDs to mark */
foreach($res as $row) {
if ($row['ParentID']) $parents[$row['ParentID']] = true;
$this->ids[$row['ID']] = true;
}
/* We need to recurse up the tree, finding ParentIDs for each ID until we run out of parents */
while (!empty($parents)) {
$res = DB::query('SELECT "ParentID", "ID" FROM "SiteTree" WHERE "ID" in ('.implode(',',array_keys($parents)).')');
$parents = array();
foreach($res as $row) {
if ($row['ParentID']) $parents[$row['ParentID']] = true;
$this->ids[$row['ID']] = true;
$this->expanded[$row['ID']] = true;
}
}
}
function mark($node) {
$id = $node->ID;
if(array_key_exists((int) $id, $this->expanded)) $node->markOpened();
return array_key_exists((int) $id, $this->ids) ? $this->ids[$id] : false;
return new SQLQuery(
array("ParentID", "ID"),
'SiteTree',
$where
);
}
}
?>

View File

@ -451,6 +451,10 @@ class LeftAndMain extends Controller {
return DataObject::get_by_id($className, $id);
}
}
public function SiteTreeAsUL() {
return $this->getSiteTreeFor($this->stat('tree_class'));
}
/**
* Get a site tree displaying the nodes under the given objects.
@ -498,7 +502,6 @@ class LeftAndMain extends Controller {
);
// Wrap the root if needs be.
if(!$rootID) {
$rootLink = '#';
@ -518,14 +521,12 @@ class LeftAndMain extends Controller {
* If ID = 0, then get the whole tree.
*/
public function getsubtree($request) {
// Get the tree
$minNodeCount = (is_numeric($request->getVar('minNodeCount'))) ? $request->getVar('minNodeCount') : NULL;
$tree = $this->getSiteTreeFor(
$this->stat('tree_class'),
$request->getVar('ID'),
null,
null,
$minNodeCount
array($this->getMarkingFilter($request->requestVars()), 'mark'),
$request->getVar('minNodeCount')
);
// Trim off the outer tag
@ -535,6 +536,14 @@ class LeftAndMain extends Controller {
return $tree;
}
/**
* @param array $params
* @return LeftAndMainMarkingFilter
*/
protected function getMarkingFilter($params) {
return new LeftAndMainMarkingFilter($params);
}
/**
* Save handler
*/
@ -1217,4 +1226,72 @@ JS;
}
class LeftAndMainMarkingFilter {
/**
* @var array Request params (unsanitized)
*/
protected $params = array();
/**
* @param array $params Request params (unsanitized)
*/
function __construct($params = null) {
$this->ids = array();
$this->expanded = array();
$parents = array();
$q = $this->getQuery($params);
$res = $q->execute();
if (!$res) return;
// And keep a record of parents we don't need to get parents
// of themselves, as well as IDs to mark
foreach($res as $row) {
if ($row['ParentID']) $parents[$row['ParentID']] = true;
$this->ids[$row['ID']] = true;
}
// We need to recurse up the tree,
// finding ParentIDs for each ID until we run out of parents
while (!empty($parents)) {
$res = DB::query('SELECT "ParentID", "ID" FROM "SiteTree" WHERE "ID" in ('.implode(',',array_keys($parents)).')');
$parents = array();
foreach($res as $row) {
if ($row['ParentID']) $parents[$row['ParentID']] = true;
$this->ids[$row['ID']] = true;
$this->expanded[$row['ID']] = true;
}
}
}
protected function getQuery($params) {
$where = array();
$SQL_params = Convert::raw2sql($params);
if(isset($SQL_params['ID'])) unset($SQL_params['ID']);
foreach($SQL_params as $name => $val) {
switch($name) {
default:
// Partial string match against a variety of fields
if(!empty($val) && singleton("SiteTree")->hasDatabaseField($name)) {
$where[] = "\"$name\" LIKE '%$val%'";
}
}
}
return new SQLQuery(
array("ParentID", "ID"),
'SiteTree',
$where
);
}
function mark($node) {
$id = $node->ID;
if(array_key_exists((int) $id, $this->expanded)) $node->markOpened();
return array_key_exists((int) $id, $this->ids) ? $this->ids[$id] : false;
}
}
?>

View File

@ -183,34 +183,8 @@ class SecurityAdmin extends LeftAndMain implements PermissionProvider {
return FormResponse::respond();
}
/**
* Return the entire site tree as a nested set of ULs.
* @return string Unordered list <UL> HTML
*/
public function SiteTreeAsUL() {
$obj = singleton($this->stat('tree_class'));
$obj->markPartialTree();
if($p = $this->currentPage()) $obj->markToExpose($p);
// getChildrenAsUL is a flexible and complex way of traversing the tree
$siteTreeList = $obj->getChildrenAsUL(
'',
'"<li id=\"record-$child->ID\" class=\"$child->class " . ($child->Locked ? " nodelete" : "") . $child->markingClasses() . ($extraArg->isCurrentPage($child) ? " current" : "") . "\">" . ' .
'"<a href=\"" . Director::link(substr($extraArg->Link(),0,-1), "show", $child->ID) . "\" >" . $child->TreeTitle . "</a>" ',
$this,
true
);
// Wrap the root if needs be
$rootLink = $this->Link() . 'show/root';
$rootTitle = _t('SecurityAdmin.SGROUPS', 'Security Groups');
if(!isset($rootID)) {
$siteTree = "<ul id=\"sitetree\" class=\"tree unformatted\"><li id=\"record-root\" class=\"Root\"><a href=\"$rootLink\"><strong>{$rootTitle}</strong></a>"
. $siteTreeList . "</li></ul>";
}
return $siteTree;
function getCMSTreeTitle() {
return _t('SecurityAdmin.SGROUPS', 'Security Groups');
}
public function EditedMember() {

View File

@ -81,7 +81,7 @@
});
// Set new URL
$('#sitetree')[0].setCustomURL(this.attr('action') + '&action_getfilteredsubtree=1', data);
$('#sitetree')[0].setCustomURL(this.attr('action') + '&action_doSearchTree=1', data);
// Disable checkbox tree controls that currently don't work with search.
// @todo: Make them work together
@ -91,7 +91,7 @@
// disable buttons to avoid multiple submission
//this.find(':submit').attr('disabled', true);
this.find(':submit[name=action_getfilteredsubtree]').addClass('loading');
this.find(':submit[name=action_doSearchTree]').addClass('loading');
this._reloadSitetree();