From 7ad6667162894a49b7a3dfb71672650d81f47b33 Mon Sep 17 00:00:00 2001 From: Jaap Jansma <jaap@edeveloper.nl> Date: Mon, 12 Mar 2018 16:02:22 +0100 Subject: [PATCH] Added action name. Easier to handle parameters this way --- CRM/FormProcessor/BAO/FormProcessorAction.php | 33 +++++++++++++++ CRM/FormProcessor/DAO/FormProcessorAction.php | 7 ++++ Civi/FormProcessor/DataBag.php | 10 ++--- ang/form_processor/ActionDialogCtrl.html | 19 ++++++++- ang/form_processor/ActionDialogCtrl.js | 34 ++++++++++++++- ang/form_processor/FormProcessorEditCtrl.js | 34 ++------------- .../FormProcessorEditCtrl/Details.html | 4 +- .../Converttitletoname.php | 34 +++++++++++++++ api/v3/FormProcessorAction/Create.php | 5 +++ api/v3/FormProcessorAction/Validatename.php | 41 +++++++++++++++++++ api/v3/FormProcessorInstance/Validatename.php | 4 +- form_processor.php | 2 +- sql/create_civicrm_form_processor.sql | 1 + 13 files changed, 185 insertions(+), 43 deletions(-) create mode 100644 api/v3/FormProcessorAction/Converttitletoname.php create mode 100644 api/v3/FormProcessorAction/Validatename.php diff --git a/CRM/FormProcessor/BAO/FormProcessorAction.php b/CRM/FormProcessor/BAO/FormProcessorAction.php index 015df03..5853f4b 100644 --- a/CRM/FormProcessor/BAO/FormProcessorAction.php +++ b/CRM/FormProcessor/BAO/FormProcessorAction.php @@ -161,6 +161,39 @@ class CRM_FormProcessor_BAO_FormProcessorAction extends CRM_FormProcessor_DAO_Fo CRM_Utils_Hook::post('delete', 'FormProcessorAction', $action->id, CRM_Core_DAO::$_nullArray); } } + + /** + * Public function to generate name from title + * + * @param $title + * @return string + * @access public + * @static + */ + public static function buildNameFromTitle($title) { + $titleParts = explode(' ', strtolower($title)); + $nameString = implode('_', $titleParts); + return substr($nameString, 0, 80); + } + + /** + * Returns whether the name is valid or not + * + * @param string $name + * @param int $id optional + * @return bool + * @static + */ + public static function isNameValid($name, $id=null) { + $sql = "SELECT COUNT(*) FROM `civicrm_form_processor_action` WHERE `name` = %1"; + $params[1] = array($name, 'String'); + if ($id) { + $sql .= " AND `id` != %2"; + $params[2] = array($id, 'Integer'); + } + $count = CRM_Core_DAO::singleValueQuery($sql, $params); + return ($count > 0) ? false : true; + } } \ No newline at end of file diff --git a/CRM/FormProcessor/DAO/FormProcessorAction.php b/CRM/FormProcessor/DAO/FormProcessorAction.php index fedb335..f7f640a 100644 --- a/CRM/FormProcessor/DAO/FormProcessorAction.php +++ b/CRM/FormProcessor/DAO/FormProcessorAction.php @@ -49,6 +49,12 @@ class CRM_FormProcessor_DAO_FormProcessorAction extends CRM_Core_DAO { 'type' => CRM_Utils_Type::T_INT, 'required' => true, ), + 'name' => array( + 'name' => 'name', + 'title' => E::ts('Name'), + 'type' => CRM_Utils_Type::T_STRING, + 'maxlength' => 80, + ) , 'title' => array( 'name' => 'title', 'title' => E::ts('Title'), @@ -90,6 +96,7 @@ class CRM_FormProcessor_DAO_FormProcessorAction extends CRM_Core_DAO { 'id' => 'id', 'form_processor_instance_id' => 'form_processor_instance_id', 'weight' => 'weight', + 'name' => 'name', 'title' => 'title', 'type' => 'type', 'configuration' => 'configuration', diff --git a/Civi/FormProcessor/DataBag.php b/Civi/FormProcessor/DataBag.php index 194dc50..86b76ff 100644 --- a/Civi/FormProcessor/DataBag.php +++ b/Civi/FormProcessor/DataBag.php @@ -56,7 +56,7 @@ class DataBag { */ public function setActionData(\CRM_FormProcessor_BAO_FormProcessorAction $action, $field, $value) { $this->actions[$action->id] = $action; - $this->actionData[$action->id][$field] = $value; + $this->actionData[$action->name][$field] = $value; return $this; } @@ -67,7 +67,7 @@ class DataBag { * @return string */ public function getActionData(\CRM_FormProcessor_BAO_FormProcessorAction $action) { - return $this->actionData[$action->id]; + return $this->actionData[$action->name]; } /** @@ -89,7 +89,7 @@ class DataBag { public function setActionDataFromActionProviderParameterBag(\CRM_FormProcessor_BAO_FormProcessorAction $action, $parameterBag) { $this->actions[$action->id] = $action; foreach($parameterBag as $field => $value) { - $this->actionData[$action->id][$field] = $value; + $this->actionData[$action->name][$field] = $value; } return $this; } @@ -132,8 +132,8 @@ class DataBag { $aliases[] = 'input.'.$input->name; } foreach($this->actions as $action) { - foreach($this->actionData[$action->id] as $field => $value) { - $aliases[] = 'action.'.$action->id.'.'.$field; + foreach($this->actionData[$action->name] as $field => $value) { + $aliases[] = 'action.'.$action->name.'.'.$field; } } return $aliases; diff --git a/ang/form_processor/ActionDialogCtrl.html b/ang/form_processor/ActionDialogCtrl.html index 59b2caa..d7ec64d 100644 --- a/ang/form_processor/ActionDialogCtrl.html +++ b/ang/form_processor/ActionDialogCtrl.html @@ -6,7 +6,7 @@ <div>{{action.type.title}}</div> </div> - <div crm-ui-field="{name: 'ActionForm.title', title: ts('Title')}"> + <div crm-ui-field="{name: 'ActionForm.title', title: ts('Title'), required: true}"> <input crm-ui-id="addActionForm.title" type="text" @@ -18,6 +18,23 @@ /> </div> + <div crm-ui-field="{name: 'ActionForm.name', title: ts('Name'), required: true}"> + <input + crm-ui-id="addActionForm.name" + type="text" + name="name" + ng-model="action.name" + ng-disabled="locks.name" + required + class="big crm-form-text"/> + + <a crm-ui-lock binding="locks.name"></a> + + <div ng-show="!isValidName(action.name) || !isNameValid"> + <em>{{ts('WARNING: The name includes invalid characters or is already in use by another action.')}}</em> + </div> + </div> + <crm-ap-action-configuration configuration="action.configuration" action="action.type" diff --git a/ang/form_processor/ActionDialogCtrl.js b/ang/form_processor/ActionDialogCtrl.js index f56c60a..d10527d 100644 --- a/ang/form_processor/ActionDialogCtrl.js +++ b/ang/form_processor/ActionDialogCtrl.js @@ -1,10 +1,42 @@ (function(angular, $, _) { - angular.module('form_processor').controller('ActionDialogCtrl', function InputDialogCtrl($scope, dialogService) { + angular.module('form_processor').controller('ActionDialogCtrl', function InputDialogCtrl($scope, dialogService, crmApi) { $scope.ts = CRM.ts(null); $scope.action = angular.copy($scope.model.action); + $scope.locks = {name: true}; + $scope.isNameValid = false; + + $scope.$watch('action.name', function(newName, oldName) { + // Watch for changes in the name field + $scope.isNameValid = false; + if (newName) { + crmApi('FormProcessorAction', 'validatename', {'name': newName,'id': $scope.action.id}) + .then(function(data) { + if (data.is_valid) { + $scope.isNameValid = true; + } + }); + } + }, true); + + $scope.$watch('action.title', function(newTitle, oldTitle) { + // Watch for changes in the name field + if ($scope.locks.name && $scope.action.id <= 0) { + crmApi('FormProcessorAction', 'converttitletoname', {'title': newTitle}) + .then(function(data) { + if (data.name) { + $scope.action.name = data.name; + } + }); + } + }, true); + + $scope.isValidName = function(name) { + return (!name) || name.match(/^[a-z0-9_]+$/) ? true : false; + }; + $scope.saveClick = function() { $scope.model.action = $scope.action; dialogService.close('ActionDialog', $scope.model); diff --git a/ang/form_processor/FormProcessorEditCtrl.js b/ang/form_processor/FormProcessorEditCtrl.js index b19c0b3..0d40165 100644 --- a/ang/form_processor/FormProcessorEditCtrl.js +++ b/ang/form_processor/FormProcessorEditCtrl.js @@ -141,7 +141,6 @@ } }); - var newActions = []; var actionWeight = 0; angular.forEach($scope.formProcessor.actions, function(action, key) { var old_id = action.id; @@ -155,37 +154,10 @@ apiCalls.push(crmApi('FormProcessorAction', 'create', action, true).then(function(action_result) { action.id = action_result.id; action.type = action_type; - if (old_id < 0) { - newActions[old_id] = action.id; - } })); actionWeight++; }); - // Update the mapping - $q.all(apiCalls).then(function(result){ - // We have saved the last action. - // Lets fix the mapping of the actions so that the mapping with an id < 0 - // will be resolved to their new id - angular.forEach($scope.formProcessor.actions, function(action, key) { - var actionChanged = false; - angular.forEach(action.mapping, function (field, parameter) { - var splitted_field = field.split('.'); - if (splitted_field[0] == 'action' && splitted_field[1] < 0) { - action.mapping[parameter] = 'action.'+newActions[splitted_field[1]]+'.'+splitted_field[2]; - actionChanged = true; - } - }); - if (actionChanged) { - var action_type = angular.copy(action.type); - action.type = action.type.name; - crmApi('FormProcessorAction', 'create', action, true).then(function(action_result) { - action.type = action_type; - }); - } - }); - }); - $scope.editFormProcessorForm.$setPristine(); if (goBack) { @@ -264,6 +236,7 @@ id: $scope.new_id, type: angular.copy(actionType), 'title': '', + 'name': '', 'configuration': angular.copy(actionType.default_configuration), 'mapping': {} }; @@ -280,7 +253,7 @@ }); $scope.updateFields($scope.formProcessor, action); - index = $scope.formProcessor.inputs.indexOf(action); + index = $scope.formProcessor.actions.indexOf(action); var model = { formProcessor: $scope.formProcessor, action: action @@ -315,7 +288,6 @@ dialogService.open('OutputHandlerDialog', '~/form_processor/OutputHandlerDialogCtrl.html', model, options) .then(function(data) { $scope.editFormProcessorForm.$setDirty(); - console.log(data); $scope.formProcessor.output_handler = data.outputHandler; }); }; @@ -338,7 +310,7 @@ if (!skipAfter) { angular.forEach(action.type.output_spec, function(output_field, output_field_key) { var field = { - 'name': 'action.'+action.id+'.'+output_field.name, + 'name': 'action.'+action.name+'.'+output_field.name, 'label': 'Action::'+action.title+'::'+output_field.title }; formProcessor.fields.push(field); diff --git a/ang/form_processor/FormProcessorEditCtrl/Details.html b/ang/form_processor/FormProcessorEditCtrl/Details.html index f78991d..63a106e 100644 --- a/ang/form_processor/FormProcessorEditCtrl/Details.html +++ b/ang/form_processor/FormProcessorEditCtrl/Details.html @@ -1,6 +1,6 @@ <div class="crm-block" ng-form="formProcessorDetailForm" crm-ui-id-scope> <div class="crm-group"> - <div crm-ui-field="{name: 'formProcessorDetailForm.title', title: ts('Title')}"> + <div crm-ui-field="{name: 'formProcessorDetailForm.title', title: ts('Title'), required: true}"> <input crm-ui-id="formProcessorDetailForm.title" type="text" @@ -10,7 +10,7 @@ required /> </div> - <div crm-ui-field="{name: 'formProcessorDetailForm.name', title: ts('Name')}"> + <div crm-ui-field="{name: 'formProcessorDetailForm.name', title: ts('Name'), required: true}"> <input crm-ui-id="formProcessorDetailForm.name" type="text" diff --git a/api/v3/FormProcessorAction/Converttitletoname.php b/api/v3/FormProcessorAction/Converttitletoname.php new file mode 100644 index 0000000..34d924f --- /dev/null +++ b/api/v3/FormProcessorAction/Converttitletoname.php @@ -0,0 +1,34 @@ +<?php + +use CRM_FormProcessor_ExtensionUtil as E; + +/** + * FormProcessorAction.Converttitletoname API + * + * @param array $params + * @return array API result descriptor + * @see civicrm_api3_create_success + * @see civicrm_api3_create_error + * @throws API_Exception + */ +function civicrm_api3_form_processor_action_converttitletoname($params) { + $title = $params['title']; + $returnValues['name'] = CRM_FormProcessor_BAO_FormProcessorAction::buildNameFromTitle($title); + return $returnValues; +} + +/** + * FormProcessor.Convgerttitletoname API specification (optional) + * This is used for documentation and validation. + * + * @param array $spec description of fields supported by this API call + * @return void + * @see http://wiki.civicrm.org/confluence/display/CRM/API+Architecture+Standards + */ +function _civicrm_api3_form_processor_action_converttitletoname_spec(&$spec) { + $spec['title'] = array( + 'title' => E::ts('Title'), + 'type' => CRM_Utils_Type::T_STRING, + 'api.required' => true + ); +} \ No newline at end of file diff --git a/api/v3/FormProcessorAction/Create.php b/api/v3/FormProcessorAction/Create.php index b280fce..b3261c4 100644 --- a/api/v3/FormProcessorAction/Create.php +++ b/api/v3/FormProcessorAction/Create.php @@ -27,6 +27,11 @@ function _civicrm_api3_form_processor_action_create_spec(&$spec) { 'type' => CRM_Utils_Type::T_INT, 'api.required' => true, ); + $spec['name'] = array( + 'title' => E::ts('Name'), + 'type' => CRM_Utils_Type::T_STRING, + 'api.required' => true + ); $spec['title'] = array( 'title' => E::ts('Title'), 'type' => CRM_Utils_Type::T_STRING, diff --git a/api/v3/FormProcessorAction/Validatename.php b/api/v3/FormProcessorAction/Validatename.php new file mode 100644 index 0000000..518b53d --- /dev/null +++ b/api/v3/FormProcessorAction/Validatename.php @@ -0,0 +1,41 @@ +<?php + +use CRM_FormProcessor_ExtensionUtil as E; + +/** + * FormProcessorAction.Validatename API + * + * @param array $params + * @return array API result descriptor + * @see civicrm_api3_create_success + * @see civicrm_api3_create_error + * @throws API_Exception + */ +function civicrm_api3_form_processor_action_validatename($params) { + $name = $params['name']; + $id = isset($params['id']) ? $params['id'] : null; + $returnValues['name'] = $name; + $returnValues['is_valid'] = CRM_FormProcessor_BAO_FormProcessorAction::isNameValid($name, $id); + return $returnValues; +} + +/** + * FormProcessor.Validatename API specification (optional) + * This is used for documentation and validation. + * + * @param array $spec description of fields supported by this API call + * @return void + * @see http://wiki.civicrm.org/confluence/display/CRM/API+Architecture+Standards + */ +function _civicrm_api3_form_processor_action_validatename_spec(&$spec) { + $spec['id'] = array( + 'title' => E::ts('ID'), + 'type' => CRM_Utils_Type::T_INT, + 'api.required' => false + ); + $spec['name'] = array( + 'title' => E::ts('Name'), + 'type' => CRM_Utils_Type::T_STRING, + 'api.required' => true + ); +} \ No newline at end of file diff --git a/api/v3/FormProcessorInstance/Validatename.php b/api/v3/FormProcessorInstance/Validatename.php index d048705..6ded749 100644 --- a/api/v3/FormProcessorInstance/Validatename.php +++ b/api/v3/FormProcessorInstance/Validatename.php @@ -3,7 +3,7 @@ use CRM_FormProcessor_ExtensionUtil as E; /** - * FormProcessor.Validatename API + * FormProcessorInstance.Validatename API * * @param array $params * @return array API result descriptor @@ -20,7 +20,7 @@ function civicrm_api3_form_processor_instance_validatename($params) { } /** - * FormProcessor.Validatename API specification (optional) + * FormProcessorInstance.Validatename API specification (optional) * This is used for documentation and validation. * * @param array $spec description of fields supported by this API call diff --git a/form_processor.php b/form_processor.php index ac5b817..f1d633a 100644 --- a/form_processor.php +++ b/form_processor.php @@ -136,7 +136,7 @@ function form_processor_civicrm_navigationMenu(&$params) { 'child' => array( $newNavId + 1 => array( 'attributes' => array( - 'label' => E::ts('Form processors,'), + 'label' => E::ts('Form processors'), 'name' => 'form_processors', 'url' => 'civicrm/admin/automation/formprocessor/#/formprocessors', 'permission' => 'administer CiviCRM', diff --git a/sql/create_civicrm_form_processor.sql b/sql/create_civicrm_form_processor.sql index 14e7a43..5062f63 100644 --- a/sql/create_civicrm_form_processor.sql +++ b/sql/create_civicrm_form_processor.sql @@ -38,6 +38,7 @@ CREATE TABLE IF NOT EXISTS `civicrm_form_processor_action` ( `id` INT UNSIGNED NOT NULL AUTO_INCREMENT, `form_processor_instance_id` INT UNSIGNED NOT NULL, `weight` INT UNSIGNED NOT NULL, + `name` VARCHAR(80) NOT NULL, `title` VARCHAR(80) NOT NULL, `type` VARCHAR(80) NOT NULL, `configuration` TEXT NULL, -- GitLab