/** * Instantiate a search page, should one not exist. */ public function requireDefaultRecords() { parent::requireDefaultRecords(); $mode = Versioned::get_reading_mode(); Versioned::reading_stage('Stage'); // Determine whether pages should be created. if (self::config()->create_default_pages) { // Determine whether an extensible search page already exists. if (!ExtensibleSearchPage::get()->first()) { // Instantiate an extensible search page. $page = ExtensibleSearchPage::create(); $page->Title = 'Search Page'; $page->write(); DB::alteration_message('"Default" Extensible Search Page', 'created'); } } else { if (ClassInfo::exists('Multisites')) { foreach (Site::get() as $site) { // Determine whether an extensible search page already exists. if (!ExtensibleSearchPage::get()->filter('SiteID', $site->ID)->first()) { // Instantiate an extensible search page. $page = ExtensibleSearchPage::create(); $page->ParentID = $site->ID; $page->Title = 'Search Page'; $page->write(); DB::alteration_message("\"{$site->Title}\" Extensible Search Page", 'created'); } } } } Versioned::set_reading_mode($mode); }
/** * Perform migration * * @param string $base Absolute base path (parent of assets folder). Will default to BASE_PATH * @return int Number of files successfully migrated */ public function run($base = null) { if (empty($base)) { $base = BASE_PATH; } // Check if the File dataobject has a "Filename" field. // If not, cannot migrate if (!DB::get_schema()->hasField('File', 'Filename')) { return 0; } // Set max time and memory limit increase_time_limit_to(); increase_memory_limit_to(); // Loop over all files $count = 0; $originalState = \Versioned::get_reading_mode(); \Versioned::reading_stage('Stage'); $filenameMap = $this->getFilenameArray(); foreach ($this->getFileQuery() as $file) { // Get the name of the file to import $filename = $filenameMap[$file->ID]; $success = $this->migrateFile($base, $file, $filename); if ($success) { $count++; } } \Versioned::set_reading_mode($originalState); return $count; }
public function tearDown() { AssetStoreTest_SpyStore::reset(); if ($this->oldReadingMode) { Versioned::set_reading_mode($this->oldReadingMode); } parent::tearDown(); }
public function provideGridSheetData($modelClass) { if (self::ModelClass == $modelClass) { $mode = static::own_config('products_reading_mode'); Versioned::set_reading_mode($mode); $products = Product::get(); return $products; } }
/** * Returns an array with 2 elements, one with a list of Page on the site (and all subsites if * applicable) and another with files. * * @return array */ public function sourceRecords() { if (class_exists('Subsite') && Subsite::get()->count() > 0) { $origMode = Versioned::get_reading_mode(); Versioned::set_reading_mode('Stage.Stage'); $items = array('Pages' => Subsite::get_from_all_subsites('SiteTree'), 'Files' => Subsite::get_from_all_subsites('File')); Versioned::set_reading_mode($origMode); return $items; } else { return array('Pages' => Versioned::get_by_stage('SiteTree', 'Stage'), 'Files' => File::get()); } }
/** * * @return DataList */ protected function getAllLivePages($subsiteID = 0) { ini_set('memory_limit', '200M'); $oldMode = Versioned::get_reading_mode(); if (class_exists('Subsite')) { Subsite::disable_subsite_filter(true); } Versioned::reading_stage('Live'); $pages = DataObject::get("SiteTree"); Versioned::set_reading_mode($oldMode); if (class_exists('Subsite')) { return $pages->filter(array('SubsiteID' => $subsiteID)); } return $pages; }
/** * @param SS_HTTPRequest $request * * @return string|HTMLText */ public function preview(SS_HTTPRequest $request) { $key = $request->param('Key'); $token = $request->param('Token'); /** * @var ShareToken $shareToken */ $shareToken = ShareToken::get()->filter('token', $token)->first(); if (!$shareToken) { return $this->errorPage(); } $page = Versioned::get_one_by_stage('SiteTree', 'Stage', sprintf('"SiteTree"."ID" = \'%d\'', $shareToken->PageID)); $latest = Versioned::get_latest_version('SiteTree', $shareToken->PageID); $controller = $this->getControllerFor($page); if (!$shareToken->isExpired() && $page->generateKey($shareToken->Token) === $key) { Requirements::css(SHAREDRAFTCONTENT_DIR . '/css/top-bar.css'); // Temporarily un-secure the draft site and switch to draft $oldSecured = Session::get('unsecuredDraftSite'); $oldMode = Versioned::get_reading_mode(); $restore = function () use($oldSecured, $oldMode) { Session::set('unsecuredDraftSite', $oldSecured); Versioned::set_reading_mode($oldMode); }; // Process page inside an unsecured draft container try { Session::set('unsecuredDraftSite', true); Versioned::reading_stage('Stage'); // Create mock request; Simplify request to single top level reqest $pageRequest = new SS_HTTPRequest('GET', $page->URLSegment); $pageRequest->match('$URLSegment//$Action/$ID/$OtherID', true); $rendered = $controller->handleRequest($pageRequest, $this->model); // Render draft heading $data = new ArrayData(array('Page' => $page, 'Latest' => $latest)); $include = (string) $data->renderWith('Includes/TopBar'); } catch (Exception $ex) { $restore(); throw $ex; } $restore(); return str_replace('</body>', $include . '</body>', (string) $rendered->getBody()); } else { return $this->errorPage(); } }
public function doSavePost($data, $form) { $post = false; if (isset($data['ID']) && $data['ID']) { $post = BlogPost::get()->byID($data['ID']); } if (!$post) { $post = BlogPost::create(); } $form->saveInto($post); $post->ParentID = $this->owner->ID; $this->owner->extend("onBeforeSavePost", $blogentry); $oldMode = Versioned::get_reading_mode(); Versioned::reading_stage('Stage'); $post->write(); $post->publish("Stage", "Live"); Versioned::set_reading_mode($oldMode); $this->owner->extend("onAfterSavePost", $post); $this->owner->redirect($this->owner->Link()); }
/** * Update the searchable content tagging for a specific fusion tag. * * @parameter <{FUSION_TAG_ID}> integer */ public function updateTagging($fusionID) { // Determine any data objects with the tagging extension. $classes = ClassInfo::subclassesFor('DataObject'); unset($classes['DataObject']); $configuration = Config::inst(); foreach ($classes as $class) { // Determine the specific data object extensions. $extensions = $configuration->get($class, 'extensions', Config::UNINHERITED); if (is_array($extensions) && in_array('TaggingExtension', $extensions)) { // Determine whether this fusion tag is being used. $mode = Versioned::get_reading_mode(); Versioned::reading_stage('Stage'); $objects = $class::get()->filter('FusionTags.ID', $fusionID); // Update the searchable content tagging for these data objects. if ($class::has_extension($class, 'Versioned')) { // These data objects are versioned. foreach ($objects as $object) { // Update the staging version. $object->writeWithoutVersion(); } Versioned::reading_stage('Live'); $objects = $class::get()->filter('FusionTags.ID', $fusionID); foreach ($objects as $object) { // Update the live version. $object->writeWithoutVersion(); } } else { // These data objects are not versioned. foreach ($objects as $object) { $object->write(); } } Versioned::set_reading_mode($mode); } } }
/** * @return DataObject */ static function get_version($class, $id, $version) { $oldMode = Versioned::get_reading_mode(); Versioned::set_reading_mode(''); $baseTable = ClassInfo::baseDataClass($class); $query = singleton($class)->buildVersionSQL("\"{$baseTable}\".\"RecordID\" = {$id} AND \"{$baseTable}\".\"Version\" = {$version}"); $record = $query->execute()->record(); $className = $record['ClassName']; if (!$className) { Debug::show($query->sql()); Debug::show($record); user_error("Versioned::get_version: Couldn't get {$class}.{$id}, version {$version}", E_USER_ERROR); } Versioned::set_reading_mode($oldMode); return new $className($record); }
/** * Build the database with default records, see {@link DataObject->requireDefaultRecords()}. */ public function requireDefaultRecords() { $dbAdmin = new DatabaseAdmin(); Versioned::set_reading_mode(''); $dbAdmin->doBuild(true, true); }
public function run($request) { increase_time_limit_to(); $type = Convert::raw2sql($request->getVar('type')); if ($type) { $this->types[] = $type; } elseif (!$this->types) { foreach (ClassInfo::subclassesFor('DataObject') as $class) { if ($class::has_extension('SolrIndexable')) { $this->types[] = $class; } } } $search = singleton('SolrSearchService'); if (isset($_GET['delete_all'])) { $search->getSolr()->deleteByQuery('*:*'); $search->getSolr()->commit(); } $count = 0; foreach ($this->types as $type) { $search->getSolr()->deleteByQuery('ClassNameHierarchy_ms:' . $type); $search->getSolr()->commit(); if (ClassInfo::exists('QueuedJob') && !isset($_GET['direct'])) { $job = new SolrReindexJob($type); $svc = singleton('QueuedJobService'); $svc->queueJob($job); $this->log("Reindexing job for {$type} has been queued"); } else { $mode = Versioned::get_reading_mode(); Versioned::reading_stage('Stage'); // get the holders first, see if we have any that AREN'T in the root (ie we've already partitioned everything...) $pages = $type::get(); $pages = $pages->filter(array('ClassName' => $type)); /* @var $search SolrSearchService */ $this->log("------------------------------"); $this->log("Start reindexing job for {$type} (Count: " . $pages->count() . "):"); $this->log("------------------------------"); foreach ($pages as $page) { // Make sure the current page is not orphaned. if ($page->ParentID > 0) { $parent = $page->getParent(); if (is_null($parent) || $parent === false) { continue; } } // Appropriately index the current page, taking versioning into account. if ($page->hasExtension('Versioned')) { $search->index($page, 'Stage'); $baseTable = $page->baseTable(); $live = Versioned::get_one_by_stage($page->ClassName, 'Live', "\"{$baseTable}\".\"ID\" = {$page->ID}"); if ($live) { $search->index($live, 'Live'); $this->log("Reindexed Live version of {$live->Title}"); } $this->log("Reindexed (#{$page->ID}) {$page->Title}"); $count++; } else { $search->index($page); $this->log("Reindexed {$type} ID#{$page->ID}"); $count++; } } Versioned::set_reading_mode($mode); } } $this->log("------------------------------"); $this->log("Reindex complete, {$count} objects re-indexed"); $this->log("------------------------------"); }
/** * Publish this page. * * @uses SiteTreeDecorator->onBeforePublish() * @uses SiteTreeDecorator->onAfterPublish() */ function doPublish() { if (!$this->canPublish()) { return false; } $original = Versioned::get_one_by_stage("SiteTree", "Live", "\"SiteTree\".\"ID\" = {$this->ID}"); if (!$original) { $original = new SiteTree(); } // Handle activities undertaken by decorators $this->invokeWithExtensions('onBeforePublish', $original); $this->Status = "Published"; //$this->PublishedByID = Member::currentUser()->ID; $this->write(); $this->publish("Stage", "Live"); DB::query("UPDATE \"SiteTree_Live\"\n\t\t\tSET \"Sort\" = (SELECT \"SiteTree\".\"Sort\" FROM \"SiteTree\" WHERE \"SiteTree_Live\".\"ID\" = \"SiteTree\".\"ID\")\n\t\t\tWHERE EXISTS (SELECT \"SiteTree\".\"Sort\" FROM \"SiteTree\" WHERE \"SiteTree_Live\".\"ID\" = \"SiteTree\".\"ID\") AND \"ParentID\" = " . sprintf('%d', $this->ParentID)); // Publish any virtual pages that might need publishing $linkedPages = $this->VirtualPages(); if ($linkedPages) { foreach ($linkedPages as $page) { $page->copyFrom($page->CopyContentFrom()); $page->write(); if ($page->ExistsOnLive) { $page->doPublish(); } } } // Need to update pages linking to this one as no longer broken, on the live site $origMode = Versioned::get_reading_mode(); Versioned::reading_stage('Live'); foreach ($this->DependentPages(false) as $page) { // $page->write() calls syncLinkTracking, which does all the hard work for us. $page->write(); } Versioned::set_reading_mode($origMode); // Check to write CMS homepage map. $usingStaticPublishing = false; foreach (ClassInfo::subclassesFor('StaticPublisher') as $class) { if ($this->hasExtension($class)) { $usingStaticPublishing = true; } } // NOTE: if you change the path here, you must also change it in sapphire/static-main.php if (self::$write_homepage_map) { if ($usingStaticPublishing && ($map = SiteTree::generate_homepage_domain_map())) { @file_put_contents(BASE_PATH . '/' . ASSETS_DIR . '/_homepage-map.php', "<?php\n\$homepageMap = " . var_export($map, true) . "; ?>"); } else { if (file_exists(BASE_PATH . '/' . ASSETS_DIR . '/_homepage-map.php')) { unlink(BASE_PATH . '/' . ASSETS_DIR . '/_homepage-map.php'); } } } // Handle activities undertaken by decorators $this->invokeWithExtensions('onAfterPublish', $original); return true; }
public function testArchiveVersion() { // In 2005 this file was created SS_Datetime::set_mock_now('2005-01-01 00:00:00'); $testPage = new VersionedTest_Subclass(); $testPage->Title = 'Archived page'; $testPage->Content = 'This is the content from 2005'; $testPage->ExtraField = '2005'; $testPage->write(); // In 2007 we updated it SS_Datetime::set_mock_now('2007-01-01 00:00:00'); $testPage->Content = "It's 2007 already!"; $testPage->ExtraField = '2007'; $testPage->write(); // In 2009 we updated it again SS_Datetime::set_mock_now('2009-01-01 00:00:00'); $testPage->Content = "I'm enjoying 2009"; $testPage->ExtraField = '2009'; $testPage->write(); // End mock, back to the present day:) SS_Datetime::clear_mock_now(); // Test 1 - 2006 Content singleton('VersionedTest_Subclass')->flushCache(true); Versioned::set_reading_mode('Archive.2006-01-01 00:00:00'); $testPage2006 = DataObject::get('VersionedTest_Subclass')->filter(array('Title' => 'Archived page'))->first(); $this->assertInstanceOf("VersionedTest_Subclass", $testPage2006); $this->assertEquals("2005", $testPage2006->ExtraField); $this->assertEquals("This is the content from 2005", $testPage2006->Content); // Test 2 - 2008 Content singleton('VersionedTest_Subclass')->flushCache(true); Versioned::set_reading_mode('Archive.2008-01-01 00:00:00'); $testPage2008 = DataObject::get('VersionedTest_Subclass')->filter(array('Title' => 'Archived page'))->first(); $this->assertInstanceOf("VersionedTest_Subclass", $testPage2008); $this->assertEquals("2007", $testPage2008->ExtraField); $this->assertEquals("It's 2007 already!", $testPage2008->Content); // Test 3 - Today singleton('VersionedTest_Subclass')->flushCache(true); Versioned::set_reading_mode('Stage.Stage'); $testPageCurrent = DataObject::get('VersionedTest_Subclass')->filter(array('Title' => 'Archived page'))->first(); $this->assertInstanceOf("VersionedTest_Subclass", $testPageCurrent); $this->assertEquals("2009", $testPageCurrent->ExtraField); $this->assertEquals("I'm enjoying 2009", $testPageCurrent->Content); }
/** * * @return DataList */ protected function getAllLivePages() { ini_set('memory_limit', '512M'); $oldMode = Versioned::get_reading_mode(); if (class_exists('Subsite')) { Subsite::disable_subsite_filter(true); } if (class_exists('Translatable')) { Translatable::disable_locale_filter(); } Versioned::reading_stage('Live'); $pages = DataObject::get("SiteTree"); Versioned::set_reading_mode($oldMode); return $pages; }
public function tearDown() { Versioned::set_reading_mode($this->oldMode); Config::unnest(); parent::tearDown(); }
/** * Return a dataobject based on the `id` and `tree_class`. * * @param int $id * @return DataObject */ public function getRecord($id) { $treeClass = $this->stat('tree_class'); $record = DataObject::get_one($treeClass, "\"{$treeClass}\".\"ID\" = {$id}"); // Then, try getting a record from the live site if (!$record) { Versioned::reading_stage('Live'); singleton($treeClass)->flushCache(); $record = DataObject::get_one($treeClass, "\"{$treeClass}\".\"ID\" = {$id}"); if ($record) { Versioned::set_reading_mode(''); } } // Then, try getting a deleted record if (!$record) { $record = Versioned::get_latest_version($treeClass, $id); } return $record; }
/** * Test that orphaned pages are handled correctly */ public function testOrphanedPages() { $origStage = Versioned::get_reading_mode(); // Setup user who can view draft content, but lacks cms permission. // To users such as this, orphaned pages should be inaccessible. canView for these pages is only // necessary for admin / cms users, who require this permission to edit / rearrange these pages. $permission = new Permission(); $permission->Code = 'VIEW_DRAFT_CONTENT'; $group = new Group(array('Title' => 'Staging Users')); $group->write(); $group->Permissions()->add($permission); $member = new Member(); $member->Email = '*****@*****.**'; $member->write(); $member->Groups()->add($group); // both pages are viewable in stage Versioned::reading_stage('Stage'); $about = $this->objFromFixture('Page', 'about'); $staff = $this->objFromFixture('Page', 'staff'); $this->assertFalse($about->isOrphaned()); $this->assertFalse($staff->isOrphaned()); $this->assertTrue($about->canView($member)); $this->assertTrue($staff->canView($member)); // Publishing only the child page to live should orphan the live record, but not the staging one $staff->publish('Stage', 'Live'); $this->assertFalse($staff->isOrphaned()); $this->assertTrue($staff->canView($member)); Versioned::reading_stage('Live'); $staff = $this->objFromFixture('Page', 'staff'); // Live copy of page $this->assertTrue($staff->isOrphaned()); // because parent isn't published $this->assertFalse($staff->canView($member)); // Publishing the parent page should restore visibility Versioned::reading_stage('Stage'); $about = $this->objFromFixture('Page', 'about'); $about->publish('Stage', 'Live'); Versioned::reading_stage('Live'); $staff = $this->objFromFixture('Page', 'staff'); $this->assertFalse($staff->isOrphaned()); $this->assertTrue($staff->canView($member)); // Removing staging page should not prevent live page being visible $about->deleteFromStage('Stage'); $staff->deleteFromStage('Stage'); $staff = $this->objFromFixture('Page', 'staff'); $this->assertFalse($staff->isOrphaned()); $this->assertTrue($staff->canView($member)); // Cleanup Versioned::set_reading_mode($origStage); }
/** * * Physically runs the task which - dependent on QueuedJobs being installed and * not skipped via script params - will queue-up chunks of pages to be cached, * or just attempt to cache call objects at once. * * @param SS_HTTPRequest $request * @return void */ public function run($request) { // Increase memory to max-allowable CacheableConfig::configure_memory_limit(); $startTime = time(); $skipQueue = $request->getVar('SkipQueue'); $currentStage = Versioned::current_stage(); /* * Restrict cache rebuild to the given stage - useful for debugging or * "Poor Man's" chunking. */ if ($paramStage = $request->getVar('Stage')) { $stage_mode_mapping = array(ucfirst($paramStage) => strtolower($paramStage)); // All stages } else { $stage_mode_mapping = array("Stage" => "stage", "Live" => "live"); } $canQueue = interface_exists('QueuedJob'); $siteConfigs = DataObject::get('SiteConfig'); foreach ($stage_mode_mapping as $stage => $mode) { Versioned::set_reading_mode('Stage.' . $stage); if (class_exists('Subsite')) { Subsite::disable_subsite_filter(true); Config::inst()->update("CacheableSiteConfig", 'cacheable_fields', array('SubsiteID')); Config::inst()->update("CacheableSiteTree", 'cacheable_fields', array('SubsiteID')); } foreach ($siteConfigs as $config) { $service = new CacheableNavigationService($mode, $config); if ($service->refreshCachedConfig()) { echo 'Caching: SiteConfig object ' . trim($config->ID) . ' (' . $config->Title . ') with mode: ' . $mode . self::new_line(2); } else { echo 'Caching fails: SiteConfig object ' . trim($config->ID) . ' (' . $config->Title . ') with mode: ' . $mode . self::new_line(2); } if (class_exists('Subsite')) { $pages = DataObject::get("Page", "SubsiteID = '" . $config->SubsiteID . "'"); } else { $pages = DataObject::get("Page"); } $pageCount = $pages->count(); /* * * Queueing should only occur if: * - QueuedJob module is available * - SkipQueue param is not set * - Total no. pages is greater than the chunk divisor */ $lowPageCount = self::$chunk_divisor > $pageCount; $doQueue = $canQueue && !$skipQueue && !$lowPageCount; if ($pageCount) { $i = 0; $chunkNum = 0; $chunk = array(); foreach ($pages as $page) { $i++; // If QueuedJobs exists and isn't user-disabled: Chunk if ($doQueue) { // Start building a chunk of pages to be refreshed $chunk[] = $page; $chunkSize = count($chunk); /* * Conditions of chunking: * - Initial chunks are chunk-size == self::$chunk_divisor * - Remaining object count equals no. objects in current $chunk */ $doChunking = $this->chunkForQueue($pageCount, $chunkSize, $i); if ($doChunking) { $chunkNum++; $this->queue($service, $chunk, $stage, $config->SubsiteID); echo "Queued chunk #" . $chunkNum . ' (' . $chunkSize . ' objects).' . self::new_line(); $chunk = array(); } // Default to non-chunking if no queuedjobs or script instructed to skip queuing } else { $percentComplete = $this->percentageComplete($i, $pageCount); $service->set_model($page); if ($service->refreshCachedPage(true)) { echo 'Caching: ' . trim($page->Title) . ' (' . $percentComplete . ') ' . self::new_line(); } else { echo 'Caching fails: ' . trim($page->Title) . ' (' . $percentComplete . ') ' . self::new_line(); } } $page->flushCache(); } } $service->completeBuild(); // Completion message $msg = self::new_line() . $pageCount . ' ' . $stage . ' pages in subsite ' . $config->ID; if ($doQueue) { $msg .= ' queued for caching.' . self::new_line(); } else { $msg .= ' objects cached.' . self::new_line(); } echo $msg . self::new_line(); } if (class_exists('Subsite')) { Subsite::disable_subsite_filter(false); } } Versioned::set_reading_mode($currentStage); $endTime = time(); $totalTime = $endTime - $startTime; $this->showConfig($totalTime, $request, $lowPageCount); }
/** * Confirm that DataObject::get_one() gets records from SiteTree_Live */ function testGetOneFromLive() { $s = new SiteTree(); $s->Title = "V1"; $s->URLSegment = "get-one-test-page"; $s->write(); $s->publish("Stage", "Live"); $s->Title = "V2"; $s->write(); $oldMode = Versioned::get_reading_mode(); Versioned::reading_stage('Live'); $checkSiteTree = DataObject::get_one("SiteTree", "\"URLSegment\" = 'get-one-test-page'"); $this->assertEquals("V1", $checkSiteTree->Title); Versioned::set_reading_mode($oldMode); }
/** * @todo Find more appropriate place to hook into database building */ public function requireDefaultRecords() { // @todo This relies on the Locale attribute being on the base data class, and not any subclasses if ($this->owner->class != ClassInfo::baseDataClass($this->owner->class)) { return false; } // Permissions: If a group doesn't have any specific TRANSLATE_<locale> edit rights, // but has CMS_ACCESS_CMSMain (general CMS access), then assign TRANSLATE_ALL permissions as a default. // Auto-setting permissions based on these intransparent criteria is a bit hacky, // but unavoidable until we can determine when a certain permission code was made available first // (see http://open.silverstripe.org/ticket/4940) $groups = Permission::get_groups_by_permission(array('CMS_ACCESS_CMSMain', 'CMS_ACCESS_LeftAndMain', 'ADMIN')); if ($groups) { foreach ($groups as $group) { $codes = $group->Permissions()->column('Code'); $hasTranslationCode = false; foreach ($codes as $code) { if (preg_match('/^TRANSLATE_/', $code)) { $hasTranslationCode = true; } } // Only add the code if no more restrictive code exists if (!$hasTranslationCode) { Permission::grant($group->ID, 'TRANSLATE_ALL'); } } } // If the Translatable extension was added after the first records were already // created in the database, make sure to update the Locale property if // if wasn't set before $idsWithoutLocale = DB::query(sprintf('SELECT "ID" FROM "%s" WHERE "Locale" IS NULL OR "Locale" = \'\'', ClassInfo::baseDataClass($this->owner->class)))->column(); if (!$idsWithoutLocale) { return; } if (class_exists('SiteTree') && $this->owner->class == 'SiteTree') { foreach (array('Stage', 'Live') as $stage) { foreach ($idsWithoutLocale as $id) { $obj = Versioned::get_one_by_stage($this->owner->class, $stage, sprintf('"SiteTree"."ID" = %d', $id)); if (!$obj || $obj->ObsoleteClassName) { continue; } $obj->Locale = Translatable::default_locale(); $oldMode = Versioned::get_reading_mode(); Versioned::reading_stage($stage); $obj->writeWithoutVersion(); Versioned::set_reading_mode($oldMode); $obj->addTranslationGroup($obj->ID); $obj->destroy(); unset($obj); } } } else { foreach ($idsWithoutLocale as $id) { $obj = DataObject::get_by_id($this->owner->class, $id); if (!$obj || $obj->ObsoleteClassName) { continue; } $obj->Locale = Translatable::default_locale(); $obj->write(); $obj->addTranslationGroup($obj->ID); $obj->destroy(); unset($obj); } } DB::alteration_message(sprintf("Added default locale '%s' to table %s", "changed", Translatable::default_locale(), $this->owner->class)); }
/** * Will publish all pages of the SiteTree for the defined translationLocale * * @param int $parentID ID of the parent to get pages for * * @return void * * @author Sebastian Diel <*****@*****.**> * @since 03.05.2012 */ public function publishSiteTree($parentID = 0) { $translationLocale = $this->getTranslationLocale(); Translatable::disable_locale_filter(); Versioned::set_reading_mode('Stage.Stage'); $pages = SiteTree::get()->filter(array("ParentID" => $parentID, "Locale" => $translationLocale)); if ($pages->exists()) { foreach ($pages as $page) { $page->publish("Stage", "Live"); $this->publishSiteTree($page->ID); } } }
public function testUnpublishedPage() { if (!class_exists('SiteTree')) { $this->markTestSkipped('Test skipped; CMS module required for testUnpublishedPage'); } $orphanedPage = new SiteTree(); $orphanedPage->ParentID = 999999; // missing parent id $orphanedPage->write(); $orphanedPage->publish("Stage", "Live"); $rootPage = new SiteTree(); $rootPage->ParentID = 0; $rootPage->write(); $rootPage->publish("Stage", "Live"); $oldMode = Versioned::get_reading_mode(); Versioned::reading_stage('Live'); try { $this->assertEmpty($orphanedPage->hasPublishedParent()); $this->assertEmpty($orphanedPage->canIncludeInGoogleSitemap()); $this->assertNotEmpty($rootPage->hasPublishedParent()); $this->assertNotEmpty($rootPage->canIncludeInGoogleSitemap()); } catch (Exception $ex) { Versioned::set_reading_mode($oldMode); throw $ex; } // finally { Versioned::set_reading_mode($oldMode); // } }
function writeToStage($stage, $forceInsert = false) { $oldMode = Versioned::get_reading_mode(); Versioned::reading_stage($stage); $result = $this->owner->write(false, $forceInsert); Versioned::set_reading_mode($oldMode); return $result; }
/** * @inheritdoc * * @return array */ function check() { $origStage = Versioned::get_reading_mode(); Versioned::set_reading_mode('Live'); $files = $this->getFiles(); if ($files) { $fileTypeValidateFunc = $this->fileTypeValidateFunc; if (method_exists($this, $fileTypeValidateFunc)) { $invalidFiles = array(); $validFiles = array(); foreach ($files as $file) { if ($this->{$fileTypeValidateFunc}($file)) { $validFiles[] = $file; } else { $invalidFiles[] = $file; } } // If at least one file was valid, count as passed if ($this->checkType == self::CHECK_SINGLE && count($invalidFiles) < count($files)) { $validFileList = "\n"; foreach ($validFiles as $vf) { $validFileList .= $vf . "\n"; } if ($fileTypeValidateFunc == 'noVidation') { $checkReturn = array(EnvironmentCheck::OK, sprintf('At least these file(s) accessible: %s', $validFileList)); } else { $checkReturn = array(EnvironmentCheck::OK, sprintf('At least these file(s) passed file type validate function "%s": %s', $fileTypeValidateFunc, $validFileList)); } } else { if (count($invalidFiles) == 0) { $checkReturn = array(EnvironmentCheck::OK, 'All files valideted'); } else { $invalidFileList = "\n"; foreach ($invalidFiles as $vf) { $invalidFileList .= $vf . "\n"; } if ($fileTypeValidateFunc == 'noVidation') { $checkReturn = array(EnvironmentCheck::ERROR, sprintf('File(s) not accessible: %s', $invalidFileList)); } else { $checkReturn = array(EnvironmentCheck::ERROR, sprintf('File(s) not passing the file type validate function "%s": %s', $fileTypeValidateFunc, $invalidFileList)); } } } } else { $checkReturn = array(EnvironmentCheck::ERROR, sprintf("Invalid file type validation method name passed: %s ", $fileTypeValidateFunc)); } } else { $checkReturn = array(EnvironmentCheck::ERROR, sprintf("No files accessible at path %s", $this->path)); } Versioned::set_reading_mode($origStage); return $checkReturn; }
/** * To process this job, we need to get the next page whose ID is the next greater than the last * processed. This way we don't need to remember a bunch of data about what we've processed */ public function process() { if (ClassInfo::exists('Subsite')) { Subsite::disable_subsite_filter(); } $pages = DataObject::get($this->reindexType, '"' . $this->reindexType . '"."ID" > ' . $this->lastIndexedID, 'ID ASC', '', '0, ' . self::$at_a_time); if (ClassInfo::exists('Subsite')) { Subsite::$disable_subsite_filter = false; } if (!$pages || !$pages->count()) { $this->isComplete = true; return; } $mode = Versioned::get_reading_mode(); Versioned::reading_stage('Stage'); // index away $service = singleton('SolrSearchService'); $live = array(); $stage = array(); $all = array(); foreach ($pages as $page) { // Make sure the current page is not orphaned. if ($page->ParentID > 0) { $parent = $page->getParent(); if (is_null($parent) || $parent === false) { continue; } } // Appropriately index the current page, taking versioning into account. if ($page->hasExtension('Versioned')) { $stage[] = $page; $base = $page->baseTable(); $idField = '"' . $base . '_Live"."ID"'; $livePage = Versioned::get_one_by_stage($page->ClassName, 'Live', $idField . ' = ' . $page->ID); if ($livePage) { $live[] = $livePage; } } else { $all[] = $page; } $this->lastIndexedID = $page->ID; } if (count($all)) { $service->indexMultiple($all); } if (count($stage)) { $service->indexMultiple($stage, 'Stage'); } if (count($live)) { $service->indexMultiple($live, 'Live'); } Versioned::set_reading_mode($mode); $this->lastIndexedID = $page->ID; $this->currentStep += $pages->count(); }
/** * Test that publishing processes respects lazy loaded fields */ public function testLazyLoadFields() { $originalMode = Versioned::get_reading_mode(); // Generate staging record and retrieve it from stage in live mode Versioned::reading_stage('Stage'); $obj = new VersionedTest_Subclass(); $obj->Name = 'bob'; $obj->ExtraField = 'Field Value'; $obj->write(); $objID = $obj->ID; $filter = sprintf('"VersionedTest_DataObject"."ID" = \'%d\'', Convert::raw2sql($objID)); Versioned::reading_stage('Live'); // Check fields are unloaded prior to access $objLazy = Versioned::get_one_by_stage('VersionedTest_DataObject', 'Stage', $filter, false); $lazyFields = $objLazy->getQueriedDatabaseFields(); $this->assertTrue(isset($lazyFields['ExtraField_Lazy'])); $this->assertEquals('VersionedTest_Subclass', $lazyFields['ExtraField_Lazy']); // Check lazy loading works when viewing a Stage object in Live mode $this->assertEquals('Field Value', $objLazy->ExtraField); // Test that writeToStage respects lazy loaded fields $objLazy = Versioned::get_one_by_stage('VersionedTest_DataObject', 'Stage', $filter, false); $objLazy->writeToStage('Live'); $objLive = Versioned::get_one_by_stage('VersionedTest_DataObject', 'Live', $filter, false); $liveLazyFields = $objLive->getQueriedDatabaseFields(); // Check fields are unloaded prior to access $this->assertTrue(isset($liveLazyFields['ExtraField_Lazy'])); $this->assertEquals('VersionedTest_Subclass', $liveLazyFields['ExtraField_Lazy']); // Check that live record has original value $this->assertEquals('Field Value', $objLive->ExtraField); Versioned::set_reading_mode($originalMode); }
public function run($request) { increase_time_limit_to(); $readingMode = Versioned::get_reading_mode(); Versioned::reading_stage('Stage'); // Make sure that we have something to migrate. if (!ClassInfo::hasTable('SolrSearchPage')) { echo "Nothing to Migrate!"; die; } // Retrieve the search tree relationships to migrate. $relationships = array(); if (DB::getConn()->hasTable('SolrSearchPage_SearchTrees')) { foreach (DB::query('SELECT * FROM SolrSearchPage_SearchTrees') as $relationship) { $relationships[$relationship['SolrSearchPageID']] = $relationship['PageID']; } } // Store the current live page migration state to avoid duplicates. $created = array(); // Migrate any live pages to begin with. $query = DB::query('SELECT * FROM SiteTree_Live st, SolrSearchPage_Live ssp WHERE st.ID = ssp.ID'); $queryCount = $query->numRecords(); $writeCount = 0; foreach ($query as $results) { $searchPage = ExtensibleSearchPage::create(); $searchPage->SearchEngine = 'SolrSearch'; // Migrate the key site tree and solr search fields across. $fields = array('ParentID', 'URLSegment', 'Title', 'MenuTitle', 'Content', 'ShowInMenus', 'ShowInSearch', 'Sort', 'ResultsPerPage', 'SortBy', 'BoostFieldsValue', 'SearchOnFieldsValue', 'SearchTypeValue', 'StartWithListing', 'QueryType', 'ListingTemplateID', 'FilterFieldsValue', 'MinFacetCount', 'FacetQueriesValue', 'FacetMappingValue', 'CustomFacetFieldsValue', 'FacetFieldsValue', 'BoostMatchFieldsValue'); foreach ($fields as $fname) { if (isset($results[$fname])) { $searchPage->{$fname} = $results[$fname]; } } // This field name no longer matches the original. if ($results['SortDir']) { $searchPage->SortDirection = $results['SortDir']; } if (isset($relationships[$results['ID']])) { $searchPage->SearchTrees()->add($relationships[$results['ID']]); } // Attempt to publish these new pages. $searchPage->doPublish(); if ($searchPage->ID) { echo "<strong>{$results['ID']}</strong> Published<br>"; $writeCount++; } $created[] = $results['ID']; } // Confirm that the current user had permission to publish these new pages. $this->checkPermissions($queryCount, $writeCount); // Migrate any remaining draft pages. $query = DB::query('SELECT * FROM SiteTree st, SolrSearchPage ssp WHERE st.ID = ssp.ID'); $queryCount = $query->numRecords(); $writeCount = 0; foreach ($query as $results) { // Make sure this search page doesn't already exist. if (!in_array($results['ID'], $created)) { $searchPage = ExtensibleSearchPage::create(); $searchPage->SearchEngine = 'SolrSearch'; // Migrate the key site tree and solr search fields across. $searchPage->ParentID = $results['ParentID']; $searchPage->URLSegment = $results['URLSegment']; $searchPage->Title = $results['Title']; $searchPage->MenuTitle = $results['MenuTitle']; $searchPage->Content = $results['Content']; $searchPage->ShowInMenus = $results['ShowInMenus']; $searchPage->ShowInSearch = $results['ShowInSearch']; $searchPage->Sort = $results['Sort']; $searchPage->ResultsPerPage = $results['ResultsPerPage']; $searchPage->SortBy = $results['SortBy']; $searchPage->SortDirection = $results['SortDir']; $searchPage->QueryType = $results['QueryType']; $searchPage->StartWithListing = $results['StartWithListing']; $searchPage->SearchTypeValue = $results['SearchTypeValue']; $searchPage->SearchOnFieldsValue = $results['SearchOnFieldsValue']; $searchPage->BoostFieldsValue = $results['BoostFieldsValue']; $searchPage->BoostMatchFieldsValue = $results['BoostMatchFieldsValue']; $searchPage->FacetFieldsValue = $results['FacetFieldsValue']; $searchPage->CustomFacetFieldsValue = $results['CustomFacetFieldsValue']; $searchPage->FacetMappingValue = $results['FacetMappingValue']; $searchPage->FacetQueriesValue = $results['FacetQueriesValue']; $searchPage->MinFacetCount = $results['MinFacetCount']; $searchPage->FilterFieldsValue = $results['FilterFieldsValue']; $searchPage->ListingTemplateID = $results['ListingTemplateID']; if (isset($relationships[$results['ID']])) { $searchPage->SearchTrees()->add($relationships[$results['ID']]); } $searchPage->write(); if ($searchPage->ID) { echo "<strong>{$results['ID']}</strong> Saved<br>"; $writeCount++; } } else { $writeCount++; } } // Confirm that the current user had permission to write these new pages. $this->checkPermissions($queryCount, $writeCount); // Remove the previous search page tables, as they are now obsolete (and may not be marked as such). $remove = array('SiteTree', 'SiteTree_Live', 'Page', 'Page_Live'); foreach ($remove as $table) { foreach ($created as $ID) { DB::query("DELETE FROM {$table} WHERE ID = {$ID}"); } } $remove = array('SolrSearchPage', 'SolrSearchPage_Live', 'SolrSearchPage_SearchTrees', 'SolrSearchPage_versions'); foreach ($remove as $table) { DB::query("DROP TABLE {$table}"); } Versioned::set_reading_mode($readingMode); echo 'Migration Complete!'; }
/** * Get a database record to be managed by the CMS. * * @param int $id Record ID * @param int $versionID optional Version id of the given record */ public function getRecord($id, $versionID = null) { $treeClass = $this->stat('tree_class'); if ($id instanceof $treeClass) { return $id; } else { if ($id && is_numeric($id)) { if ($this->request->getVar('Version')) { $versionID = (int) $this->request->getVar('Version'); } if ($versionID) { $record = Versioned::get_version($treeClass, $id, $versionID); } else { $record = DataObject::get_one($treeClass, "\"{$treeClass}\".\"ID\" = {$id}"); } // Then, try getting a record from the live site if (!$record) { // $record = Versioned::get_one_by_stage($treeClass, "Live", "\"$treeClass\".\"ID\" = $id"); Versioned::reading_stage('Live'); singleton($treeClass)->flushCache(); $record = DataObject::get_one($treeClass, "\"{$treeClass}\".\"ID\" = {$id}"); if ($record) { Versioned::set_reading_mode(''); } } // Then, try getting a deleted record if (!$record) { $record = Versioned::get_latest_version($treeClass, $id); } // Don't open a page from a different locale /** The record's Locale is saved in database in 2.4, and not related with Session, * we should not check their locale matches the Translatable::get_current_locale, * here as long as we all the HTTPRequest is init with right locale. * This bit breaks the all FileIFrameField functions if the field is used in CMS * and its relevent ajax calles, like loading the tree dropdown for TreeSelectorField. */ /* if($record && Object::has_extension('SiteTree', 'Translatable') && $record->Locale && $record->Locale != Translatable::get_current_locale()) { $record = null; }*/ return $record; } else { if (substr($id, 0, 3) == 'new') { return $this->getNewItem($id); } } } }
/** * Publish this page. * * @uses SiteTreeExtension->onBeforePublish() * @uses SiteTreeExtension->onAfterPublish() */ public function doPublish() { if (!$this->canPublish()) { return false; } $original = Versioned::get_one_by_stage("SiteTree", "Live", "\"SiteTree\".\"ID\" = {$this->ID}"); if (!$original) { $original = new SiteTree(); } // Handle activities undertaken by extensions $this->invokeWithExtensions('onBeforePublish', $original); //$this->PublishedByID = Member::currentUser()->ID; $this->write(); $this->publish("Stage", "Live"); DB::query("UPDATE \"SiteTree_Live\"\n\t\t\tSET \"Sort\" = (SELECT \"SiteTree\".\"Sort\" FROM \"SiteTree\" WHERE \"SiteTree_Live\".\"ID\" = \"SiteTree\".\"ID\")\n\t\t\tWHERE EXISTS (SELECT \"SiteTree\".\"Sort\" FROM \"SiteTree\" WHERE \"SiteTree_Live\".\"ID\" = \"SiteTree\".\"ID\") AND \"ParentID\" = " . sprintf('%d', $this->ParentID)); // Publish any virtual pages that might need publishing $linkedPages = $this->VirtualPages(); if ($linkedPages) { foreach ($linkedPages as $page) { $page->copyFrom($page->CopyContentFrom()); $page->write(); if ($page->ExistsOnLive) { $page->doPublish(); } } } // Need to update pages linking to this one as no longer broken, on the live site $origMode = Versioned::get_reading_mode(); Versioned::reading_stage('Live'); foreach ($this->DependentPages(false) as $page) { // $page->write() calls syncLinkTracking, which does all the hard work for us. $page->write(); } Versioned::set_reading_mode($origMode); // Handle activities undertaken by extensions $this->invokeWithExtensions('onAfterPublish', $original); return true; }