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

@ -256,58 +256,14 @@ HTML;
} }
} }
/**
* Return the entire site tree as a nested UL.
* @return string HTML for site tree
*/
public function SiteTreeAsUL() { public function SiteTreeAsUL() {
$obj = singleton('Folder'); return $this->getSiteTreeFor($this->stat('tree_class'), null, 'ChildFolders');
$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; public function getCMSTreeTitle() {
return Director::absoluteBaseURL() . "assets";
} }
/**
* 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);
}
//------------------------------------------------------------------------------------------// //------------------------------------------------------------------------------------------//
// Data saving handlers // Data saving handlers
@ -319,7 +275,8 @@ HTML;
$form = new Form( $form = new Form(
$this, $this,
'SyncForm', 'SyncForm',
new FieldSet(), new FieldSet(
),
new FieldSet( new FieldSet(
$btn = new FormAction('doSync', _t('FILESYSTEMSYNC','Look for new files')) $btn = new FormAction('doSync', _t('FILESYSTEMSYNC','Look for new files'))
) )

View File

@ -50,7 +50,6 @@ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionPr
'AddForm', 'AddForm',
'SiteTreeAsUL', 'SiteTreeAsUL',
'getshowdeletedsubtree', 'getshowdeletedsubtree',
'getfilteredsubtree',
'SearchTreeForm', 'SearchTreeForm',
'ReportForm', 'ReportForm',
'LangForm', 'LangForm',
@ -132,30 +131,11 @@ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionPr
Versioned::prepopulate_versionnumber_cache("SiteTree", "Stage"); Versioned::prepopulate_versionnumber_cache("SiteTree", "Stage");
Versioned::prepopulate_versionnumber_cache("SiteTree", "Live"); Versioned::prepopulate_versionnumber_cache("SiteTree", "Live");
return $this->getSiteTreeFor("SiteTree"); return $this->getSiteTreeFor($this->stat('tree_class'));
} }
/** protected function getMarkingFilter($params) {
* Use a CMSSiteTreeFilter to only get certain nodes return new CMSMainMarkingFilter($params);
*
* @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;
} }
public function generateDataTreeHints() { public function generateDataTreeHints() {
@ -186,7 +166,7 @@ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionPr
} }
public function generateTreeStylingJS() { public function generateTreeStylingJS() {
$classes = ClassInfo::subclassesFor('SiteTree'); $classes = ClassInfo::subclassesFor($this->stat('tree_class'));
foreach($classes as $class) { foreach($classes as $class) {
$obj = singleton($class); $obj = singleton($class);
if($obj instanceof HiddenClass) continue; if($obj instanceof HiddenClass) continue;
@ -1114,7 +1094,7 @@ JS;
_t('CMSMain_left.ss.CLEAR', 'Clear') _t('CMSMain_left.ss.CLEAR', 'Clear')
), ),
new FormAction( new FormAction(
'getfilteredsubtree', 'doSearchTree',
_t('CMSMain_left.ss.SEARCH', 'Search') _t('CMSMain_left.ss.SEARCH', 'Search')
) )
) )
@ -1124,6 +1104,10 @@ JS;
return $form; return $form;
} }
function doSearchTree($data, $form) {
return $this->getsubtree($this->request);
}
function publishall() { function publishall() {
ini_set("memory_limit", -1); ini_set("memory_limit", -1);
ini_set('max_execution_time', 0); ini_set('max_execution_time', 0);
@ -1357,24 +1341,12 @@ JS;
} }
} }
class CMSMainMarkingFilter { class CMSMainMarkingFilter extends 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();
$this->params = $params;
protected function getQuery($params) {
$where = array(); $where = array();
$SQL_params = Convert::raw2sql($this->params); $SQL_params = Convert::raw2sql($params);
foreach($SQL_params as $name => $val) { foreach($SQL_params as $name => $val) {
switch($name) { switch($name) {
// Match against URLSegment, Title, MenuTitle & Content // Match against URLSegment, Title, MenuTitle & Content
@ -1402,38 +1374,13 @@ class CMSMainMarkingFilter {
} }
} }
$where = empty($where) ? '' : 'WHERE (' . implode(') AND (',$where) . ')'; return new SQLQuery(
array("ParentID", "ID"),
$parents = array(); 'SiteTree',
$where
/* 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;
}
} }
?> ?>

View File

@ -452,6 +452,10 @@ class LeftAndMain extends Controller {
} }
} }
public function SiteTreeAsUL() {
return $this->getSiteTreeFor($this->stat('tree_class'));
}
/** /**
* Get a site tree displaying the nodes under the given objects. * 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. // Wrap the root if needs be.
if(!$rootID) { if(!$rootID) {
$rootLink = '#'; $rootLink = '#';
@ -518,14 +521,12 @@ class LeftAndMain extends Controller {
* If ID = 0, then get the whole tree. * If ID = 0, then get the whole tree.
*/ */
public function getsubtree($request) { public function getsubtree($request) {
// Get the tree
$minNodeCount = (is_numeric($request->getVar('minNodeCount'))) ? $request->getVar('minNodeCount') : NULL;
$tree = $this->getSiteTreeFor( $tree = $this->getSiteTreeFor(
$this->stat('tree_class'), $this->stat('tree_class'),
$request->getVar('ID'), $request->getVar('ID'),
null, null,
null, array($this->getMarkingFilter($request->requestVars()), 'mark'),
$minNodeCount $request->getVar('minNodeCount')
); );
// Trim off the outer tag // Trim off the outer tag
@ -535,6 +536,14 @@ class LeftAndMain extends Controller {
return $tree; return $tree;
} }
/**
* @param array $params
* @return LeftAndMainMarkingFilter
*/
protected function getMarkingFilter($params) {
return new LeftAndMainMarkingFilter($params);
}
/** /**
* Save handler * 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 FormResponse::respond();
} }
/** function getCMSTreeTitle() {
* Return the entire site tree as a nested set of ULs. return _t('SecurityAdmin.SGROUPS', 'Security Groups');
* @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;
} }
public function EditedMember() { public function EditedMember() {

View File

@ -81,7 +81,7 @@
}); });
// Set new URL // 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. // Disable checkbox tree controls that currently don't work with search.
// @todo: Make them work together // @todo: Make them work together
@ -91,7 +91,7 @@
// disable buttons to avoid multiple submission // disable buttons to avoid multiple submission
//this.find(':submit').attr('disabled', true); //this.find(':submit').attr('disabled', true);
this.find(':submit[name=action_getfilteredsubtree]').addClass('loading'); this.find(':submit[name=action_doSearchTree]').addClass('loading');
this._reloadSitetree(); this._reloadSitetree();