Skip to content

Commit

Permalink
FEATURE: Initial import
Browse files Browse the repository at this point in the history
  • Loading branch information
camspiers committed Jun 29, 2013
0 parents commit 9428fcc
Show file tree
Hide file tree
Showing 10 changed files with 428 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/vendor/
11 changes: 11 additions & 0 deletions .php_cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

$finder = Symfony\CS\Finder\DefaultFinder::create()
->name('*.php')
->exclude(array(
'vendor'
))
->in(__DIR__);

return Symfony\CS\Config\Config::create()
->finder($finder);
9 changes: 9 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
language: php

php:
- 5.3
- 5.4

before_script:
- composer self-update
- composer install --dev
20 changes: 20 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# SilverStripe Versioned DataObjects

## Installation (with composer)

$ composer require heyday/silverstripe-versioneddataobjects

## Usage

```php
class MyDataObject extends DataObject
{
private static $extensions = array(
'VersionedDataObject'
);
}
```

## Unit testing

None :(
Empty file added _config/config.yml
Empty file.
131 changes: 131 additions & 0 deletions code/VersionedDataObject.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
<?php

class VersionedDataObject extends Versioned
{
/**
*
*/
public function __construct()
{
parent::__construct(
array(
'Stage',
'Live'
)
);
}
/**
* @param null $class
* @param $extension
* @param $args
* @return array
*/
public static function get_extra_config($class, $extension, $args)
{
return array(
'db' => array(
'Version' => 'Int',
),
'has_many' => array(
'Versions' => $class
),
'searchable_fields' => array()
);
}
/**
* @param $fields
*/
public function updateSummaryFields(&$fields)
{
$fields = array_merge(
$fields,
array(
'isModifiedNice' => 'Modified',
'isPublishedNice' => 'Published'
)
);
}
/**
* @param $fields
*/
public function updateSearchableFields(&$fields)
{
unset($fields['isModifiedNice']);
unset($fields['isPublishedNice']);
}
/**
* @return bool
*/
public function isNew()
{
$id = $this->owner->ID;
if (empty($id)) {
return true;
}
if (is_numeric($id)) {
return false;
}
}
/**
* @return bool
*/
public function isPublished()
{
if ($this->isNew()) {
return false;
}

$table = $this->owner->class;

while (($p = get_parent_class($table)) !== 'DataObject') {
$table = $p;
}

return (bool) DB::query("SELECT \"ID\" FROM \"{$table}_Live\" WHERE \"ID\" = {$this->owner->ID}")->value();
}
/**
* @param $value
* @return string
*/
protected function getBooleanNice($value)
{
return $value ? 'Yes' : 'No';
}
/**
* @return mixed
*/
public function isPublishedNice()
{
return $this->getBooleanNice($this->isPublished());
}
/**
* @return mixed
*/
public function isModifiedNice()
{
return $this->getBooleanNice($this->stagesDiffer('Stage', 'Live'));
}
/**
* @param FieldList $fields
*/
public function updateCMSFields(FieldList $fields)
{
$fields->removeByName('Version');
$fields->removeByName('Versions');
}
/**
*
*/
public function onBeforeWrite()
{
$fieldsIgnoredByVersioning = array('Version');

$changedFields = array_keys($this->owner->getChangedFields(true, 2));
$oneChangedFields = array_keys($this->owner->getChangedFields(true, 1));

if ($oneChangedFields && !array_diff($changedFields, $fieldsIgnoredByVersioning)) {
// This will have the affect of preserving the versioning
$this->migrateVersion($this->owner->Version);
}
}
}
214 changes: 214 additions & 0 deletions code/VersionedDataObjectDetailsForm.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
<?php

/**
* Class VersionedDataObjectDetailsForm
*/
class VersionedDataObjectDetailsForm extends GridFieldDetailForm
{
}

/**
* Class VersionedDataObjectDetailsForm_ItemRequest
*/
class VersionedDataObjectDetailsForm_ItemRequest extends GridFieldDetailForm_ItemRequest
{
/**
* @var array
*/
private static $allowed_actions = array(
'edit',
'view',
'ItemEditForm'
);
/**
* @return Form
*/
public function ItemEditForm()
{
$form = parent::ItemEditForm();
/* @var $actions FieldList */
$actions = $form->Actions();

$actions->replaceField(
'action_doSave',
FormAction::create('save', _t('SiteTree.BUTTONSAVED', 'Saved'))
->setAttribute('data-icon', 'accept')
->setAttribute('data-icon-alternate', 'addpage')
->setAttribute('data-text-alternate', _t('CMSMain.SAVEDRAFT', 'Save draft'))
->setUseButtonTag(true)
);

/* @var $publish FormAction */
$publish = FormAction::create('publish', _t('SiteTree.BUTTONPUBLISHED', 'Published'))
->setAttribute('data-icon', 'accept')
->setAttribute('data-icon-alternate', 'disk')
->setAttribute('data-text-alternate', _t('SiteTree.BUTTONSAVEPUBLISH', 'Save & publish'))
->setUseButtonTag(true);

if ($this->record->stagesDiffer('Stage', 'Live')) {
$publish->addExtraClass('ss-ui-alternate');

$actions->push(
FormAction::create(
'rollback',
_t(
'SiteTree.BUTTONCANCELDRAFT',
'Cancel draft changes'
),
'delete'
)->setDescription(
_t(
'SiteTree.BUTTONCANCELDRAFTDESC',
'Delete your draft and revert to the currently published page'
)
)
);
}

$actions->push($publish);

if ($this->record->isPublished()) {
/* @var $unpublish FormAction */
$unpublish = FormAction::create('unpublish', _t('SiteTree.BUTTONUNPUBLISH', 'Unpublish'), 'delete')
->addExtraClass('ss-ui-action-destructive');

$actions->push($unpublish);
}

return $form;
}

/**
* @param $data
* @param $form
* @return HTMLText|SS_HTTPResponse|ViewableData_Customised
*/
public function save($data, $form)
{
return $this->doSave($data, $form);
}

/**
* @param $data
* @param $form
* @return HTMLText|SS_HTTPResponse|ViewableData_Customised
*/
public function publish($data, $form)
{
$new_record = $this->record->ID == 0;
$controller = Controller::curr();
$list = $this->gridField->getList();

if ($list instanceof ManyManyList) {
// Data is escaped in ManyManyList->add()
$extraData = (isset($data['ManyMany'])) ? $data['ManyMany'] : null;
} else {
$extraData = null;
}

if (!$this->record->canEdit()) {
return $controller->httpError(403);
}

if (isset($data['ClassName']) && $data['ClassName'] != $this->record->ClassName) {
$newClassName = $data['ClassName'];
// The records originally saved attribute was overwritten by $form->saveInto($record) before.
// This is necessary for newClassInstance() to work as expected, and trigger change detection
// on the ClassName attribute
$this->record->setClassName($this->record->ClassName);
// Replace $record with a new instance
$this->record = $this->record->newClassInstance($newClassName);
}

try {
$form->saveInto($this->record);
$this->record->write();
$list->add($this->record, $extraData);
$this->record->publish('Stage', 'Live');
} catch (ValidationException $e) {
$form->sessionMessage($e->getResult()->message(), 'bad');
$responseNegotiator = new PjaxResponseNegotiator(array(
'CurrentForm' => function () use (&$form) {
return $form->forTemplate();
},
'default' => function () use (&$controller) {
return $controller->redirectBack();
}
));
if ($controller->getRequest()->isAjax()) {
$controller->getRequest()->addHeader('X-Pjax', 'CurrentForm');
}

return $responseNegotiator->respond($controller->getRequest());
}

// TODO Save this item into the given relationship

$link = '<a href="' . $this->Link('edit') . '">"'
. htmlspecialchars($this->record->Title, ENT_QUOTES)
. '"</a>';
$message = sprintf(
'Published %s %s',
$this->record->i18n_singular_name(),
$link
);

$form->sessionMessage($message, 'good');

if ($new_record) {
return Controller::curr()->redirect($this->Link());
} elseif ($this->gridField->getList()->byId($this->record->ID)) {
// Return new view, as we can't do a "virtual redirect" via the CMS Ajax
// to the same URL (it assumes that its content is already current, and doesn't reload)
return $this->edit(Controller::curr()->getRequest());
} else {
// Changes to the record properties might've excluded the record from
// a filtered list, so return back to the main view if it can't be found
$noActionURL = $controller->removeAction($data['url']);
$controller->getRequest()->addHeader('X-Pjax', 'Content');

return $controller->redirect($noActionURL, 302);
}
}

/**
* @return HTMLText|ViewableData_Customised
*/
public function unPublish()
{
$origStage = Versioned::current_stage();
Versioned::reading_stage('Live');

// This way our ID won't be unset
$clone = clone $this->record;
$clone->delete();

Versioned::reading_stage($origStage);

return $this->edit(Controller::curr()->getRequest());
}
/**
* @param $data
* @param $form
* @return HTMLText|ViewableData_Customised
*/
public function rollback($data, $form)
{
if (!$this->record->canEdit()) {
return Controller::curr()->httpError(403);
}

$this->record->doRollbackTo('Live');

$this->record = DataList::create($this->record->class)->byID($this->record->ID);

$message = _t(
'CMSMain.ROLLEDBACKPUBv2',
"Rolled back to published version."
);

$form->sessionMessage($message, 'good');

return $this->edit(Controller::curr()->getRequest());
}
}
Loading

0 comments on commit 9428fcc

Please sign in to comment.