Ticket #4199: CMSMain.patch
| File CMSMain.patch, 20.8 KB (added by drx, 4 years ago) |
|---|
-
CMSMain.php
3 3 * The main "content" area of the CMS. 4 4 * This class creates a 2-frame layout - left-tree and right-form - to sit beneath the main 5 5 * admin menu. 6 * 6 * 7 7 * @package cms 8 8 * @subpackage content 9 9 * @todo Create some base classes to contain the generic functionality that will be replicated. 10 10 */ 11 11 class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionProvider { 12 12 13 13 static $url_segment = ''; 14 14 15 15 static $url_rule = '/$Action/$ID/$OtherID'; 16 16 17 17 // Maintain a lower priority than other administration sections 18 18 // so that Director does not think they are actions of CMSMain 19 19 static $url_priority = 40; 20 20 21 21 static $menu_title = 'Site Content'; 22 22 23 23 static $menu_priority = 10; 24 24 25 25 static $tree_class = "SiteTree"; 26 26 27 27 static $subitem_class = "Member"; 28 28 29 29 static $allowed_actions = array( 30 30 'addmember', 31 31 'addpage', … … 57 57 'getfilteredsubtree', 58 58 'batchactions' 59 59 ); 60 60 61 61 /** 62 62 * SiteTree Columns that can be filtered using the the Site Tree Search button 63 63 */ 64 64 static $site_tree_filter_options = array( 65 65 'Title' => array('CMSMain.TITLE', 'Title'), 66 66 'MenuTitle' => array('CMSMain.MENUTITLE', 'Navigation Label'), 67 'ClassName' => array('CMSMain.PAGETYPE', 'Page Type'), 67 'ClassName' => array('CMSMain.PAGETYPE', 'Page Type'), 68 68 'Status' => array('CMSMain.STATUS', 'Status'), 69 69 'MetaDescription' => array('CMSMain.METADESC', 'Description'), 70 70 'MetaKeywords' => array('CMSMain.METAKEYWORDS', 'Keywords') 71 71 ); 72 72 73 73 static function T_SiteTreeFilterOptions(){ 74 74 return array( 75 75 'Title' => _t('CMSMain.TITLEOPT', 'Title', 0, 'The dropdown title in CMSMain left SiteTreeFilterOptions'), 76 76 'MenuTitle' => _t('CMSMain.MENUTITLEOPT', 'Navigation Label', 0, 'The dropdown title in CMSMain left SiteTreeFilterOptions'), 77 'Status' => _t('CMSMain.STATUSOPT', 'Status', 0, "The dropdown title in CMSMain left SiteTreeFilterOptions"), 78 'MetaDescription' => _t('CMSMain.METADESCOPT', 'Description', 0, "The dropdown title in CMSMain left SiteTreeFilterOptions"), 77 'Status' => _t('CMSMain.STATUSOPT', 'Status', 0, "The dropdown title in CMSMain left SiteTreeFilterOptions"), 78 'MetaDescription' => _t('CMSMain.METADESCOPT', 'Description', 0, "The dropdown title in CMSMain left SiteTreeFilterOptions"), 79 79 'MetaKeywords' => _t('CMSMain.METAKEYWORDSOPT', 'Keywords', 0, "The dropdown title in CMSMain left SiteTreeFilterOptions") 80 80 ); 81 81 } 82 82 83 83 public function init() { 84 84 parent::init(); 85 85 86 86 // Locale" attribute is either explicitly added by LeftAndMain Javascript logic, 87 87 // or implied on a translated record (see {@link Translatable->updateCMSFields()}). 88 88 if(Translatable::is_enabled()) { … … 92 92 $this->Locale = $this->getRequest()->requestVar("Locale"); 93 93 } elseif($this->getRequest()->requestVar("locale")) { 94 94 $this->Locale = $this->getRequest()->requestVar("locale"); 95 } elseif (Session::get("{$this->class}.Locale")) { 96 $this->Locale = Session::get("{$this->class}.Locale"); 95 97 } else { 96 98 $this->Locale = Translatable::default_locale(); 97 99 } 98 100 Translatable::set_current_locale($this->Locale); 101 Session::set("{$this->class}.Locale", $this->Locale); 99 102 } 100 103 101 104 // collect languages for TinyMCE spellchecker plugin 102 105 if(Translatable::is_enabled()) { 103 106 $spellcheckLangs = Translatable::get_existing_content_languages(); … … 110 113 111 114 // Set custom options for TinyMCE specific to CMSMain 112 115 HtmlEditorConfig::get('cms')->setOption('spellchecker_languages', '+' . implode(',', $spellcheckSpec)); 113 116 114 117 Requirements::javascript(CMS_DIR . '/javascript/CMSMain.js'); 115 118 Requirements::javascript(CMS_DIR . '/javascript/CMSMain_left.js'); 116 119 Requirements::javascript(CMS_DIR . '/javascript/CMSMain_right.js'); 117 120 } 118 121 119 122 /** 120 123 * If this is set to true, the "switchView" context in the 121 124 * template is shown, with links to the staging and publish site. … … 134 137 135 138 /** 136 139 * Override {@link LeftAndMain} Link to allow blank URL segment for CMSMain. 137 * 140 * 138 141 * @return string 139 142 */ 140 143 public function Link($action = null) { … … 174 177 175 178 return $tree; 176 179 } 177 180 178 181 public function getfilteredsubtree() { 179 182 // Get the tree 180 183 $tree = $this->getSiteTreeFor($this->stat('tree_class'), $_REQUEST['ID'], null, array(new CMSMainMarkingFilter(), 'mark')); … … 182 185 // Trim off the outer tag 183 186 $tree = ereg_replace('^[ \t\r\n]*<ul[^>]*>','', $tree); 184 187 $tree = ereg_replace('</ul[^>]*>[ \t\r\n]*$','', $tree); 185 188 186 189 return $tree; 187 190 } 188 191 189 192 /** 190 193 * Returns the SiteTree columns that can be filtered using the the Site Tree Search button as a DataObjectSet 191 194 */ … … 208 211 $types = SiteTree::page_type_classes(); array_unshift($types, 'All'); 209 212 $optionsetField = new DropdownField('ClassName', 'ClassName', array_combine($types, $types), 'Any'); 210 213 return $optionsetField->Field(); 211 } 214 } 212 215 213 216 public function generateDataTreeHints() { 214 217 $classes = ClassInfo::subclassesFor( $this->stat('tree_class') ); … … 324 327 if($instance->stat('need_permission') && !$this->can(singleton($class)->stat('need_permission'))) continue; 325 328 326 329 $addAction = $instance->i18n_singular_name(); 327 330 328 331 // if we're in translation mode, the link between the translated pagetype 329 332 // title and the actual classname might not be obvious, so we add it in parantheses 330 333 // Example: class "RedirectorPage" has the title "Weiterleitung" in German, … … 338 341 'AddAction' => $addAction, 339 342 ))); 340 343 } 341 344 342 345 $result->sort('AddAction'); 343 346 344 347 return $result; 345 348 } 346 349 … … 363 366 $record = DataObject::get_one( $treeClass, "`$treeClass`.ID = $id"); 364 367 if($record) Versioned::reading_stage(null); 365 368 } 366 369 367 370 // Then, try getting a deleted record 368 371 if(!$record) { 369 372 $record = Versioned::get_latest_version($treeClass, $id); … … 399 402 $fields->push(new HiddenField('Sort','', $record->Sort )); 400 403 401 404 $idField->setValue($id); 402 405 403 406 if($record->ID && is_numeric( $record->ID ) ) { 404 407 $liveRecord = Versioned::get_one_by_stage('SiteTree', 'Live', "`SiteTree`.ID = $record->ID"); 405 408 if($liveRecord) $liveURLField->setValue($liveRecord->AbsoluteLink()); 406 409 } 407 410 408 411 if(!$record->IsDeletedFromStage) { 409 412 $stageURLField->setValue($record->AbsoluteLink()); 410 413 } 411 414 412 415 // getAllCMSActions can be used to completely redefine the action list 413 416 if($record->hasMethod('getAllCMSActions')) { 414 417 $actions = $record->getAllCMSActions(); … … 458 461 459 462 if(is_numeric($parent)) $parentObj = DataObject::get_by_id("SiteTree", $parent); 460 463 if(!$parentObj || !$parentObj->ID) $parent = 0; 461 464 462 465 if($parentObj && !$parentObj->canAddChildren()) return Security::permissionFailure($this); 463 466 if(!singleton($className)->canCreate()) return Security::permissionFailure($this); 464 467 … … 474 477 */ 475 478 public function getNewItem($id, $setID = true) { 476 479 list($dummy, $className, $parentID, $suffix) = array_pad(explode('-',$id),4,null); 477 480 478 481 $newItem = new $className(); 479 482 480 483 if( !$suffix ) { … … 507 510 508 511 # Some modules like subsites add extra fields that need to be set when the new item is created 509 512 $this->extend('augmentNewSiteTreeItem', $newItem); 510 513 511 514 return $newItem; 512 515 } 513 516 514 517 /** 515 518 * Delete the page from live. This means a page in draft mode might still exist. 516 * 519 * 517 520 * @see delete() 518 521 */ 519 522 public function deletefromlive($urlParams, $form) { … … 521 524 Versioned::reading_stage('Live'); 522 525 $record = DataObject::get_by_id("SiteTree", $id); 523 526 if($record && !$record->canDelete()) return Security::permissionFailure($this); 524 527 525 528 $descRemoved = ''; 526 529 $descendantsRemoved = 0; 527 530 528 531 // before deleting the records, get the descendants of this tree 529 532 if($record) { 530 533 $descendantIDs = $record->getDescendantIDList('SiteTree'); … … 561 564 */ 562 565 public function performPublish($record) { 563 566 if($record && !$record->canPublish()) return Security::permissionFailure($this); 564 567 565 568 $record->doPublish(); 566 569 } 567 570 … … 569 572 * Reverts a page by publishing it to live. 570 573 * Use {@link restorepage()} if you want to restore a page 571 574 * which was deleted from draft without publishing. 572 * 575 * 573 576 * @uses SiteTree->doRevertToLive() 574 577 */ 575 578 public function revert($urlParams, $form) { … … 578 581 // a user can restore a page without publication rights, as it just adds a new draft state 579 582 // (this action should just be available when page has been "deleted from draft") 580 583 if($record && !$record->canEdit()) return Security::permissionFailure($this); 581 584 582 585 $record->doRevertToLive(); 583 586 584 587 $title = Convert::raw2js($record->Title); … … 588 591 589 592 return FormResponse::respond(); 590 593 } 591 594 592 595 /** 593 596 * Delete the current page from draft stage. 594 597 * @see deletefromlive() … … 597 600 $id = $_REQUEST['ID']; 598 601 $record = DataObject::get_one("SiteTree", "SiteTree.ID = $id"); 599 602 if($record && !$record->canDelete()) return Security::permissionFailure(); 600 603 601 604 // save ID and delete record 602 605 $recordID = $record->ID; 603 606 $record->delete(); 604 607 605 608 if(Director::is_ajax()) { 606 609 // need a valid ID value even if the record doesn't have one in the database 607 610 // (its still present in the live tables) … … 615 618 FormResponse::add($this->deleteTreeNodeJS($record)); 616 619 FormResponse::status_message(sprintf(_t('CMSMain.REMOVEDPAGEFROMDRAFT',"Removed '%s' from the draft site"),$record->Title), 'good'); 617 620 return FormResponse::respond(); 618 } 621 } 619 622 } else { 620 623 Director::redirectBack(); 621 624 } … … 675 678 676 679 $page = DataObject::get_by_id("SiteTree", $SQL_id); 677 680 if($page && !$page->canPublish()) return Security::permissionFailure($this); 678 681 679 682 $page->doUnpublish(); 680 683 681 684 return $this->tellBrowserAboutPublicationChange($page, sprintf(_t('CMSMain.REMOVEDPAGE',"Removed '%s' from the published site"),$page->Title)); 682 685 } 683 686 684 687 /** 685 688 * Return a few pieces of information about a change to a page 686 689 * - Send the new status message … … 697 700 698 701 FormResponse::add($this->getActionUpdateJS($page)); 699 702 FormResponse::update_status($page->Status); 700 703 701 704 if($JS_stageURL || $JS_liveURL) { 702 705 FormResponse::add("\$('sitetree').setNodeTitle($page->ID, '$JS_title');"); 703 706 } else { … … 705 708 FormResponse::add("if(node && node.parentTreeNode) node.parentTreeNode.removeTreeNode(node);"); 706 709 FormResponse::add("$('Form_EditForm').reloadIfSetTo($page->ID);"); 707 710 } 708 711 709 712 FormResponse::status_message($statusMessage, 'good'); 710 713 FormResponse::add("$('Form_EditForm').elements.StageURLSegment.value = '$JS_stageURL';"); 711 714 FormResponse::add("$('Form_EditForm').elements.LiveURLSegment.value = '$JS_liveURL';"); … … 717 720 function performRollback($id, $version) { 718 721 $record = DataObject::get_by_id($this->stat('tree_class'), $id); 719 722 if($record && !$record->canPublish()) return Security::permissionFailure($this); 720 723 721 724 $record->doRollbackTo($version); 722 725 return $record; 723 726 } … … 730 733 731 734 if($record) { 732 735 if($record && !$record->canView()) return Security::permissionFailure($this); 733 736 734 737 $fields = $record->getCMSFields($this); 735 738 $fields->removeByName("Status"); 736 739 … … 738 741 $fields->push(new HiddenField("Version")); 739 742 $fields->insertBefore( 740 743 new LiteralField( 741 'YouAreViewingHeader', 744 'YouAreViewingHeader', 742 745 '<p class="message notice">' . 743 746 sprintf( 744 747 _t( … … 747 750 PR_MEDIUM, 748 751 'Version number is a linked string, created is a relative time (e.g. 2 days ago), by a specific author' 749 752 ), 750 "<a href=\"admin/getversion/$record->ID/$version\" title=\"" . $versionAuthor->Title . "\">$version</a>", 753 "<a href=\"admin/getversion/$record->ID/$version\" title=\"" . $versionAuthor->Title . "\">$version</a>", 751 754 $record->obj('LastEdited')->Ago(), 752 755 $versionAuthor->Title 753 756 ) . … … 764 767 765 768 // encode the message to appear in the body of the email 766 769 $archiveURL = Director::absoluteBaseURL() . $record->URLSegment . '?archiveDate=' . $record->obj('LastEdited')->URLDatetime(); 767 770 768 771 // Ensure that source file comments are disabled 769 772 SSViewer::set_source_file_comments(false); 770 773 771 774 $archiveEmailMessage = urlencode( $this->customise( array( 'ArchiveDate' => $record->obj('LastEdited'), 'ArchiveURL' => $archiveURL ) )->renderWith( 'ViewArchivedEmail' ) ); 772 775 $archiveEmailMessage = preg_replace( '/\+/', '%20', $archiveEmailMessage ); 773 776 … … 781 784 "ID" => $id, 782 785 "Version" => $version, 783 786 )); 784 787 785 788 // historical version shouldn't be editable 786 789 $readonlyFields = $form->Fields()->makeReadonly(); 787 790 $form->setFields($readonlyFields); … … 791 794 )); 792 795 793 796 SSViewer::setOption('rewriteHashlinks', false); 794 797 795 798 if(Director::is_ajax()) { 796 799 $result = $templateData->renderWith($this->class . '_right'); 797 800 $parts = split('</?form[^>]*>', $result); … … 799 802 } else { 800 803 return $templateData->renderWith('LeftAndMain'); 801 804 } 802 803 805 806 804 807 } 805 808 } 806 809 … … 819 822 820 823 $page = DataObject::get_by_id("SiteTree", $id); 821 824 if($page && !$page->canView()) return Security::permissionFailure($this); 822 825 823 826 $record = $page->compareVersions($fromVersion, $toVersion); 824 827 $fromVersionRecord = Versioned::get_version('SiteTree', $id, $fromVersion); 825 828 $toVersionRecord = Versioned::get_version('SiteTree', $id, $toVersion); 826 829 827 830 if($record) { 828 831 $fromDateNice = $fromVersionRecord->obj('LastEdited')->Ago(); 829 832 $toDateNice = $toVersionRecord->obj('LastEdited')->Ago(); … … 836 839 $fields->insertBefore( 837 840 new LiteralField( 838 841 'YouAreComparingHeader', 839 '<p class="message notice">' . 842 '<p class="message notice">' . 840 843 sprintf( 841 844 _t('CMSMain.COMPARINGV',"Comparing versions %s and %s"), 842 845 "<a href=\"admin/getversion/$id/$fromVersionRecord->Version\" title=\"$fromAuthor->Title\">$fromVersionRecord->Version</a> <small>($fromDateNice)</small>", 843 846 "<a href=\"admin/getversion/$id/$toVersionRecord->Version\" title=\"$toAuthor->Title\">$toVersionRecord->Version</a> <small>($toDateNice)</small>" 844 847 ) . 845 848 '</p>' 846 ), 849 ), 847 850 "Root" 848 851 ); 849 852 … … 855 858 "ID" => $id, 856 859 "Version" => $fromVersion, 857 860 )); 858 861 859 862 // comparison views shouldn't be editable 860 863 $readonlyFields = $form->Fields()->makeReadonly(); 861 864 $form->setFields($readonlyFields); 862 865 863 866 foreach($form->Fields()->dataFields() as $field) { 864 867 $field->dontEscape = true; 865 868 } … … 919 922 'DialogType' => 'alert' 920 923 ))->renderWith('Dialog'); 921 924 } 922 925 923 926 /** 924 927 * Batch Actions Handler 925 928 */ … … 972 975 foreach( $this->PageTypes() as $arrayData ) { 973 976 $pageTypes[$arrayData->getField('ClassName')] = $arrayData->getField('AddAction'); 974 977 } 975 978 976 979 $fields = new FieldSet( 977 980 new HiddenField("ParentID"), 978 981 new HiddenField("Locale", 'Locale', Translatable::get_current_locale()), 979 982 new DropdownField("PageType", "", $pageTypes, 'Page') 980 983 ); 981 984 982 985 $actions = new FieldSet( 983 986 new FormAction("addpage", _t('CMSMain.GO',"Go")) 984 987 ); … … 1019 1022 function publishall() { 1020 1023 ini_set("memory_limit", -1); 1021 1024 ini_set('max_execution_time', 0); 1022 1025 1023 1026 $response = ""; 1024 1027 1025 1028 if(isset($this->requestParams['confirm'])) { … … 1029 1032 while(true) { 1030 1033 foreach($pages as $page) { 1031 1034 if($page && !$page->canPublish()) return Security::permissionFailure($this); 1032 1035 1033 1036 $page->doPublish(); 1034 1037 $page->destroy(); 1035 1038 unset($page); … … 1056 1059 . _t('CMSMain.PUBALLCONFIRM',"Please publish every page in the site, copying content stage to live",PR_LOW,'Confirmation button') .'" /> 1057 1060 </form>'; 1058 1061 } 1059 1062 1060 1063 return $response; 1061 1064 } 1062 1065 1063 1066 /** 1064 1067 * Restore a completely deleted page from the SiteTree_versions table. 1065 1068 */ … … 1089 1092 if($page && !$page->canEdit()) return Security::permissionFailure($this); 1090 1093 1091 1094 $newPage = $page->duplicate(); 1092 1095 1093 1096 // ParentID can be hard-set in the URL. This is useful for pages with multiple parents 1094 1097 if($_GET['parentID'] && is_numeric($_GET['parentID'])) { 1095 1098 $newPage->ParentID = $_GET['parentID']; … … 1114 1117 user_error("CMSMain::duplicate() Bad ID: '$id'", E_USER_WARNING); 1115 1118 } 1116 1119 } 1117 1118 1120 1119 1121 1122 1120 1123 /** 1121 1124 * Create a new translation from an existing item, switch to this language and reload the tree. 1122 1125 */ … … 1125 1128 $originalLangID = (int)$_REQUEST['ID']; 1126 1129 1127 1130 $record = $this->getRecord($originalLangID); 1128 1131 1129 1132 $this->Locale = $langCode; 1130 1133 Translatable::set_current_locale($langCode); 1131 1134 1132 1135 // Create a new record in the database - this is different 1133 1136 // to the usual "create page" pattern of storing the record 1134 1137 // in-memory until a "save" is performed by the user, mainly … … 1137 1140 $translatedRecord = $record->createTranslation($langCode); 1138 1141 1139 1142 $url = sprintf( 1140 "%s/%d/?locale=%s", 1143 "%s/%d/?locale=%s", 1141 1144 $this->Link('show'), 1142 1145 $translatedRecord->ID, 1143 1146 $langCode … … 1157 1160 $title = _t("{$class}.MENUTITLE", LeftAndMain::menu_title_for_class($class)); 1158 1161 $perms["CMS_ACCESS_" . $class] = sprintf( 1159 1162 _t( 1160 'CMSMain.ACCESS', 1163 'CMSMain.ACCESS', 1161 1164 "Access to '%s' (%s)", 1162 1165 PR_MEDIUM, 1163 1166 "Item in permission selection identifying the admin section, with title and classname. Example: Access to 'Files & Images' (AssetAdmin)" 1164 ), 1167 ), 1165 1168 $title, 1166 1169 $class 1167 1170 ); 1168 1171 } 1169 1172 $perms["CMS_ACCESS_LeftAndMain"] = _t( 1170 'CMSMain.ACCESSALLINTERFACES', 1173 'CMSMain.ACCESSALLINTERFACES', 1171 1174 'Access to all CMS interfaces' 1172 1175 ); 1173 1176 return $perms; 1174 1177 } 1175 1178 1176 1179 /** 1177 1180 * Returns all languages with languages already used appearing first. 1178 1181 * Called by the SSViewer when rendering the template. … … 1181 1184 $member = Member::currentUser(); //check to see if the current user can switch langs or not 1182 1185 if(Permission::checkMember($member, 'VIEW_LANGS')) { 1183 1186 $dropdown = new LanguageDropdownField( 1184 'LangSelector', 1185 'Language', 1186 array(), 1187 'SiteTree', 1187 'LangSelector', 1188 'Language', 1189 array(), 1190 'SiteTree', 1188 1191 'Locale-English' 1189 1192 ); 1190 1193 $dropdown->setValue(Translatable::get_current_locale()); 1191 1194 return $dropdown; 1192 1195 } 1193 1196 1194 1197 //user doesn't have permission to switch langs so just show a string displaying current language 1195 1198 return i18n::get_locale_name( Translatable::get_current_locale() ); 1196 1199 } 1197 1200 1198 1201 /** 1199 1202 * Determine if there are more than one languages in our site tree. 1200 * 1203 * 1201 1204 * @return boolean 1202 1205 */ 1203 1206 function MultipleLanguages() { … … 1205 1208 1206 1209 return (count($langs) > 1); 1207 1210 } 1208 1211 1209 1212 /** 1210 1213 * @return boolean 1211 1214 */ … … 1215 1218 } 1216 1219 1217 1220 class CMSMainMarkingFilter { 1218 1221 1219 1222 function __construct() { 1220 1223 $this->ids = array(); 1221 1224 $this->expanded = array(); 1222 1225 1223 1226 $where = array(); 1224 1227 1225 1228 // Match against URLSegment, Title, MenuTitle & Content 1226 1229 if (isset($_REQUEST['SiteTreeSearchTerm'])) { 1227 1230 $term = Convert::raw2sql($_REQUEST['SiteTreeSearchTerm']); 1228 1231 $where[] = "`URLSegment` LIKE '%$term%' OR `Title` LIKE '%$term%' OR `MenuTitle` LIKE '%$term%' OR `Content` LIKE '%$term%'"; 1229 1232 } 1230 1233 1231 1234 // Match against date 1232 1235 if (isset($_REQUEST['SiteTreeFilterDate'])) { 1233 1236 $date = $_REQUEST['SiteTreeFilterDate']; 1234 1237 $date = ((int)substr($date,6,4)) . '-' . ((int)substr($date,3,2)) . '-' . ((int)substr($date,0,2)); 1235 $where[] = "`LastEdited` > '$date'"; 1238 $where[] = "`LastEdited` > '$date'"; 1236 1239 } 1237 1240 1238 1241 // Match against exact ClassName 1239 1242 if (isset($_REQUEST['ClassName']) && $_REQUEST['ClassName'] != 'All') { 1240 1243 $klass = Convert::raw2sql($_REQUEST['ClassName']); 1241 1244 $where[] = "`ClassName` = '$klass'"; 1242 1245 } 1243 1244 // Partial string match against a variety of fields 1246 1247 // Partial string match against a variety of fields 1245 1248 foreach (CMSMain::T_SiteTreeFilterOptions() as $key => $value) { 1246 1249 if (!empty($_REQUEST[$key])) { 1247 1250 $match = Convert::raw2sql($_REQUEST[$key]); 1248 1251 $where[] = "`$key` LIKE '%$match%'"; 1249 1252 } 1250 1253 } 1251 1254 1252 1255 $where = empty($where) ? '' : 'WHERE (' . implode(') AND (',$where) . ')'; 1253 1256 1254 1257 $parents = array(); 1255 1258 1256 1259 /* Do the actual search */ 1257 1260 $res = DB::query('SELECT `ParentID`, `ID` FROM SiteTree '.$where); 1258 1261 if (!$res) return; 1259 1262 1260 1263 /* And keep a record of parents we don't need to get parents of themselves, as well as IDs to mark */ 1261 1264 foreach($res as $row) { 1262 1265 if ($row['ParentID']) $parents[$row['ParentID']] = true; 1263 1266 $this->ids[$row['ID']] = true; 1264 1267 } 1265 1268 1266 1269 /* We need to recurse up the tree, finding ParentIDs for each ID until we run out of parents */ 1267 1270 while (!empty($parents)) { 1268 1271 $res = DB::query('SELECT `ParentID`, `ID` FROM SiteTree WHERE `ID` in ('.implode(',',array_keys($parents)).')'); … … 1275 1278 } 1276 1279 } 1277 1280 } 1278 1281 1279 1282 function mark($node) { 1280 1283 $id = $node->ID; 1281 1284 if (array_key_exists($id, $this->expanded)) $node->markOpened();
