public function testPublish() { $this->publishAllFixtures(); $base = $this->objFromFixture(ChangeSetTest_Base::class, 'base'); $baseID = $base->ID; $baseBefore = $base->Version; $end1 = $this->objFromFixture(ChangeSetTest_End::class, 'end1'); $end1ID = $end1->ID; $end1Before = $end1->Version; // Create a new changest $changeset = new ChangeSet(); $changeset->write(); $changeset->addObject($base); $changeset->addObject($end1); // Make a lot of changes // - ChangeSetTest_Base.base modified // - ChangeSetTest_End.end1 deleted // - new ChangeSetTest_Mid added $base->Foo = 343; $base->write(); $baseAfter = $base->Version; $midNew = new ChangeSetTest_Mid(); $midNew->Bar = 39; $midNew->write(); $midNewID = $midNew->ID; $midNewAfter = $midNew->Version; $end1->delete(); $changeset->addObject($midNew); // Publish $this->logInWithPermission('ADMIN'); $this->assertTrue($changeset->canPublish()); $this->assertTrue($changeset->isSynced()); $changeset->publish(); $this->assertEquals(ChangeSet::STATE_PUBLISHED, $changeset->State); // Check each item has the correct before/after version applied $baseChange = $changeset->Changes()->filter(['ObjectClass' => ChangeSetTest_Base::class, 'ObjectID' => $baseID])->first(); $this->assertEquals((int) $baseBefore, (int) $baseChange->VersionBefore); $this->assertEquals((int) $baseAfter, (int) $baseChange->VersionAfter); $this->assertEquals((int) $baseChange->VersionBefore + 1, (int) $baseChange->VersionAfter); $this->assertEquals((int) $baseChange->VersionAfter, (int) Versioned::get_versionnumber_by_stage(ChangeSetTest_Base::class, Versioned::LIVE, $baseID)); $end1Change = $changeset->Changes()->filter(['ObjectClass' => ChangeSetTest_End::class, 'ObjectID' => $end1ID])->first(); $this->assertEquals((int) $end1Before, (int) $end1Change->VersionBefore); $this->assertEquals(0, (int) $end1Change->VersionAfter); $this->assertEquals(0, (int) Versioned::get_versionnumber_by_stage(ChangeSetTest_End::class, Versioned::LIVE, $end1ID)); $midNewChange = $changeset->Changes()->filter(['ObjectClass' => ChangeSetTest_Mid::class, 'ObjectID' => $midNewID])->first(); $this->assertEquals(0, (int) $midNewChange->VersionBefore); $this->assertEquals((int) $midNewAfter, (int) $midNewChange->VersionAfter); $this->assertEquals((int) $midNewAfter, (int) Versioned::get_versionnumber_by_stage(ChangeSetTest_Mid::class, Versioned::LIVE, $midNewID)); // Test trying to re-publish is blocked $this->setExpectedException('BadMethodCallException', "ChangeSet can't be published if it has been already published or reverted."); $changeset->publish(); }
public function testPublishCreateNewVersion() { $page1 = $this->objFromFixture('VersionedTest_DataObject', 'page1'); $page1->Content = 'orig'; $page1->write(); $firstVersion = $page1->Version; $page1->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE, false); $this->assertEquals($firstVersion, $page1->Version, 'publish() with $createNewVersion=FALSE does not create a new version'); $page1->Content = 'changed'; $page1->write(); $secondVersion = $page1->Version; $this->assertTrue($firstVersion < $secondVersion, 'write creates new version'); $page1->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE, true); $thirdVersion = Versioned::get_latest_version('VersionedTest_DataObject', $page1->ID)->Version; $liveVersion = Versioned::get_versionnumber_by_stage('VersionedTest_DataObject', 'Live', $page1->ID); $stageVersion = Versioned::get_versionnumber_by_stage('VersionedTest_DataObject', 'Stage', $page1->ID); $this->assertTrue($secondVersion < $thirdVersion, 'publish() with $createNewVersion=TRUE creates a new version'); $this->assertEquals($liveVersion, $thirdVersion, 'publish() with $createNewVersion=TRUE publishes to live'); $this->assertEquals($stageVersion, $secondVersion, 'publish() with $createNewVersion=TRUE does not affect stage'); }
/** * Publish this item, then close it. * * Note: Unlike Versioned::doPublish() and Versioned::doUnpublish, this action is not recursive. */ public function publish() { // Logical checks prior to publish if (!$this->canPublish()) { throw new Exception("The current member does not have permission to publish this ChangeSetItem."); } if ($this->VersionBefore || $this->VersionAfter) { throw new BadMethodCallException("This ChangeSetItem has already been published"); } // Record state changed $this->VersionAfter = Versioned::get_versionnumber_by_stage($this->ObjectClass, Versioned::DRAFT, $this->ObjectID, false); $this->VersionBefore = Versioned::get_versionnumber_by_stage($this->ObjectClass, Versioned::LIVE, $this->ObjectID, false); switch ($this->getChangeType()) { case static::CHANGE_NONE: break; case static::CHANGE_DELETED: // Non-recursive delete $object = $this->getObjectInStage(Versioned::LIVE); $object->deleteFromStage(Versioned::LIVE); break; case static::CHANGE_MODIFIED: case static::CHANGE_CREATED: // Non-recursive publish $object = $this->getObjectInStage(Versioned::DRAFT); $object->publishSingle(); break; } $this->write(); }
/** * Determine if there are any additional restrictions on this object for the given reading version. * * Override this in a subclass to customise any additional effect that Versioned applies to canView. * * This is expected to be called by canView, and thus is only responsible for denying access if * the default canView would otherwise ALLOW access. Thus it should not be called in isolation * as an authoritative permission check. * * This has the following extension points: * - canViewDraft is invoked if Mode = stage and Stage = stage * - canViewArchived is invoked if Mode = archive * * @param Member $member * @return bool False is returned if the current viewing mode denies visibility */ public function canViewVersioned($member = null) { // Bypass when live stage $owner = $this->owner; $mode = $owner->getSourceQueryParam("Versioned.mode"); $stage = $owner->getSourceQueryParam("Versioned.stage"); if ($mode === 'stage' && $stage === static::LIVE) { return true; } // Bypass if site is unsecured if (Session::get('unsecuredDraftSite')) { return true; } // Bypass if record doesn't have a live stage if (!$this->hasStages()) { return true; } // If we weren't definitely loaded from live, and we can't view non-live content, we need to // check to make sure this version is the live version and so can be viewed $latestVersion = Versioned::get_versionnumber_by_stage($owner->class, static::LIVE, $owner->ID); if ($latestVersion == $owner->Version) { // Even if this is loaded from a non-live stage, this is the live version return true; } // Extend versioned behaviour $extended = $owner->extendedCan('canViewNonLive', $member); if ($extended !== null) { return (bool) $extended; } // Fall back to default permission check $permissions = Config::inst()->get($owner->class, 'non_live_permissions', Config::FIRST_SET); $check = Permission::checkMember($member, $permissions); return (bool) $check; }