Skip to content

Commit

Permalink
Implemented a new editing interface compatible with SS3.
Browse files Browse the repository at this point in the history
  • Loading branch information
ajshort committed May 6, 2012
1 parent 46f778a commit 6c94de9
Show file tree
Hide file tree
Showing 20 changed files with 710 additions and 637 deletions.
14 changes: 10 additions & 4 deletions _config.php
Expand Up @@ -4,12 +4,18 @@
* @package advancedworkflow
*/

// Add the following to your config to enable workflow
// Add the following to your config to enable workflow
// DataObject::add_extension('SiteTree', 'WorkflowApplicable');

Object::add_extension('Member', 'Hierarchy');
Object::add_extension('LeftAndMain', 'AdvancedWorkflowExtension');

if(($MODULE_DIR = basename(dirname(__FILE__))) != 'advancedworkflow') {
throw new Exception("The advanced workflow module must be in a directory named 'advancedworkflow', not $MODULE_DIR");
}
define('ADVANCED_WORKFLOW_DIR', basename(dirname(__FILE__)));

if(ADVANCED_WORKFLOW_DIR != 'advancedworkflow') {
throw new Exception(
"The advanced workflow module must be in a directory named 'advancedworkflow', not " . ADVANCED_WORKFLOW_DIR
);
}

LeftAndMain::require_css(ADVANCED_WORKFLOW_DIR . '/css/AdvancedWorkflowAdmin.css');
10 changes: 5 additions & 5 deletions code/actions/NotifyUsersWorkflowAction.php
Expand Up @@ -25,12 +25,12 @@ public function getCMSFields() {
new LiteralField('NotificationNote', '<p>' . $this->fieldLabel('NotificationNote') . '</p>'),
new TextField('EmailSubject', $this->fieldLabel('EmailSubject')),
new TextField('EmailFrom', $this->fieldLabel('EmailFrom')),
new TextareaField('EmailTemplate', $this->fieldLabel('EmailTemplate'), 10),

new TextareaField('EmailTemplate', $this->fieldLabel('EmailTemplate')),
new ToggleCompositeField('FormattingHelpContainer',
$this->fieldLabel('FormattingHelp'), new LiteralField('FormattingHelp', $this->getFormattingHelp()))
));

if (class_exists('ListingPage')) {
// allow the user to select an existing 'listing template'. The "getItems()" for that template
// will be the list of items in the workflow
Expand All @@ -39,10 +39,10 @@ public function getCMSFields() {
if ($templates) {
$opts = $templates->map();
}

$fields->addFieldToTab('Root.Main', new DropdownField('ListingTemplateID', $this->fieldLabel('ListingTemplateID'), $opts, '', null, '(choose)'), 'EmailTemplate');
}

if ($this->ListingTemplateID) {
$fields->removeFieldFromTab('Root.Main', 'EmailTemplate');
}
Expand Down
298 changes: 7 additions & 291 deletions code/admin/AdvancedWorkflowAdmin.php
@@ -1,300 +1,16 @@
<?php
/**
* An admin interface for managing workflow definitions, actions and transitions.
*
* @license BSD License (http://silverstripe.org/bsd-license/)
* @package advancedworkflow
* @subpackage admin
*
* @package advancedworkflow
*/
class AdvancedWorkflowAdmin extends ModelAdmin {

public static $title = 'Workflows';
public static $menu_title = 'Workflows';
public static $url_segment = 'workflows';

public static $managed_models = array(
'WorkflowDefinition' => array('record_controller' => 'AdvancedWorkflowAdmin_RecordController'),
'WorkflowAction' => array('record_controller' => 'AdvancedWorkflowAdmin_RecordController'),
'WorkflowTransition' => array('record_controller' => 'AdvancedWorkflowAdmin_RecordController')
);

public static $allowed_actions = array(
'tree',
'sort',
'CreateDefinitionForm',
'CreateActionForm',
'CreateTransitionForm'
);

/**
* @return string
*/
public function tree($request) {
$data = array();
$class = $request->getVar('class');
$id = $request->getVar('id');

if($id == 0) {
$items = singleton('WorkflowService')->getDefinitions();
$type = 'WorkflowDefinition';
} elseif($class == 'WorkflowDefinition') {
$items = DataObject::get('WorkflowAction', '"WorkflowDefID" = ' . (int) $id);
$type = 'WorkflowAction';
} else {
$items = DataObject::get('WorkflowTransition', '"ActionID" = ' . (int) $id);
$type = 'WorkflowTransition';
}

if($items) foreach($items as $item) {
$new = array(
'data' => array(
'title' => $item->Title,
'attr' => array('href' => $this->Link("$type/{$item->ID}/edit")),
'icon' => $item->stat('icon')),
'attr' => array(
'id' => "{$type}_{$item->ID}",
'title' => Convert::raw2att($item->Title),
'data-id' => $item->ID,
'data-type' => $type,
'data-class' => $item->class)
);

if($item->numChildren() > 0) {
$new['state'] = 'closed';
}

$data[] = $new;
}

return Convert::raw2json($data);
}

/**
* @return string
*/
public function sort($request) {
$service = singleton('WorkflowService');
$type = $request->postVar('type');
$order = $request->postVar('ids');
$parentId = $request->postVar('parent_id');

switch($type) {
case 'WorkflowDefinition':
$current = $service->getDefinitions();
break;
case 'WorkflowAction':
$current = DataObject::get('WorkflowAction', sprintf('"WorkflowDefID" = %d', $parentId));
break;
case 'WorkflowTransition':
$current = DataObject::get('WorkflowTransition', sprintf('"ActionID" = %d', $parentId));
break;
default:
return $this->httpError(400, _t('AdvancedWorkflowAdmin.INVALIDSORTTYPE', 'Invalid sort type.'));
}

if(!$order || count($order) != count($current)) {
return new SS_HTTPResponse(
null, 400, _t('AdvancedWorkflowAdmin.INVALIDSORT', 'An invalid sort order was specified.')
);
}

$service->reorder($current, $order);

return new SS_HTTPResponse(
null, 200, _t('AdvancedWorkflowAdmin.SORTORDERSAVED', 'The sort order has been saved.')
);
}

/**
* @return Form
*/
public function CreateDefinitionForm() {
return new Form(
$this,
'CreateDefinitionForm',
new FieldSet(
$this->getClassCreationField('WorkflowDefinition')),
new FieldSet(
new FormAction('doCreateWorkflowItem', _t('AdvancedWorkflowAdmin.CREATE', 'Create')))
);
}

/**
* @return Form
*/
public function CreateActionForm() {
return new Form(
$this,
'CreateActionForm',
new FieldSet(
$this->getClassCreationField('WorkflowAction', false),
new HiddenField('ParentID')),
new FieldSet(
new FormAction('doCreateWorkflowItem', _t('AdvancedWorkflowAdmin.CREATE', 'Create')))
);
}

/**
* @return Form
*/
public function CreateTransitionForm() {
return new Form(
$this,
'CreateTransitionForm',
new FieldSet(
$this->getClassCreationField('WorkflowTransition'),
new HiddenField('ParentID')),
new FieldSet(
new FormAction('doCreateWorkflowItem', _t('AdvancedWorkflowAdmin.CREATE', 'Create')))
);
}

/**
* Creates a workflow item - a definition, action, transition or any subclasses
* of these.
*
* @param array $data
* @param Form $form
* @return string
*/
public function doCreateWorkflowItem($data, $form) {
// assume the form name is in the form CreateTypeForm
$data = $form->getData();
$type = 'Workflow' . substr($form->Name(), 6, -4);
$allowSelf = ($type != 'WorkflowAction');

// determine the class to create - if it is manually specified then use that,
// falling back to creating an object of the root type if allowed.
if(isset($data['Class']) && class_exists($data['Class'])) {
$class = $data['Class'];
$valid = is_subclass_of($class, $type) || ($allowSelf && $class == $type);

if(!$valid) return new SS_HTTPResponse(
null, 400, _t('AdvancedWorkflowAdmin.INVALIDITEM', 'An invalid workflow item was specified.')
);
} else {
$class = $type;

if(!$allowSelf) return new SS_HTTPResponse(
null, 400, _t('AdvancedWorkflowAdmin.MUSTSPECIFYITEM', 'You must specify a workflow item to create.')
);
}

// check that workflow actions and transitions have valid parent id values.
if($type != 'WorkflowDefinition') {
$parentId = $data['ParentID'];
$parentClass = ($type == 'WorkflowAction') ? 'WorkflowDefinition' : 'WorkflowAction';
public static $menu_title = 'Workflows';
public static $menu_priority = -1;
public static $url_segment = 'workflows';

if(!is_numeric($parentId) || !DataObject::get_by_id($parentClass, $parentId)) {
return new SS_HTTPResponse(
null, 400, _t('AdvancedWorkflowAdmin.INVALIDPARENT', 'An invalid parent was specified.')
);
}
}

// if an add form can be returned without writing a new rcord to the database,
// then just do that
if(array_key_exists($class, $this->getManagedModels())) {
$form = $this->$type()->AddForm();
$title = singleton($type)->singular_name();

if($type == 'WorkflowTransition') {
$form->dataFieldByName('ActionID')->setValue($parentId);
}
} else {
$record = new $class;
$record->Title = sprintf(_t('AdvancedWorkflowAdmin.NEWITEM', 'New %s'), $record->singular_name());

if($type == 'WorkflowAction') {
$record->WorkflowDefID = $parentId;
} elseif($type == 'WorkflowTransition') {
$record->ActionID = $parentId;
}

$record->write();

$control = $this->getRecordControllerClass('WorkflowDefinition');
$control = new $control($this->$type(), null, $record->ID);
$form = $control->EditForm();
$title = $record->singular_name();
}

return new SS_HTTPResponse(
$this->isAjax() ? $form->forAjaxTemplate() : $form->forTemplate(), 200,
sprintf(_t('AdvancedWorkflowAdmin.CREATEITEM', 'Fill out this form to create a "%s".'), $title)
);
}

/**
* Returns a dropdown createable classes which all have a common parent class,
* or a label field if only one option is available.
*
* @param string $class The parent class.
* @param bool $includeSelf Include the parent class itself.
* @return DropdownField|LabelField
*/
protected function getClassCreationField($class, $includeSelf = true) {
$classes = ClassInfo::subclassesFor($class);
$createable = array();

if(!$includeSelf) {
array_shift($classes);
}

foreach($classes as $class) {
if(singleton($class)->canCreate()) $createable[$class] = singleton($class)->singular_name();
}

if(count($classes) == 1) {
return new LabelField('Class', current($createable));
}

return new DropdownField(
'Class', '', $createable, '', null, ($includeSelf ? false : _t('AdvancedWorkflowAdmin.SELECT', '(select)'))
);
}
public static $managed_models = 'WorkflowDefinition';
public static $model_importers = array();

}

/**
* A record controller that hides the "Back" button, and shows a message on deletion rather than redirecting to
* the search form.
*
* @package advancedworkflow
* @subpackage admin
*/
class AdvancedWorkflowAdmin_RecordController extends ModelAdmin_RecordController {

/**
* @return Form
*/
public function EditForm() {
$form = parent::EditForm();
$form->Actions()->removeByName('action_goBack');

return $form;
}

/**
* @return string
*/
public function doDelete() {
if($this->currentRecord->canDelete()) {
$this->currentRecord->delete();

$form = new Form(
$this,
'EditForm',
new FieldSet(new LiteralField(
'RecordDeleted',
'<p>' . _t('AdvancedWorkflowAdmin.RECORDDELETED', 'This record has been deleted.') . '</p>'
)),
new FieldSet()
);
return $form->forTemplate();
} else {
return $this->redirectBack();
}
}

}
12 changes: 9 additions & 3 deletions code/dataobjects/WorkflowAction.php
Expand Up @@ -124,16 +124,22 @@ public function numChildren() {
}

public function getCMSFields() {
$fields = new FieldSet(new TabSet('Root'));
$fields = new FieldList(new TabSet('Root'));
$fields->addFieldToTab('Root.Main', new TextField('Title', _t('WorkflowAction.TITLE', 'Title')));
$label = _t('WorkflowAction.ALLOW_EDITING', 'Allow editing during this step?');
$fields->addFieldToTab('Root.Main', new DropdownField('AllowEditing', $label, $this->dbObject('AllowEditing')->enumValues(), 'No'));
return $fields;
}


public function getValidator() {
return new RequiredFields('Title');
}

public function summaryFields() {
return array('Title' => 'Title', 'Transitions' => 'Transitions');
}


public function Icon() {
return $this->stat('icon');
}
}

0 comments on commit 6c94de9

Please sign in to comment.