<commit_before><?php

/**
 * A class that wraps around an array description of a workflow
 * 
 * array(
 *	'Step Name' = array(
 *		'type'		=> class name
 *		'transitions'	=> array(
 *			'transition name' => 'target step',
 *			'next name' => 'other step'
 *		)
 *	),
 *	'Next Step'	= array(
 *		
 *	),
 * )
 * 
 * This can be defined in config yml as follows
 * 
 * Injector:
 *   SimpleReviewApprove:
 *     class: WorkflowTemplate
 *     constructor:
 *       - Review and Approve
 *       - Description of the workflow template
 *       - 0.1 (version number)
 *     properties:
 *       structure:
 *         Apply for approval:
 *           type: AssignUsersToWorkflowAction
 *           transitions: 
 *             notify: Notify users
 *         Notify users:
 *           type: NotifyUsersWorkflowAction
 *           transitions:
 *             approval: Approval
 *         Approval:
 *           type: SimpleApprovalWorkflowAction
 *           transitions:
 *             Approve: Publish
 *             Reject: Reject
 *         Publish:
 *           type: PublishItemWorkflowAction
 *         Reject:
 *           type: CancelWorkflowAction
 *   WorkflowService:
 *     properties:
 *       templates:
 *         - %$SimpleReviewApprove
 * 
 * When updating a template, there's a few things that can be done to assist
 * the system when changing things around
 * 
 * 1. Update the 'version' number 
 * 
 * @author <EMAIL>
 * @license BSD License http://silverstripe.org/bsd-license/
 */
class WorkflowTemplate {
	protected $name;
	protected $description;
	protected $version;
	
	/**
	 * An array representation of the structure of this workflow template
	 * 
	 * @var array
	 */
	protected $structure;
	
	public function __construct($name, $description = '', $version = '0.0') {
		$this->name = $name;
		$this->description = $description;
		$this->version = $version;
	}
	
	public function getName() {
		return $this->name;
	}
	
	public function getVersion() {
		return $this->version;
	}
	
	public function getDescription() {
		return $this->description;
	}
	
	/**
	 * Set the structure for this template
	 * 
	 * @param array $structure 
	 */
	public function setStructure($structure) {
		$this->structure = $structure;
	}
	
	/**
	 * Creates the relevant data objects for this structure, returning an array
	 * of actions in the order they've been created 
	 * 
	 * @param WorkflowDefinition $definitino
	 *				An optional workflow definition to bind the actions into
	 */
	public function createActions($definition = null) {
		$actions = array();
		$transitions = new ArrayObject();
		$sort = 1;
		foreach ($this->structure as $actionName => $actionTemplate) {
			$action = $this->createAction($actionName, $actionTemplate, $definition);
			// add a sort value in! 
			$action->Sort = $sort++;
			$action->write();
			
			$actions[$actionName] = $action;
			
			$newTransitions = $this->updateActionTransitions($actionTemplate, $action);
			foreach ($newTransitions as $t) {
				$transitions->append($t);
			}
		}

		foreach ($transitions as $transition) {
			if (isset($actions[$transition->Target])) {
				$transition->NextActionID = $actions[$transition->Target]->ID;
			}
			
			$transition->write();
		}
		
		return $actions;
	}
	
	/**
	 * Create a workflow action based on a template
	 * 
	 * @param string $name
	 * @param array $template
	 * @param WorkflowDefinition $definition
	 * @return WorkflowAction
	 */
	protected function createAction($name, $actionTemplate, WorkflowDefinition $definition) {
		$type = $actionTemplate['type'];
		if (!$type || !class_exists($type)) {
			throw new Exception('Invalid action class specified in template');
		}

		$action = $type::create();

		$action->Title = $name;

		if (isset($actionTemplate['properties']) && is_array($actionTemplate['properties'])) {
			foreach ($actionTemplate['properties'] as $prop => $val) {
				$action->$prop = $val;
			}
		}

		if ($definition) {
			$action->WorkflowDefID = $definition->ID;
		}

		$action->write();
		
		return $action;
	}
	
	/**
	 * Update the transitions for a given action
	 * <commit_msg>FIX: Provide a default value for WorkflowTemplate::createAction() to prevent errors.<commit_after><?php

/**
 * A class that wraps around an array description of a workflow
 * 
 * array(
 *	'Step Name' = array(
 *		'type'		=> class name
 *		'transitions'	=> array(
 *			'transition name' => 'target step',
 *			'next name' => 'other step'
 *		)
 *	),
 *	'Next Step'	= array(
 *		
 *	),
 * )
 * 
 * This can be defined in config yml as follows
 * 
 * Injector:
 *   SimpleReviewApprove:
 *     class: WorkflowTemplate
 *     constructor:
 *       - Review and Approve
 *       - Description of the workflow template
 *       - 0.1 (version number)
 *     properties:
 *       structure:
 *         Apply for approval:
 *           type: AssignUsersToWorkflowAction
 *           transitions: 
 *             notify: Notify users
 *         Notify users:
 *           type: NotifyUsersWorkflowAction
 *           transitions:
 *             approval: Approval
 *         Approval:
 *           type: SimpleApprovalWorkflowAction
 *           transitions:
 *             Approve: Publish
 *             Reject: Reject
 *         Publish:
 *           type: PublishItemWorkflowAction
 *         Reject:
 *           type: CancelWorkflowAction
 *   WorkflowService:
 *     properties:
 *       templates:
 *         - %$SimpleReviewApprove
 * 
 * When updating a template, there's a few things that can be done to assist
 * the system when changing things around
 * 
 * 1. Update the 'version' number 
 * 
 * @author <EMAIL>.au
 * @license BSD License http://silverstripe.org/bsd-license/
 */
class WorkflowTemplate {
	protected $name;
	protected $description;
	protected $version;
	
	/**
	 * An array representation of the structure of this workflow template
	 * 
	 * @var array
	 */
	protected $structure;
	
	public function __construct($name, $description = '', $version = '0.0') {
		$this->name = $name;
		$this->description = $description;
		$this->version = $version;
	}
	
	public function getName() {
		return $this->name;
	}
	
	public function getVersion() {
		return $this->version;
	}
	
	public function getDescription() {
		return $this->description;
	}
	
	/**
	 * Set the structure for this template
	 * 
	 * @param array $structure 
	 */
	public function setStructure($structure) {
		$this->structure = $structure;
	}
	
	/**
	 * Creates the relevant data objects for this structure, returning an array
	 * of actions in the order they've been created 
	 * 
	 * @param WorkflowDefinition $definitino
	 *				An optional workflow definition to bind the actions into
	 */
	public function createActions($definition = null) {
		$actions = array();
		$transitions = new ArrayObject();
		$sort = 1;
		foreach ($this->structure as $actionName => $actionTemplate) {
			$action = $this->createAction($actionName, $actionTemplate, $definition);
			// add a sort value in! 
			$action->Sort = $sort++;
			$action->write();
			
			$actions[$actionName] = $action;
			
			$newTransitions = $this->updateActionTransitions($actionTemplate, $action);
			foreach ($newTransitions as $t) {
				$transitions->append($t);
			}
		}

		foreach ($transitions as $transition) {
			if (isset($actions[$transition->Target])) {
				$transition->NextActionID = $actions[$transition->Target]->ID;
			}
			
			$transition->write();
		}
		
		return $actions;
	}
	
	/**
	 * Create a workflow action based on a template
	 * 
	 * @param string $name
	 * @param array $template
	 * @param WorkflowDefinition $definition
	 * @return WorkflowAction
	 */
	protected function createAction($name, $actionTemplate, WorkflowDefinition $definition = null) {
		$type = $actionTemplate['type'];
		if (!$type || !class_exists($type)) {
			throw new Exception('Invalid action class specified in template');
		}

		$action = $type::create();

		$action->Title = $name;

		if (isset($actionTemplate['properties']) && is_array($actionTemplate['properties'])) {
			foreach ($actionTemplate['properties'] as $prop => $val) {
				$action->$prop = $val;
			}
		}

		if ($definition) {
			$action->WorkflowDefID = $definition->ID;
		}

		$action->write();
		
		return $action;
	}
	
	/**
	 * Update the transitions for a given action
	 * 
{'fraction_non_alphanumeric': 0.12778782399035563, 'fraction_numerical': 0.0014466546112115732, 'mean_word_length': 2.8550185873605947, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 63, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4873542', 'n_tokens_mistral': 2668, 'n_tokens_neox': 2369, 'n_words': 676}