From a395c5322fc1965b775be50149a38cdff36cca59 Mon Sep 17 00:00:00 2001 From: Damian Mooyman Date: Fri, 21 Jun 2013 10:45:33 +1200 Subject: [PATCH] API Move of codebase to parameterised query database abstraction layer API Renamed DB static methods to properly conform to naming convention (lowercase, underscored) API Replaced deprecated method --- code/batchactions/CMSBatchActions.php | 8 +- code/controllers/AssetAdmin.php | 12 +- code/controllers/CMSMain.php | 54 ++--- code/controllers/CMSSiteTreeFilter.php | 2 +- code/controllers/ContentController.php | 4 +- code/controllers/ModelAsController.php | 20 +- code/controllers/OldPageRedirector.php | 16 +- code/controllers/RootURLController.php | 9 +- code/controllers/SilverStripeNavigator.php | 32 +-- code/forms/FolderUnusedAssetsField.php | 12 +- code/model/SiteTree.php | 214 ++++++++++-------- code/model/SiteTreeFileExtension.php | 8 +- code/model/SiteTreeFolderExtension.php | 14 +- code/model/VirtualPage.php | 20 +- code/reports/BrokenLinksReport.php | 11 +- code/search/SearchForm.php | 4 +- tasks/MigrateSiteTreeLinkingTask.php | 5 +- tasks/RemoveOrphanedPagesTask.php | 53 ++--- tasks/UpgradeSiteTreePermissionSchemaTask.php | 6 +- tests/controller/CMSMainTest.php | 10 +- tests/controller/CMSSiteTreeFilterTest.php | 2 +- tests/model/FileLinkTrackingTest.php | 16 +- tests/model/SiteTreeTest.php | 22 +- tests/model/VirtualPageTest.php | 2 +- tests/search/SearchFormTest.php | 8 +- 25 files changed, 311 insertions(+), 253 deletions(-) diff --git a/code/batchactions/CMSBatchActions.php b/code/batchactions/CMSBatchActions.php index 0354eddd..762d6df9 100644 --- a/code/batchactions/CMSBatchActions.php +++ b/code/batchactions/CMSBatchActions.php @@ -66,7 +66,9 @@ class CMSBatchAction_Delete extends CMSBatchAction { // check to see if the record exists on the live site, // if it doesn't remove the tree node - $liveRecord = Versioned::get_one_by_stage( 'SiteTree', 'Live', "\"SiteTree\".\"ID\"=$id"); + $liveRecord = Versioned::get_one_by_stage( 'SiteTree', 'Live', array( + '"SiteTree"."ID"' => $id + )); if($liveRecord) { $liveRecord->IsDeletedFromStage = true; $status['modified'][$liveRecord->ID] = array( @@ -111,7 +113,9 @@ class CMSBatchAction_DeleteFromLive extends CMSBatchAction { if($page->canDelete()) $page->doDeleteFromLive(); // check to see if the record exists on the stage site, if it doesn't remove the tree node - $stageRecord = Versioned::get_one_by_stage( 'SiteTree', 'Stage', "\"SiteTree\".\"ID\"=$id"); + $stageRecord = Versioned::get_one_by_stage( 'SiteTree', 'Stage', array( + '"SiteTree"."ID"' => $id + )); if($stageRecord) { $stageRecord->IsAddedToStage = true; $status['modified'][$stageRecord->ID] = array( diff --git a/code/controllers/AssetAdmin.php b/code/controllers/AssetAdmin.php index 3335ff99..b012be2f 100644 --- a/code/controllers/AssetAdmin.php +++ b/code/controllers/AssetAdmin.php @@ -335,9 +335,9 @@ JS public function delete($data, $form) { $className = $this->stat('tree_class'); - $record = DataObject::get_by_id($className, Convert::raw2sql($data['ID'])); + $record = DataObject::get_by_id($className, $data['ID']); if($record && !$record->canDelete()) return Security::permissionFailure(); - if(!$record || !$record->ID) throw new HTTPResponse_Exception("Bad record ID #" . (int)$data['ID'], 404); + if(!$record || !$record->ID) throw new SS_HTTPResponse_Exception("Bad record ID #" . (int)$data['ID'], 404); $parentID = $record->ParentID; $record->delete(); $this->setCurrentPageID(null); @@ -557,10 +557,10 @@ JS } /** - * ################################# - * Garbage collection. - * ################################# - */ + * ################################# + * Garbage collection. + * ################################# + */ /** * Removes all unused thumbnails from the file store diff --git a/code/controllers/CMSMain.php b/code/controllers/CMSMain.php index 340529ad..7b7cd9d3 100644 --- a/code/controllers/CMSMain.php +++ b/code/controllers/CMSMain.php @@ -536,7 +536,7 @@ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionPr if($versionID) { $record = Versioned::get_version($treeClass, $id, $versionID); } else { - $record = DataObject::get_one($treeClass, "\"$treeClass\".\"ID\" = $id"); + $record = DataObject::get_by_id($treeClass, $id); } // Then, try getting a record from the live site @@ -545,7 +545,7 @@ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionPr Versioned::reading_stage('Live'); singleton($treeClass)->flushCache(); - $record = DataObject::get_one( $treeClass, "\"$treeClass\".\"ID\" = $id"); + $record = DataObject::get_by_id($treeClass, $id); if($record) Versioned::set_reading_mode(''); } @@ -816,9 +816,8 @@ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionPr // Fall back to homepage record if(!$id) { $homepageSegment = RootURLController::get_homepage_link(); - $homepageRecord = DataObject::get_one('SiteTree', sprintf( - '"SiteTree"."URLSegment" = \'%s\'', - Convert::raw2sql($homepageSegment) + $homepageRecord = DataObject::get_one('SiteTree', array( + '"SiteTree"."URLSegment"' => $homepageSegment )); if($homepageRecord) $id = $homepageRecord->ID; } @@ -836,14 +835,14 @@ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionPr $className = $this->stat('tree_class'); // Existing or new record? - $SQL_id = Convert::raw2sql($data['ID']); - if(substr($SQL_id,0,3) != 'new') { - $record = DataObject::get_by_id($className, $SQL_id); + $id = $data['ID']; + if(substr($id,0,3) != 'new') { + $record = DataObject::get_by_id($className, $id); if($record && !$record->canEdit()) return Security::permissionFailure($this); - if(!$record || !$record->ID) throw new SS_HTTPResponse_Exception("Bad record ID #$SQL_id", 404); + if(!$record || !$record->ID) throw new SS_HTTPResponse_Exception("Bad record ID #$id", 404); } else { if(!singleton($this->stat('tree_class'))->canCreate()) return Security::permissionFailure($this); - $record = $this->getNewItem($SQL_id, false); + $record = $this->getNewItem($id, false); } // TODO Coupling to SiteTree @@ -892,17 +891,17 @@ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionPr $newItem = new $className(); - if( !$suffix ) { + if( !$suffix ) { $sessionTag = "NewItems." . $parentID . "." . $className; - if(Session::get($sessionTag)) { - $suffix = '-' . Session::get($sessionTag); - Session::set($sessionTag, Session::get($sessionTag) + 1); - } - else - Session::set($sessionTag, 1); + if(Session::get($sessionTag)) { + $suffix = '-' . Session::get($sessionTag); + Session::set($sessionTag, Session::get($sessionTag) + 1); + } + else + Session::set($sessionTag, 1); - $id = $id . $suffix; - } + $id = $id . $suffix; + } $newItem->Title = _t( 'CMSMain.NEWPAGE', @@ -915,7 +914,7 @@ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionPr // DataObject::fieldExists only checks the current class, not the hierarchy // This allows the CMS to set the correct sort value if($newItem->castingHelper('Sort')) { - $newItem->Sort = DB::query("SELECT MAX(\"Sort\") FROM \"SiteTree\" WHERE \"ParentID\" = '" . Convert::raw2sql($parentID) . "'")->value() + 1; + $newItem->Sort = DB::prepared_query('SELECT MAX("Sort") FROM "SiteTree" WHERE "ParentID" = ?', array($parentID))->value() + 1; } if($setID) $newItem->ID = $id; @@ -1007,11 +1006,9 @@ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionPr $restoredPage = Versioned::get_latest_version("SiteTree", $id); if(!$restoredPage) return new SS_HTTPResponse("SiteTree #$id not found", 400); - $record = Versioned::get_one_by_stage( - 'SiteTree', - 'Live', - sprintf("\"SiteTree_Live\".\"ID\" = '%d'", (int)$data['ID']) - ); + $record = Versioned::get_one_by_stage('SiteTree', 'Live', array( + '"SiteTree_Live"."ID"' => $id + )); // a user can restore a page without publication rights, as it just adds a new draft state // (this action should just be available when page has been "deleted from draft") @@ -1038,11 +1035,8 @@ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionPr * @see deletefromlive() */ public function delete($data, $form) { - $id = Convert::raw2sql($data['ID']); - $record = DataObject::get_one( - "SiteTree", - sprintf("\"SiteTree\".\"ID\" = %d", $id) - ); + $id = $data['ID']; + $record = DataObject::get_by_id("SiteTree", $id); if($record && !$record->canDelete()) return Security::permissionFailure(); if(!$record || !$record->ID) throw new SS_HTTPResponse_Exception("Bad record ID #$id", 404); diff --git a/code/controllers/CMSSiteTreeFilter.php b/code/controllers/CMSSiteTreeFilter.php index bac1a858..47a09024 100644 --- a/code/controllers/CMSSiteTreeFilter.php +++ b/code/controllers/CMSSiteTreeFilter.php @@ -101,7 +101,7 @@ abstract class CMSSiteTreeFilter extends Object { } while(!empty($parents)) { - $q = new SQLQuery(); + $q = new SQLSelect(); $q->setSelect(array('"ID"','"ParentID"')) ->setFrom('"SiteTree"') ->setWhere('"ID" in ('.implode(',',array_keys($parents)).')'); diff --git a/code/controllers/ContentController.php b/code/controllers/ContentController.php index 426ff9db..073e13eb 100755 --- a/code/controllers/ContentController.php +++ b/code/controllers/ContentController.php @@ -71,7 +71,7 @@ class ContentController extends Controller { $parent = SiteTree::get_by_link($parentRef); if(!$parent && is_numeric($parentRef)) { - $parent = DataObject::get_by_id('SiteTree', Convert::raw2sql($parentRef)); + $parent = DataObject::get_by_id('SiteTree', $parentRef); } if($parent) return $parent->Children(); @@ -208,7 +208,7 @@ class ContentController extends Controller { $response = $this->request->isMedia() ? null : ErrorPage::response_for($code); // Failover to $message if the HTML response is unavailable / inappropriate parent::httpError($code, $response ? $response : $message); - } + } /** * Get the project name diff --git a/code/controllers/ModelAsController.php b/code/controllers/ModelAsController.php index c5e89fbd..c43b6494 100644 --- a/code/controllers/ModelAsController.php +++ b/code/controllers/ModelAsController.php @@ -64,7 +64,7 @@ class ModelAsController extends Controller implements NestedController { } // If the database has not yet been created, redirect to the build page. - if(!DB::isActive() || !ClassInfo::hasTable('SiteTree')) { + if(!DB::is_active() || !ClassInfo::hasTable('SiteTree')) { $this->response->redirect(Director::absoluteBaseURL() . 'dev/build?returnURL=' . (isset($_GET['url']) ? urlencode($_GET['url']) : null)); $this->popCurrent(); @@ -101,14 +101,16 @@ class ModelAsController extends Controller implements NestedController { // Find page by link, regardless of current locale settings if(class_exists('Translatable')) Translatable::disable_locale_filter(); - $sitetree = DataObject::get_one( - 'SiteTree', - sprintf( - '"SiteTree"."URLSegment" = \'%s\' %s', - Convert::raw2sql(rawurlencode($URLSegment)), - (SiteTree::config()->nested_urls ? 'AND "SiteTree"."ParentID" = 0' : null) - ) - ); + + // Select child page + $conditions = array('"SiteTree"."URLSegment"' => rawurlencode($URLSegment)); + if(SiteTree::config()->nested_urls) { + $conditions[] = array('"SiteTree"."ParentID"' => 0); + } + $sitetree = DataObject::get_one('SiteTree', $conditions); + + // Check translation module + // @todo Refactor out module specific code if(class_exists('Translatable')) Translatable::enable_locale_filter(); if(!$sitetree) { diff --git a/code/controllers/OldPageRedirector.php b/code/controllers/OldPageRedirector.php index a9a606bb..fd59901f 100644 --- a/code/controllers/OldPageRedirector.php +++ b/code/controllers/OldPageRedirector.php @@ -6,7 +6,7 @@ class OldPageRedirector extends Extension { * On every URL that generates a 404, we'll capture it here and see if we can * find an old URL that it should be redirecting to. * - * @param SS_HTTPResponse $request The request object + * @param SS_HTTPRequest $request The request object * @throws SS_HTTPResponse_Exception */ public function onBeforeHTTPError404($request) { @@ -41,7 +41,7 @@ class OldPageRedirector extends Extension { static public function find_old_page($params, $parent = null, $redirect = false) { $parent = is_numeric($parent) ? SiteTree::get()->byId($parent) : $parent; $params = (array)$params; - $URL = Convert::raw2sql(array_shift($params)); + $URL = rawurlencode(array_shift($params)); if (empty($URL)) { return false; } if ($parent) { $page = SiteTree::get()->filter(array('ParentID' => $parent->ID, 'URLSegment' => $URL))->First(); @@ -51,11 +51,17 @@ class OldPageRedirector extends Extension { if (!$page) { // If we haven't found a candidate, lets resort to finding an old page with this URL segment - // TODO: Rewrite using ORM syntax - $query = new SQLQuery ( + $oldFilter = array( + '"SiteTree_versions"."URLSegment"' => $URL, + '"SiteTree_versions"."WasPublished"' => true + ); + if($parent) { + $oldFilter[] = array('"SiteTree_versions"."ParentID"' => $parent->ID); + } + $query = new SQLSelect( '"RecordID"', '"SiteTree_versions"', - "\"URLSegment\" = '$URL' AND \"WasPublished\" = 1" . ($parent ? ' AND "ParentID" = ' . $parent->ID : ''), + $oldFilter, '"LastEdited" DESC', null, null, diff --git a/code/controllers/RootURLController.php b/code/controllers/RootURLController.php index 31bf0177..16026033 100644 --- a/code/controllers/RootURLController.php +++ b/code/controllers/RootURLController.php @@ -29,11 +29,12 @@ class RootURLController extends Controller { */ static public function get_homepage_link() { if(!self::$cached_homepage_link) { - // TODO Move to 'homepagefordomain' module + // @todo Move to 'homepagefordomain' module if(class_exists('HomepageForDomainExtension')) { $host = str_replace('www.', null, $_SERVER['HTTP_HOST']); - $SQL_host = Convert::raw2sql($host); - $candidates = DataObject::get('SiteTree', "\"HomepageForDomain\" LIKE '%$SQL_host%'"); + $candidates = SiteTree::get()->where(array( + '"SiteTree"."HomepageForDomain" LIKE ?' => "%$host%" + )); if($candidates) foreach($candidates as $candidate) { if(preg_match('/(,|^) *' . preg_quote($host) . ' *(,|$)/', $candidate->HomepageForDomain)) { self::$cached_homepage_link = trim($candidate->RelativeLink(true), '/'); @@ -117,7 +118,7 @@ class RootURLController extends Controller { $this->pushCurrent(); $this->init(); - if(!DB::isActive() || !ClassInfo::hasTable('SiteTree')) { + if(!DB::is_active() || !ClassInfo::hasTable('SiteTree')) { $this->response = new SS_HTTPResponse(); $this->response->redirect(Director::absoluteBaseURL() . 'dev/build?returnURL=' . (isset($_GET['url']) ? urlencode($_GET['url']) : null)); return $this->response; diff --git a/code/controllers/SilverStripeNavigator.php b/code/controllers/SilverStripeNavigator.php index 5e1e089c..1265b21b 100644 --- a/code/controllers/SilverStripeNavigator.php +++ b/code/controllers/SilverStripeNavigator.php @@ -194,16 +194,12 @@ class SilverStripeNavigatorItem extends ViewableData { if(!isset($this->record->_cached_isArchived)) { $baseTable = ClassInfo::baseDataClass($this->record->class); - $currentDraft = Versioned::get_one_by_stage( - $baseTable, - 'Stage', - sprintf('"%s"."ID" = %d', $baseTable, $this->record->ID) - ); - $currentLive = Versioned::get_one_by_stage( - $baseTable, - 'Live', - sprintf('"%s"."ID" = %d', $baseTable, $this->record->ID) - ); + $currentDraft = Versioned::get_one_by_stage($baseTable, 'Stage', array( + "\"$baseTable\".\"ID\"" => $this->record->ID + )); + $currentLive = Versioned::get_one_by_stage($baseTable, 'Live', array( + "\"$baseTable\".\"ID\"" => $this->record->ID + )); $this->record->_cached_isArchived = ( (!$currentDraft || ($currentDraft && $this->record->Version != $currentDraft->Version)) @@ -306,11 +302,9 @@ class SilverStripeNavigatorItem_StageLink extends SilverStripeNavigatorItem { protected function getDraftPage() { $baseTable = ClassInfo::baseDataClass($this->record->class); - return Versioned::get_one_by_stage( - $baseTable, - 'Stage', - sprintf('"%s"."ID" = %d', $baseTable, $this->record->ID) - ); + return Versioned::get_one_by_stage($baseTable, 'Stage', array( + "\"$baseTable\".\"ID\"" => $this->record->ID + )); } } @@ -360,11 +354,9 @@ class SilverStripeNavigatorItem_LiveLink extends SilverStripeNavigatorItem { protected function getLivePage() { $baseTable = ClassInfo::baseDataClass($this->record->class); - return Versioned::get_one_by_stage( - $baseTable, - 'Live', - sprintf('"%s"."ID" = %d', $baseTable, $this->record->ID) - ); + return Versioned::get_one_by_stage($baseTable, 'Live', array( + "\"$baseTable\".\"ID\"" => $this->record->ID + )); } } diff --git a/code/forms/FolderUnusedAssetsField.php b/code/forms/FolderUnusedAssetsField.php index e174608f..fcb87289 100644 --- a/code/forms/FolderUnusedAssetsField.php +++ b/code/forms/FolderUnusedAssetsField.php @@ -4,6 +4,10 @@ * @subpackage filesystem */ class Folder_UnusedAssetsField extends CompositeField { + + /** + * @var Folder + */ protected $folder; public function __construct($folder) { @@ -39,10 +43,10 @@ class Folder_UnusedAssetsField extends CompositeField { /** - * Creates table for displaying unused files. - * - * @return GridField - */ + * Creates table for displaying unused files. + * + * @return GridField + */ protected function getAssetList() { $where = $this->folder->getUnusedFilesListFilter(); $files = File::get()->where($where); diff --git a/code/model/SiteTree.php b/code/model/SiteTree.php index aab7375c..4a92f277 100755 --- a/code/model/SiteTree.php +++ b/code/model/SiteTree.php @@ -328,22 +328,22 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid $link = RootURLController::get_homepage_link(); } - $parts = Convert::raw2sql(preg_split('|/+|', $link)); + $parts = preg_split('|/+|', $link); // Grab the initial root level page to traverse down from. $URLSegment = array_shift($parts); - $sitetree = DataObject::get_one ( - 'SiteTree', - "\"SiteTree\".\"URLSegment\" = '$URLSegment'" . ( - self::config()->nested_urls ? ' AND "SiteTree"."ParentID" = 0' : '' - ), - $cache - ); + $conditions = array('"SiteTree"."URLSegment"' => rawurlencode($URLSegment)); + if(self::config()->nested_urls) { + $conditions[] = array('"SiteTree"."ParentID"' => 0); + } + $sitetree = DataObject::get_one('SiteTree', $conditions, $cache); /// Fall back on a unique URLSegment for b/c. - if(!$sitetree + if( !$sitetree && self::config()->nested_urls - && $page = DataObject::get_one('SiteTree', "\"SiteTree\".\"URLSegment\" = '$URLSegment'", $cache) + && $page = DataObject::get_one('SiteTree', array( + '"SiteTree"."URLSegment"' => $URLSegment + ), $cache) ) { return $page; } @@ -364,9 +364,10 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid // Traverse down the remaining URL segments and grab the relevant SiteTree objects. foreach($parts as $segment) { - $next = DataObject::get_one ( - 'SiteTree', - "\"SiteTree\".\"URLSegment\" = '$segment' AND \"SiteTree\".\"ParentID\" = $sitetree->ID", + $next = DataObject::get_one('SiteTree', array( + '"SiteTree"."URLSegment"' => $segment, + '"SiteTree"."ParentID"' => $sitetree->ID + ), $cache ); @@ -440,11 +441,11 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid if ( !($page = DataObject::get_by_id('SiteTree', $arguments['id'])) // Get the current page by ID. && !($page = Versioned::get_latest_version('SiteTree', $arguments['id'])) // Attempt link to old version. - && !($page = DataObject::get_one('ErrorPage', '"ErrorPage"."ErrorCode" = \'404\'')) // Link to 404 page. + && !($page = DataObject::get_one('ErrorPage', array('"ErrorPage"."ErrorCode"' => 404))) // Link to 404 page directly. ) { return; // There were no suitable matches at all. } - + $link = Convert::raw2att($page->Link()); if($content) { @@ -536,7 +537,9 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid public function getAbsoluteLiveLink($includeStageEqualsLive = true) { $oldStage = Versioned::current_stage(); Versioned::reading_stage('Live'); - $live = Versioned::get_one_by_stage('SiteTree', 'Live', '"SiteTree"."ID" = ' . $this->ID); + $live = Versioned::get_one_by_stage('SiteTree', 'Live', array( + '"SiteTree"."ID"' => $this->ID + )); if($live) { $link = $live->AbsoluteLink(); if($includeStageEqualsLive) $link .= '?stage=Live'; @@ -785,8 +788,8 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid * @return SiteTree Parent of this page. */ public function getParent() { - if ($this->getField("ParentID")) { - return DataObject::get_one("SiteTree", "\"SiteTree\".\"ID\" = " . $this->getField("ParentID")); + if ($parentID = $this->getField("ParentID")) { + return DataObject::get_by_id("SiteTree", $parentID); } } @@ -1201,7 +1204,8 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid return $result; } - $SQL_idList = implode($ids, ", "); + // Placeholder for parameterised ID list + $idPlaceholders = DB::placeholders($ids); // if page can't be viewed, don't grant edit permissions // to do - implement can_view_multiple(), so this can be enabled @@ -1218,16 +1222,22 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid // Start by filling the array with the pages that actually exist $table = ($stage=='Stage') ? "SiteTree" : "SiteTree_$stage"; - $result = array_fill_keys( - ($ids) ? DB::query("SELECT \"ID\" FROM \"$table\" WHERE \"ID\" IN (".implode(", ", $ids).")")->column() : array(), - false - ); + if($ids) { + $idQuery = "SELECT \"ID\" FROM \"$table\" WHERE \"ID\" IN ($idPlaceholders)"; + $stageIds = DB::prepared_query($idQuery, $ids)->column(); + } else { + $stageIds = array(); + } + $result = array_fill_keys($stageIds, false); // Get the uninherited permissions $uninheritedPermissions = Versioned::get_by_stage("SiteTree", $stage) - ->where("(\"$typeField\" = 'LoggedInUsers' OR + ->where(array( + "(\"$typeField\" = 'LoggedInUsers' OR (\"$typeField\" = 'OnlyTheseUsers' AND \"$groupJoinTable\".\"SiteTreeID\" IS NOT NULL)) - AND \"SiteTree\".\"ID\" IN ($SQL_idList)") + AND \"SiteTree\".\"ID\" IN ($idPlaceholders)" + => $ids + )) ->leftJoin($groupJoinTable, "\"$groupJoinTable\".\"SiteTreeID\" = \"SiteTree\".\"ID\" AND \"$groupJoinTable\".\"GroupID\" IN ($SQL_groupList)"); if($uninheritedPermissions) { @@ -1236,8 +1246,11 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid } // Get permissions that are inherited - $potentiallyInherited = Versioned::get_by_stage("SiteTree", $stage, "\"$typeField\" = 'Inherit' - AND \"SiteTree\".\"ID\" IN ($SQL_idList)"); + $potentiallyInherited = Versioned::get_by_stage( + "SiteTree", + $stage, + array("\"$typeField\" = 'Inherit' AND \"SiteTree\".\"ID\" IN ($idPlaceholders)" => $ids) + ); if($potentiallyInherited) { // Group $potentiallyInherited by ParentID; we'll look at the permission of all those @@ -1323,10 +1336,12 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid // You can only delete pages that you can edit $editableIDs = array_keys(array_filter(self::can_edit_multiple($ids, $memberID))); if($editableIDs) { - $idList = implode(",", $editableIDs); // You can only delete pages whose children you can delete - $childRecords = DataObject::get("SiteTree", "\"ParentID\" IN ($idList)"); + $editablePlaceholders = DB::placeholders($editableIDs); + $childRecords = SiteTree::get()->where(array( + "\"SiteTree\".\"ParentID\" IN ($editablePlaceholders)" => $editableIDs + )); if($childRecords) { $children = $childRecords->map("ID", "ParentID"); @@ -1492,7 +1507,7 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid // schema migration // @todo Move to migration task once infrastructure is implemented if($this->class == 'SiteTree') { - $conn = DB::getConn(); + $conn = DB::get_schema(); // only execute command if fields haven't been renamed to _obsolete_ already by the task if(array_key_exists('Viewers', $conn->fieldList('SiteTree'))) { $task = new UpgradeSiteTreePermissionSchemaTask(); @@ -1510,7 +1525,10 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid // If Sort hasn't been set, make this page come after it's siblings if(!$this->Sort) { $parentID = ($this->ParentID) ? $this->ParentID : 0; - $this->Sort = DB::query("SELECT MAX(\"Sort\") + 1 FROM \"SiteTree\" WHERE \"ParentID\" = $parentID")->value(); + $this->Sort = DB::prepared_query( + "SELECT MAX(\"Sort\") + 1 FROM \"SiteTree\" WHERE \"ParentID\" = ?", + array($parentID) + )->value(); } // If there is no URLSegment set, generate one from Title @@ -1663,15 +1681,13 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid if(class_exists($this->URLSegment) && is_subclass_of($this->URLSegment, 'RequestHandler')) return false; } - $IDFilter = ($this->ID) ? "AND \"SiteTree\".\"ID\" <> $this->ID" : null; - $parentFilter = null; - + // Filters by url, id, and parent + $filter = array('"SiteTree"."URLSegment"' => $this->URLSegment); + if($this->ID) { + $filter['"SiteTree"."ID" <> ?'] = $this->ID; + } if(self::config()->nested_urls) { - if($this->ParentID) { - $parentFilter = " AND \"SiteTree\".\"ParentID\" = $this->ParentID"; - } else { - $parentFilter = ' AND "SiteTree"."ParentID" = 0'; - } + $filter['"SiteTree"."ParentID"'] = $this->ParentID ? $this->ParentID : 0; } $votes = array_filter( @@ -1682,11 +1698,9 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid return min($votes); } - $segment = Convert::raw2sql($this->URLSegment); - $existingPage = DataObject::get_one( - 'SiteTree', - "\"SiteTree\".\"URLSegment\" = '$segment' $IDFilter $parentFilter" - ); + // Check existence + $existingPage = DataObject::get_one('SiteTree', $filter); + if ($existingPage) return false; return !($existingPage); } @@ -1719,11 +1733,9 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid * @return string */ public function getStageURLSegment() { - $stageRecord = Versioned::get_one_by_stage( - 'SiteTree', - 'Stage', - "\"SiteTree\".\"ID\" = $this->ID" - ); + $stageRecord = Versioned::get_one_by_stage('SiteTree', 'Stage', array( + '"SiteTree"."ID"' => $this->ID + )); return ($stageRecord) ? $stageRecord->URLSegment : null; } @@ -1731,11 +1743,9 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid * @return string */ public function getLiveURLSegment() { - $liveRecord = Versioned::get_one_by_stage( - 'SiteTree', - 'Live', - "\"SiteTree\".\"ID\" = $this->ID" - ); + $liveRecord = Versioned::get_one_by_stage('SiteTree', 'Live', array( + '"SiteTree"."ID"' => $this->ID + )); return ($liveRecord) ? $liveRecord->URLSegment : null; } @@ -1748,7 +1758,10 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid // Update the content without actually creating a new version foreach(array("SiteTree_Live", "SiteTree") as $table) { // Published site - $published = DB::query("SELECT * FROM \"$table\" WHERE \"ID\" = $this->ID")->record(); + $published = DB::prepared_query( + "SELECT * FROM \"$table\" WHERE \"ID\" = ?", + array($this->ID) + )->record(); $origPublished = $published; foreach($fields as $fieldName => $fieldType) { @@ -1758,8 +1771,8 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid if(isset($published[$fieldName])) { $published[$fieldName] = str_replace($old, $new, $published[$fieldName], $numReplaced); if($numReplaced) { - DB::query("UPDATE \"$table\" SET \"$fieldName\" = '" - . Convert::raw2sql($published[$fieldName]) . "' WHERE \"ID\" = $this->ID"); + $query = sprintf('UPDATE "%s" SET "%s" = ? WHERE "ID" = ?', $table, $fieldName); + DB::prepared_query($query, array($published[$fieldName], $this->ID)); // Tell static caching to update itself if($table == 'SiteTree_Live') { @@ -1787,17 +1800,17 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid } // Content links - $items = new ArrayList(); + $items = new ArrayList(); - // We merge all into a regular SS_List, because DataList doesn't support merge - if($contentLinks = $this->BackLinkTracking()) { - $linkList = new ArrayList(); - foreach($contentLinks as $item) { - $item->DependentLinkType = 'Content link'; - $linkList->push($item); - } + // We merge all into a regular SS_List, because DataList doesn't support merge + if($contentLinks = $this->BackLinkTracking()) { + $linkList = new ArrayList(); + foreach($contentLinks as $item) { + $item->DependentLinkType = 'Content link'; + $linkList->push($item); + } $items->merge($linkList); - } + } // Virtual pages if($includeVirtuals) { @@ -1807,19 +1820,22 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid foreach($virtuals as $item) { $item->DependentLinkType = 'Virtual page'; $virtualList->push($item); - } + } $items->merge($virtualList); - } + } } // Redirector pages - $redirectors = DataObject::get("RedirectorPage", "\"RedirectorPage\".\"RedirectionType\" = 'Internal' AND \"LinkToID\" = $this->ID"); + $redirectors = RedirectorPage::get()->where(array( + '"RedirectorPage"."RedirectionType"' => 'Internal', + '"RedirectorPage"."LinkToID"' => $this->ID + )); if($redirectors) { $redirectorList = new ArrayList(); foreach($redirectors as $item) { $item->DependentLinkType = 'Redirector page'; $redirectorList->push($item); - } + } $items->merge($redirectorList); } @@ -1845,14 +1861,26 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid * Return all virtual pages that link to this page */ public function VirtualPages() { + + // Ignore new records if(!$this->ID) return null; + + // Check subsite virtual pages + // @todo Refactor out subsite module specific code if(class_exists('Subsite')) { - return Subsite::get_from_all_subsites('VirtualPage', "\"CopyContentFromID\" = " . (int)$this->ID); - } elseif(class_exists('VirtualPage')) { - return DataObject::get('VirtualPage', "\"CopyContentFromID\" = " . (int)$this->ID); - }else{ - return null; + return Subsite::get_from_all_subsites('VirtualPage', array( + '"VirtualPage"."CopyContentFromID"' => $this->ID + )); } + + // Check existing virtualpages + if(class_exists('VirtualPage')) { + return VirtualPage::get()->where(array( + '"VirtualPage"."CopyContentFromID"' => $this->ID + )); + } + + return null; } /** @@ -2099,9 +2127,9 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid ->setAttribute( 'data-placeholder', _t('SiteTree.GroupPlaceholder', 'Click to select group') + ) ) ) - ) ); $visibility->setTitle($this->fieldLabel('Visibility')); @@ -2235,7 +2263,9 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid $rootTabSet->addExtraClass('ss-ui-action-tabset action-menus'); // Render page information into the "more-options" drop-up, on the top. - $live = Versioned::get_one_by_stage('SiteTree', 'Live', "\"SiteTree\".\"ID\"='$this->ID'"); + $live = Versioned::get_one_by_stage('SiteTree', 'Live', array( + '"SiteTree"."ID"' => $this->ID + )); $moreOptions->push( new LiteralField('Information', $this->customise(array( @@ -2246,7 +2276,9 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid ); // "readonly"/viewing version that isn't the current version of the record - $stageOrLiveRecord = Versioned::get_one_by_stage($this->class, Versioned::current_stage(), sprintf('"SiteTree"."ID" = %d', $this->ID)); + $stageOrLiveRecord = Versioned::get_one_by_stage($this->class, Versioned::current_stage(), array( + '"SiteTree"."ID"' => $this->ID + )); if($stageOrLiveRecord && $stageOrLiveRecord->Version != $this->Version) { $moreOptions->push(FormAction::create('email', _t('CMSMain.EMAIL', 'Email'))); $moreOptions->push(FormAction::create('rollback', _t('CMSMain.ROLLBACK', 'Roll back to this version'))); @@ -2326,7 +2358,7 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid // Set up the initial state of the button to reflect the state of the underlying SiteTree object. if($this->stagesDiffer('Stage', 'Live')) { $publish->addExtraClass('ss-ui-alternate'); - } + } } $actions = new FieldList(array($majorActions, $rootTabSet)); @@ -2346,7 +2378,9 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid public function doPublish() { if (!$this->canPublish()) return false; - $original = Versioned::get_one_by_stage("SiteTree", "Live", "\"SiteTree\".\"ID\" = $this->ID"); + $original = Versioned::get_one_by_stage("SiteTree", "Live", array( + '"SiteTree"."ID"' => $this->ID + )); if(!$original) $original = new SiteTree(); // Handle activities undertaken by extensions @@ -2355,9 +2389,11 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid $this->write(); $this->publish("Stage", "Live"); - DB::query("UPDATE \"SiteTree_Live\" - SET \"Sort\" = (SELECT \"SiteTree\".\"Sort\" FROM \"SiteTree\" WHERE \"SiteTree_Live\".\"ID\" = \"SiteTree\".\"ID\") - WHERE EXISTS (SELECT \"SiteTree\".\"Sort\" FROM \"SiteTree\" WHERE \"SiteTree_Live\".\"ID\" = \"SiteTree\".\"ID\") AND \"ParentID\" = " . sprintf('%d', $this->ParentID) ); + DB::prepared_query('UPDATE "SiteTree_Live" + SET "Sort" = (SELECT "SiteTree"."Sort" FROM "SiteTree" WHERE "SiteTree_Live"."ID" = "SiteTree"."ID") + WHERE EXISTS (SELECT "SiteTree"."Sort" FROM "SiteTree" WHERE "SiteTree_Live"."ID" = "SiteTree"."ID") AND "ParentID" = ?', + array($this->ParentID) + ); // Publish any virtual pages that might need publishing $linkedPages = $this->VirtualPages(); @@ -2417,7 +2453,7 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid // If we're on the draft site, then we can update the status. // Otherwise, these lines will resurrect an inappropriate record - if(DB::query("SELECT \"ID\" FROM \"SiteTree\" WHERE \"ID\" = $this->ID")->value() + if(DB::prepared_query("SELECT \"ID\" FROM \"SiteTree\" WHERE \"ID\" = ?", array($this->ID))->value() && Versioned::current_stage() != 'Live') { $this->write(); } @@ -2455,10 +2491,10 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid public function doRestoreToStage() { // if no record can be found on draft stage (meaning it has been "deleted from draft" before), // create an empty record - if(!DB::query("SELECT \"ID\" FROM \"SiteTree\" WHERE \"ID\" = $this->ID")->value()) { - $conn = DB::getConn(); + if(!DB::prepared_query("SELECT \"ID\" FROM \"SiteTree\" WHERE \"ID\" = ?", array($this->ID))->value()) { + $conn = DB::get_conn(); if(method_exists($conn, 'allowPrimaryKeyEditing')) $conn->allowPrimaryKeyEditing('SiteTree', true); - DB::query("INSERT INTO \"SiteTree\" (\"ID\") VALUES ($this->ID)"); + DB::prepared_query("INSERT INTO \"SiteTree\" (\"ID\") VALUES (?)", array($this->ID)); if(method_exists($conn, 'allowPrimaryKeyEditing')) $conn->allowPrimaryKeyEditing('SiteTree', false); } @@ -2517,7 +2553,7 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid if($this->isNew()) return false; - return (DB::query("SELECT \"ID\" FROM \"SiteTree_Live\" WHERE \"ID\" = $this->ID")->value()) + return (DB::prepared_query("SELECT \"ID\" FROM \"SiteTree_Live\" WHERE \"ID\" = ?", array($this->ID))->value()) ? true : false; } @@ -2766,7 +2802,7 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid if(!$this->canEdit() && !$this->canAddChildren()) { if (!$this->canView()) { - $classes .= " disabled"; + $classes .= " disabled"; } else { $classes .= " edit-disabled"; } diff --git a/code/model/SiteTreeFileExtension.php b/code/model/SiteTreeFileExtension.php index 71c0fae2..0e7d6cb0 100644 --- a/code/model/SiteTreeFileExtension.php +++ b/code/model/SiteTreeFileExtension.php @@ -60,8 +60,8 @@ class SiteTreeFileExtension extends DataExtension { * Updates link tracking. */ public function onAfterDelete() { - // We query the explicit ID list, because BackLinkTracking will get modified after the stage - // site does its thing + // We query the explicit ID list, because BackLinkTracking will get modified after the stage + // site does its thing $brokenPageIDs = $this->owner->BackLinkTracking()->column("ID"); if($brokenPageIDs) { $origStage = Versioned::current_stage(); @@ -75,8 +75,8 @@ class SiteTreeFileExtension extends DataExtension { Versioned::reading_stage('Live'); $liveBrokenPages = DataObject::get('SiteTree')->byIDs($brokenPageIDs); foreach($liveBrokenPages as $brokenPage) { - $brokenPage->write(); - } + $brokenPage->write(); + } Versioned::reading_stage($origStage); } diff --git a/code/model/SiteTreeFolderExtension.php b/code/model/SiteTreeFolderExtension.php index 66a99e4a..1e190c13 100644 --- a/code/model/SiteTreeFolderExtension.php +++ b/code/model/SiteTreeFolderExtension.php @@ -1,11 +1,15 @@ CopyContentFromID")->value(); - $liveSourceVersion = DB::query("SELECT \"Version\" FROM \"SiteTree_Live\" WHERE \"ID\" = $this->CopyContentFromID")->value(); + $stageSourceVersion = DB::prepared_query( + 'SELECT "Version" FROM "SiteTree" WHERE "ID" = ?', + array($this->CopyContentFromID) + )->value(); + $liveSourceVersion = DB::prepared_query( + 'SELECT "Version" FROM "SiteTree_Live" WHERE "ID" = ?', + array($this->CopyContentFromID) + )->value(); // We're going to create a new VP record in SiteTree_versions because the published // version might not exist, unless we're publishing the latest version @@ -281,7 +287,8 @@ class VirtualPage extends Page { if($performCopyFrom && $this instanceof VirtualPage) { // This flush is needed because the get_one cache doesn't respect site version :-( singleton('SiteTree')->flushCache(); - $source = DataObject::get_one("SiteTree",sprintf('"SiteTree"."ID" = %d', $this->CopyContentFromID)); + // @todo Update get_one to support parameterised queries + $source = DataObject::get_by_id("SiteTree", $this->CopyContentFromID); // Leave the updating of image tracking until after write, in case its a new record $this->copyFrom($source, false); } @@ -318,15 +325,16 @@ class VirtualPage extends Page { // Note: *_versions records are left intact foreach(array('', 'Live') as $stage) { if($stage) $removedTable = "{$removedTable}_{$stage}"; - DB::query(sprintf('DELETE FROM "%s" WHERE "ID" = %d', $removedTable, $this->ID)); + DB::prepared_query("DELETE FROM \"$removedTable\" WHERE \"ID\" = ?", array($this->ID)); } - } + } // Also publish the change immediately to avoid inconsistent behaviour between // a non-virtual draft and a virtual live record (e.g. republishing the original record // shouldn't republish the - now unrelated - changes on the ex-VirtualPage draft). // Copies all stage fields to live as well. - $source = DataObject::get_one("SiteTree",sprintf('"SiteTree"."ID" = %d', $this->CopyContentFromID)); + // @todo Update get_one to support parameterised queries + $source = DataObject::get_by_id("SiteTree", $this->CopyContentFromID); $this->copyFrom($source); $this->publish('Stage', 'Live'); diff --git a/code/reports/BrokenLinksReport.php b/code/reports/BrokenLinksReport.php index 2a46dd22..10ba8a6c 100644 --- a/code/reports/BrokenLinksReport.php +++ b/code/reports/BrokenLinksReport.php @@ -29,8 +29,15 @@ class BrokenLinksReport extends SS_Report { $sort = ''; } } - if (!isset($_REQUEST['CheckSite']) || $params['CheckSite'] == 'Published') $ret = Versioned::get_by_stage('SiteTree', 'Live', '("SiteTree"."HasBrokenLink" = 1 OR "SiteTree"."HasBrokenFile" = 1)', $sort, $join, $limit); - else $ret = DataObject::get('SiteTree', '("SiteTree"."HasBrokenFile" = 1 OR "HasBrokenLink" = 1)', $sort, $join, $limit); + if (!isset($_REQUEST['CheckSite']) || $params['CheckSite'] == 'Published') { + $ret = Versioned::get_by_stage('SiteTree', 'Live', array( + '"SiteTree"."HasBrokenLink" = ? OR "SiteTree"."HasBrokenFile" = ?' => array(true, true) + ), $sort, $join, $limit); + } else { + $ret = DataObject::get('SiteTree', array( + '"SiteTree"."HasBrokenFile" = ? OR "SiteTree"."HasBrokenLink" = ?' => array(true, true) + ), $sort, $join, $limit); + } $returnSet = new ArrayList(); if ($ret) foreach($ret as $record) { diff --git a/code/search/SearchForm.php b/code/search/SearchForm.php index cbafee55..24b5939c 100644 --- a/code/search/SearchForm.php +++ b/code/search/SearchForm.php @@ -137,9 +137,9 @@ class SearchForm extends Form { $start = isset($_GET['start']) ? (int)$_GET['start'] : 0; if(strpos($keywords, '"') !== false || strpos($keywords, '+') !== false || strpos($keywords, '-') !== false || strpos($keywords, '*') !== false) { - $results = DB::getConn()->searchEngine($this->classesToSearch, $keywords, $start, $pageLength, "\"Relevance\" DESC", "", true); + $results = DB::get_conn()->searchEngine($this->classesToSearch, $keywords, $start, $pageLength, "\"Relevance\" DESC", "", true); } else { - $results = DB::getConn()->searchEngine($this->classesToSearch, $keywords, $start, $pageLength); + $results = DB::get_conn()->searchEngine($this->classesToSearch, $keywords, $start, $pageLength); } // filter by permission diff --git a/tasks/MigrateSiteTreeLinkingTask.php b/tasks/MigrateSiteTreeLinkingTask.php index 170c5661..e89d5d3e 100644 --- a/tasks/MigrateSiteTreeLinkingTask.php +++ b/tasks/MigrateSiteTreeLinkingTask.php @@ -18,7 +18,10 @@ class MigrateSiteTreeLinkingTask extends BuildTask { $linkedPages = new DataList('SiteTree'); $linkedPages = $linkedPages->innerJoin('SiteTree_LinkTracking', '"SiteTree_LinkTracking"."SiteTreeID" = "SiteTree"."ID"'); if($linkedPages) foreach($linkedPages as $page) { - $tracking = DB::query(sprintf('SELECT "ChildID", "FieldName" FROM "SiteTree_LinkTracking" WHERE "SiteTreeID" = %d', $page->ID))->map(); + $tracking = DB::prepared_query( + 'SELECT "ChildID", "FieldName" FROM "SiteTree_LinkTracking" WHERE "SiteTreeID" = ?', + array($page->ID) + )->map(); foreach($tracking as $childID => $fieldName) { $linked = DataObject::get_by_id('SiteTree', $childID); diff --git a/tasks/RemoveOrphanedPagesTask.php b/tasks/RemoveOrphanedPagesTask.php index c48f120e..5de582af 100644 --- a/tasks/RemoveOrphanedPagesTask.php +++ b/tasks/RemoveOrphanedPagesTask.php @@ -85,21 +85,16 @@ in the other stage:
if($orphans) foreach($orphans as $orphan) { $latestVersion = Versioned::get_latest_version($this->orphanedSearchClass, $orphan->ID); $latestAuthor = DataObject::get_by_id('Member', $latestVersion->AuthorID); + $orphanBaseClass = ClassInfo::baseDataClass($this->orphanedSearchClass); $stageRecord = Versioned::get_one_by_stage( $this->orphanedSearchClass, - 'Stage', - sprintf("\"%s\".\"ID\" = %d", - ClassInfo::baseDataClass($this->orphanedSearchClass), - $orphan->ID - ) + 'Stage', + array("\"$orphanBaseClass\".\"ID\"" => $orphan->ID) ); $liveRecord = Versioned::get_one_by_stage( $this->orphanedSearchClass, 'Live', - sprintf("\"%s\".\"ID\" = %d", - ClassInfo::baseDataClass($this->orphanedSearchClass), - $orphan->ID - ) + array("\"$orphanBaseClass\".\"ID\"" => $orphan->ID) ); $label = sprintf( '%s (#%d, Last Modified Date: %s, Last Modifier: %s, %s)', @@ -218,14 +213,12 @@ in the other stage:
protected function removeOrphans($orphanIDs) { $removedOrphans = array(); + $orphanBaseClass = ClassInfo::baseDataClass($this->orphanedSearchClass); foreach($orphanIDs as $id) { $stageRecord = Versioned::get_one_by_stage( $this->orphanedSearchClass, 'Stage', - sprintf("\"%s\".\"ID\" = %d", - ClassInfo::baseDataClass($this->orphanedSearchClass), - $id - ) + array("\"$orphanBaseClass\".\"ID\"" => $id) ); if($stageRecord) { $removedOrphans[$stageRecord->ID] = sprintf('Removed %s (#%d) from Stage', $stageRecord->Title, $stageRecord->ID); @@ -236,10 +229,7 @@ in the other stage:
$liveRecord = Versioned::get_one_by_stage( $this->orphanedSearchClass, 'Live', - sprintf("\"%s\".\"ID\" = %d", - ClassInfo::baseDataClass($this->orphanedSearchClass), - $id - ) + array("\"$orphanBaseClass\".\"ID\"" => $id) ); if($liveRecord) { $removedOrphans[$liveRecord->ID] = sprintf('Removed %s (#%d) from Live', $liveRecord->Title, $liveRecord->ID); @@ -265,14 +255,12 @@ in the other stage:
$holder->write(); $removedOrphans = array(); + $orphanBaseClass = ClassInfo::baseDataClass($this->orphanedSearchClass); foreach($orphanIDs as $id) { $stageRecord = Versioned::get_one_by_stage( $this->orphanedSearchClass, - 'Stage', - sprintf("\"%s\".\"ID\" = %d", - ClassInfo::baseDataClass($this->orphanedSearchClass), - $id - ) + 'Stage', + array("\"$orphanBaseClass\".\"ID\"" => $id) ); if($stageRecord) { $removedOrphans[$stageRecord->ID] = sprintf('Rebased %s (#%d)', $stageRecord->Title, $stageRecord->ID); @@ -286,11 +274,8 @@ in the other stage:
} $liveRecord = Versioned::get_one_by_stage( $this->orphanedSearchClass, - 'Live', - sprintf("\"%s\".\"ID\" = %d", - ClassInfo::baseDataClass($this->orphanedSearchClass), - $id - ) + 'Live', + array("\"$orphanBaseClass\".\"ID\"" => $id) ); if($liveRecord) { $removedOrphans[$liveRecord->ID] = sprintf('Rebased %s (#%d)', $liveRecord->Title, $liveRecord->ID); @@ -315,15 +300,19 @@ in the other stage:
* Gets all orphans from "Stage" and "Live" stages. * * @param string $class - * @param string $filter + * @param array $filter * @param string $sort * @param string $join * @param int|array $limit * @return SS_List */ - public function getOrphanedPages($class = 'SiteTree', $filter = '', $sort = null, $join = null, $limit = null) { - $filter .= ($filter) ? ' AND ' : ''; - $filter .= sprintf("\"%s\".\"ParentID\" != 0 AND \"Parents\".\"ID\" IS NULL", $class); + public function getOrphanedPages($class = 'SiteTree', $filter = array(), $sort = null, $join = null, $limit = null) { + // Alter condition + if(empty($filter)) $where = array(); + elseif(is_array($filter)) $where = $filter; + else $where = array($filter); + $where[] = array("\"$class\".\"ParentID\" != ?" => 0); + $where[] = '"Parents"."ID" IS NULL'; $orphans = new ArrayList(); foreach(array('Stage', 'Live') as $stage) { @@ -333,7 +322,7 @@ in the other stage:
$stageOrphans = Versioned::get_by_stage( $class, $stage, - $filter, + $where, $sort, null, $limit diff --git a/tasks/UpgradeSiteTreePermissionSchemaTask.php b/tasks/UpgradeSiteTreePermissionSchemaTask.php index ae770ada..3de12f93 100644 --- a/tasks/UpgradeSiteTreePermissionSchemaTask.php +++ b/tasks/UpgradeSiteTreePermissionSchemaTask.php @@ -22,8 +22,8 @@ class UpgradeSiteTreePermissionSchemaTask extends BuildTask { public function run($request) { // transfer values for changed column name foreach(array('SiteTree','SiteTree_Live','SiteTree_versions') as $table) { - DB::query("UPDATE \"{$table}\" SET \"CanViewType\" = 'Viewers';"); - DB::query("UPDATE \"{$table}\" SET \"CanEditType\" = 'Editors';"); + DB::prepared_query("UPDATE \"{$table}\" SET \"CanViewType\" = ?", array('Viewers')); + DB::prepared_query("UPDATE \"{$table}\" SET \"CanEditType\" = ?", array('Editors')); } //Debug::message('Moved SiteTree->Viewers to SiteTree->CanViewType'); //Debug::message('Moved SiteTree->Editors to SiteTree->CanEditType'); @@ -44,7 +44,7 @@ class UpgradeSiteTreePermissionSchemaTask extends BuildTask { // rename legacy columns foreach(array('SiteTree','SiteTree_Live','SiteTree_versions') as $table) { foreach(array('Viewers','Editors','ViewersGroup','EditorsGroup') as $field) { - DB::getConn()->dontRequireField($table, $field); + DB::get_conn()->dontRequireField($table, $field); } } } diff --git a/tests/controller/CMSMainTest.php b/tests/controller/CMSMainTest.php index 644cc858..7355cc25 100644 --- a/tests/controller/CMSMainTest.php +++ b/tests/controller/CMSMainTest.php @@ -92,9 +92,9 @@ class CMSMainTest extends FunctionalTest { // Get the latest version of the redirector page $pageID = $this->idFromFixture('RedirectorPage', 'page5'); - $latestID = DB::query('select max("Version") from "RedirectorPage_versions" where "RecordID"=' . $pageID)->value(); - $dsCount = DB::query('select count("Version") from "RedirectorPage_versions" where "RecordID"=' . $pageID . ' and "Version"=' . $latestID)->value(); - $this->assertEquals(1, $dsCount, "Published page has no duplicate version records: it has " . $dsCount . " for version " . $latestID); + $latestID = DB::prepared_query('select max("Version") from "RedirectorPage_versions" where "RecordID" = ?', array($pageID))->value(); + $dsCount = DB::prepared_query('select count("Version") from "RedirectorPage_versions" where "RecordID" = ? and "Version"= ?', array($pageID, $latestID))->value(); + $this->assertEquals(1, $dsCount, "Published page has no duplicate version records: it has " . $dsCount . " for version " . $latestID); $this->session()->clear('loggedInAs'); @@ -191,7 +191,9 @@ class CMSMainTest extends FunctionalTest { $response = $this->get('admin/pages/edit/show/' . $pageID); - $livePage = Versioned::get_one_by_stage("SiteTree", "Live", "\"SiteTree\".\"ID\" = $pageID"); + $livePage = Versioned::get_one_by_stage("SiteTree", "Live", array( + '"SiteTree"."ID"' => $pageID + )); $this->assertInstanceOf('SiteTree', $livePage); $this->assertTrue($livePage->canDelete()); diff --git a/tests/controller/CMSSiteTreeFilterTest.php b/tests/controller/CMSSiteTreeFilterTest.php index e364fcd3..adeb571d 100644 --- a/tests/controller/CMSSiteTreeFilterTest.php +++ b/tests/controller/CMSSiteTreeFilterTest.php @@ -82,7 +82,7 @@ class CMSSiteTreeFilterTest extends SapphireTest { $deletedPage = Versioned::get_one_by_stage( 'SiteTree', 'Live', - sprintf('"SiteTree_Live"."ID" = %d', $deletedPageID) + array('"SiteTree_Live"."ID"' => $deletedPageID) ); $f = new CMSSiteTreeFilter_DeletedPages(array('Term' => 'Page')); diff --git a/tests/model/FileLinkTrackingTest.php b/tests/model/FileLinkTrackingTest.php index 419af896..14572443 100644 --- a/tests/model/FileLinkTrackingTest.php +++ b/tests/model/FileLinkTrackingTest.php @@ -32,16 +32,16 @@ class FileLinkTrackingTest extends SapphireTest { $page = $this->objFromFixture('Page', 'page1'); $this->assertTrue($page->doPublish()); $this->assertContains('ID")->value()); + DB::prepared_query("SELECT \"Content\" FROM \"SiteTree_Live\" WHERE \"ID\" = ?", array($page->ID))->value()); $file = $this->objFromFixture('File', 'file1'); $file->Name = 'renamed-test-file.pdf'; $file->write(); $this->assertContains('ID")->value()); + DB::prepared_query("SELECT \"Content\" FROM \"SiteTree\" WHERE \"ID\" = ?", array($page->ID))->value()); $this->assertContains('ID")->value()); + DB::prepared_query("SELECT \"Content\" FROM \"SiteTree_Live\" WHERE \"ID\" = ?", array($page->ID))->value()); } public function testFileLinkRewritingOnVirtualPages() { @@ -62,9 +62,9 @@ class FileLinkTrackingTest extends SapphireTest { // Verify that the draft and publish virtual pages both have the corrected link $this->assertContains('ID")->value()); + DB::prepared_query("SELECT \"Content\" FROM \"SiteTree\" WHERE \"ID\" = ?", array($svp->ID))->value()); $this->assertContains('ID")->value()); + DB::prepared_query("SELECT \"Content\" FROM \"SiteTree_Live\" WHERE \"ID\" = ?", array($svp->ID))->value()); } public function testLinkRewritingOnAPublishedPageDoesntMakeItEditedOnDraft() { @@ -90,7 +90,7 @@ class FileLinkTrackingTest extends SapphireTest { $page = $this->objFromFixture('Page', 'page1'); $this->assertTrue($page->doPublish()); $this->assertContains('ID")->value()); + DB::prepared_query("SELECT \"Content\" FROM \"SiteTree_Live\" WHERE \"ID\" = ?", array($page->ID))->value()); // Rename the file twice $file = $this->objFromFixture('File', 'file1'); @@ -105,9 +105,9 @@ class FileLinkTrackingTest extends SapphireTest { // Confirm that the correct image is shown in both the draft and live site $this->assertContains('ID")->value()); + DB::prepared_query("SELECT \"Content\" FROM \"SiteTree\" WHERE \"ID\" = ?", array($page->ID))->value()); $this->assertContains('ID")->value()); + DB::prepared_query("SELECT \"Content\" FROM \"SiteTree_Live\" WHERE \"ID\" = ?", array($page->ID))->value()); } } diff --git a/tests/model/SiteTreeTest.php b/tests/model/SiteTreeTest.php index 5b9a940e..da27bcd3 100644 --- a/tests/model/SiteTreeTest.php +++ b/tests/model/SiteTreeTest.php @@ -22,7 +22,7 @@ class SiteTreeTest extends SapphireTest { ); public function testCreateDefaultpages() { - $remove = DataObject::get('SiteTree'); + $remove = SiteTree::get(); if($remove) foreach($remove as $page) $page->delete(); // Make sure the table is empty $this->assertEquals(DB::query('SELECT COUNT("ID") FROM "SiteTree"')->value(), 0); @@ -104,9 +104,9 @@ class SiteTreeTest extends SapphireTest { public function testParentNodeCachedInMemory() { $parent = new SiteTree(); - $parent->Title = 'Section Title'; - $child = new SiteTree(); - $child->Title = 'Page Title'; + $parent->Title = 'Section Title'; + $child = new SiteTree(); + $child->Title = 'Page Title'; $child->setParent($parent); $this->assertInstanceOf("SiteTree", $child->Parent); @@ -136,14 +136,16 @@ class SiteTreeTest extends SapphireTest { $oldMode = Versioned::get_reading_mode(); Versioned::reading_stage('Live'); - $checkSiteTree = DataObject::get_one("SiteTree", "\"SiteTree\".\"URLSegment\" = 'get-one-test-page'"); + $checkSiteTree = DataObject::get_one("SiteTree", array( + '"SiteTree"."URLSegment"' => 'get-one-test-page' + )); $this->assertEquals("V1", $checkSiteTree->Title); Versioned::set_reading_mode($oldMode); } public function testChidrenOfRootAreTopLevelPages() { - $pages = DataObject::get("SiteTree"); + $pages = SiteTree::get(); foreach($pages as $page) $page->publish('Stage', 'Live'); unset($pages); @@ -426,7 +428,9 @@ class SiteTreeTest extends SapphireTest { public function testReadArchiveDate() { $date = '2009-07-02 14:05:07'; Versioned::reading_archived_date($date); - DataObject::get('SiteTree', "\"SiteTree\".\"ParentID\" = 0"); + SiteTree::get()->where(array( + '"SiteTree"."ParentID"' => 0 + )); Versioned::reading_archived_date(null); $this->assertEquals( Versioned::get_reading_mode(), @@ -619,7 +623,9 @@ class SiteTreeTest extends SapphireTest { Director::set_current_page($aboutPage); $this->assertTrue ( - DataObject::get_one('SiteTree', '"Title" = \'About Us\'')->isCurrent(), + DataObject::get_one('SiteTree', array( + '"SiteTree"."Title"' => 'About Us' + ))->isCurrent(), 'Assert that isCurrent works on another instance with the same ID.' ); diff --git a/tests/model/VirtualPageTest.php b/tests/model/VirtualPageTest.php index aa6bd301..5b61e2c0 100644 --- a/tests/model/VirtualPageTest.php +++ b/tests/model/VirtualPageTest.php @@ -314,7 +314,7 @@ class VirtualPageTest extends SapphireTest { // Unpublish the source page, confirm that the virtual page has also been unpublished $p->doUnpublish(); - // The draft VP still has the CopyContentFromID link + // The draft VP still has the CopyContentFromID link $vp->flushCache(); $vp = DataObject::get_by_id('SiteTree', $vp->ID); $this->assertEquals($p->ID, $vp->CopyContentFromID); diff --git a/tests/search/SearchFormTest.php b/tests/search/SearchFormTest.php index 9a3a42b6..96d38689 100644 --- a/tests/search/SearchFormTest.php +++ b/tests/search/SearchFormTest.php @@ -19,8 +19,8 @@ class ZZZSearchFormTest extends FunctionalTest { protected $mockController; public function waitUntilIndexingFinished() { - $db = DB::getConn(); - if (method_exists($db, 'waitUntilIndexingFinished')) DB::getConn()->waitUntilIndexingFinished(); + $schema = DB::get_schema(); + if (method_exists($schema, 'waitUntilIndexingFinished')) $schema->waitUntilIndexingFinished(); } public function setUpOnce() { @@ -46,7 +46,7 @@ class ZZZSearchFormTest extends FunctionalTest { * @return Boolean */ protected function checkFulltextSupport() { - $conn = DB::getConn(); + $conn = DB::get_conn(); if(class_exists('MSSQLDatabase') && $conn instanceof MSSQLDatabase) { $supports = $conn->fullTextEnabled(); } else { @@ -231,7 +231,7 @@ class ZZZSearchFormTest extends FunctionalTest { public function testSearchTitleAndContentWithSpecialCharacters() { if(!$this->checkFulltextSupport()) return; - if(class_exists('PostgreSQLDatabase') && DB::getConn() instanceof PostgreSQLDatabase) { + if(class_exists('PostgreSQLDatabase') && DB::get_conn() instanceof PostgreSQLDatabase) { $this->markTestSkipped("PostgreSQLDatabase doesn't support entity-encoded searches"); }