/** * Test that objects are correctly published recursively */ public function testRecursivePublish() { /** @var VersionedOwnershipTest_Subclass $parent */ $parent = $this->objFromFixture('VersionedOwnershipTest_Subclass', 'subclass1_published'); $parentID = $parent->ID; $banner1 = $this->objFromFixture('VersionedOwnershipTest_RelatedMany', 'relatedmany1_published'); $banner2 = $this->objFromFixture('VersionedOwnershipTest_RelatedMany', 'relatedmany2_published'); $banner2ID = $banner2->ID; // Modify, Add, and Delete banners on stage $banner1->Title = 'Renamed Banner 1'; $banner1->write(); $banner2->delete(); $banner4 = new VersionedOwnershipTest_RelatedMany(); $banner4->Title = 'New Banner'; $parent->Banners()->add($banner4); // Check state of objects before publish $oldLiveBanners = [['Title' => 'Related Many 1'], ['Title' => 'Related Many 2']]; $newBanners = [['Title' => 'Renamed Banner 1'], ['Title' => 'Related Many 3'], ['Title' => 'New Banner']]; $parentDraft = Versioned::get_by_stage('VersionedOwnershipTest_Subclass', Versioned::DRAFT)->byID($parentID); $this->assertDOSEquals($newBanners, $parentDraft->Banners()); $parentLive = Versioned::get_by_stage('VersionedOwnershipTest_Subclass', Versioned::LIVE)->byID($parentID); $this->assertDOSEquals($oldLiveBanners, $parentLive->Banners()); // On publishing of owner, all children should now be updated $now = DBDatetime::now(); DBDatetime::set_mock_now($now); // Lock 'now' to predictable time $parent->publishRecursive(); // Now check each object has the correct state $parentDraft = Versioned::get_by_stage('VersionedOwnershipTest_Subclass', Versioned::DRAFT)->byID($parentID); $this->assertDOSEquals($newBanners, $parentDraft->Banners()); $parentLive = Versioned::get_by_stage('VersionedOwnershipTest_Subclass', Versioned::LIVE)->byID($parentID); $this->assertDOSEquals($newBanners, $parentLive->Banners()); // Check that the deleted banner hasn't actually been deleted from the live stage, // but in fact has been unlinked. $banner2Live = Versioned::get_by_stage('VersionedOwnershipTest_RelatedMany', Versioned::LIVE)->byID($banner2ID); $this->assertEmpty($banner2Live->PageID); // Test that a changeset was created /** @var ChangeSet $changeset */ $changeset = ChangeSet::get()->sort('"ChangeSet"."ID" DESC')->first(); $this->assertNotEmpty($changeset); // Test that this changeset is inferred $this->assertTrue((bool) $changeset->IsInferred); $this->assertEquals("Generated by publish of 'Subclass 1' at " . $now->Nice(), $changeset->getTitle()); // Test that this changeset contains all items $this->assertDOSContains([['ObjectID' => $parent->ID, 'ObjectClass' => $parent->baseClass(), 'Added' => ChangeSetItem::EXPLICITLY], ['ObjectID' => $banner1->ID, 'ObjectClass' => $banner1->baseClass(), 'Added' => ChangeSetItem::IMPLICITLY], ['ObjectID' => $banner4->ID, 'ObjectClass' => $banner4->baseClass(), 'Added' => ChangeSetItem::IMPLICITLY]], $changeset->Changes()); // Objects that are unlinked should not need to be a part of the changeset $this->assertNotDOSContains([['ObjectID' => $banner2ID, 'ObjectClass' => $banner2->baseClass()]], $changeset->Changes()); }
/** * Performs the actual action of adding the object to the ChangeSet, once the ChangeSet ID is known * * @param DataObject $object The object to add to the ChangeSet * @param int $campaignID The ID of the ChangeSet to add $object to * @return SS_HTTPResponse * @throws SS_HTTPResponse_Exception */ public function addToCampaign($object, $campaignID) { /** @var ChangeSet $changeSet */ $changeSet = ChangeSet::get()->byID($campaignID); if (!$changeSet) { $this->editForm->httpError(404, _t('AddToCampaign.ErrorNotFound', 'That {Type} couldn\'t be found', '', ['Type' => 'Campaign'])); return null; } if (!$changeSet->canEdit()) { $this->editForm->httpError(403, _t('AddToCampaign.ErrorCampaignPermissionDenied', 'It seems you don\'t have the necessary permissions to add {ObjectTitle} to {CampaignTitle}', '', ['ObjectTitle' => $object->Title, 'CampaignTitle' => $changeSet->Title])); return null; } $changeSet->addObject($object); if (Director::is_ajax()) { $response = new SS_HTTPResponse(_t('AddToCampaign.Success', 'Successfully added {ObjectTitle} to {CampaignTitle}', '', ['ObjectTitle' => $object->Title, 'CampaignTitle' => $changeSet->Title]), 200); $response->addHeader('Content-Type', 'text/plain; charset=utf-8'); return $response; } else { return $this->editForm->getController()->redirectBack(); } }
/** * @todo Use GridFieldDetailForm once it can handle structured data and form schemas * * @param int $id * @return Form */ public function getDetailEditForm($id) { // Get record-specific fields $record = null; if ($id) { $record = ChangeSet::get()->byID($id); if (!$record || !$record->canView()) { return null; } } if (!$record) { $record = ChangeSet::singleton(); } $fields = $record->getCMSFields(); // Add standard fields $fields->push(HiddenField::create('ID')); $form = Form::create($this, 'DetailEditForm', $fields, FieldList::create(FormAction::create('save', _t('CMSMain.SAVE', 'Save'))->setIcon('save'), FormAction::create('cancel', _t('LeftAndMain.CANCEL', 'Cancel'))->setUseButtonTag(true))); // Load into form if ($id && $record) { $form->loadDataFrom($record); } $form->getValidator()->addRequiredField('Name'); // Configure form to respond to validation errors with form schema // if requested via react. $form->setValidationResponseCallback(function () use($form, $record) { $schemaId = Controller::join_links($this->Link('schema/DetailEditForm'), $record->exists() ? $record->ID : ''); return $this->getSchemaResponse($form, $schemaId); }); return $form; }