From 25e8a9df0aa871e8f038e64fe436134bab056786 Mon Sep 17 00:00:00 2001 From: Jaap Jansma <jaap.jansma@civicoop.org> Date: Fri, 11 Oct 2019 13:21:07 +0200 Subject: [PATCH] Added function to clone a data processor. --- CHANGELOG.md | 1 + CRM/Dataprocessor/Form/CloneDataProcessor.php | 159 ++++++++++++++++++ CRM/Dataprocessor/Form/DataProcessor.php | 4 + api/v3/DataProcessor.php | 3 + .../Dataprocessor/Form/CloneDataProcessor.tpl | 64 +++++++ .../CRM/Dataprocessor/Form/DataProcessor.tpl | 2 +- .../Form/DataProcessorBlocks/Fields.tpl | 13 +- .../Form/ManageDataProcessors.tpl | 21 ++- xml/Menu/dataprocessor.xml | 7 + 9 files changed, 256 insertions(+), 18 deletions(-) create mode 100644 CRM/Dataprocessor/Form/CloneDataProcessor.php create mode 100644 templates/CRM/Dataprocessor/Form/CloneDataProcessor.tpl diff --git a/CHANGELOG.md b/CHANGELOG.md index c1f7c166..2773a6c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ * Fixed issue with updating navigation after editing an output. * Added option to expand criteria forms on search forms. * Added a Date field. +* Added function to clone a data processor. # Version 1.0.7 diff --git a/CRM/Dataprocessor/Form/CloneDataProcessor.php b/CRM/Dataprocessor/Form/CloneDataProcessor.php new file mode 100644 index 00000000..9ec9a0ac --- /dev/null +++ b/CRM/Dataprocessor/Form/CloneDataProcessor.php @@ -0,0 +1,159 @@ +<?php + +use CRM_Dataprocessor_ExtensionUtil as E; + +/** + * Form controller class + * + * @see https://wiki.civicrm.org/confluence/display/CRMDOC/QuickForm+Reference + */ +class CRM_Dataprocessor_Form_CloneDataProcessor extends CRM_Core_Form { + + private $dataProcessorId; + + private $dataProcessor; + + /** + * @var \Civi\DataProcessor\ProcessorType\AbstractProcessorType + */ + private $dataProcessorClass; + + private $currentUrl; + + /** + * Function to perform processing before displaying form (overrides parent function) + * + * @access public + */ + function preProcess() { + $this->dataProcessorId = CRM_Utils_Request::retrieve('id', 'Integer', $this, true); + $this->dataProcessor = civicrm_api3('DataProcessor', 'getsingle', ['id' => $this->dataProcessorId]); + $this->dataProcessorClass = CRM_Dataprocessor_BAO_DataProcessor::dataProcessorToClass($this->dataProcessor, true); + $this->currentUrl = CRM_Utils_System::url('civicrm/dataprocessor/form/edit', array('reset' => 1, 'action' => 'update', 'id' => $this->dataProcessorId)); + $this->assign('data_processor_id', $this->dataProcessorId); + $this->assign('dataProcessor', $this->dataProcessor); + } + + public function buildQuickForm() { + CRM_Utils_System::setTitle(E::ts('Clone data processor: %1', [1=>$this->dataProcessor['title']])); + $this->add('hidden', 'id'); + + $this->add('text', 'name', E::ts('Name'), array('size' => CRM_Utils_Type::HUGE), FALSE); + $this->add('text', 'title', E::ts('Title'), array('size' => CRM_Utils_Type::HUGE), TRUE); + $this->add('text', 'description', E::ts('Description'), array('size' => 100, 'maxlength' => 256)); + $this->add('checkbox', 'is_active', E::ts('Enabled')); + + $this->addButtons(array( + array('type' => 'next', 'name' => E::ts('Save'), 'isDefault' => TRUE,), + array('type' => 'cancel', 'name' => E::ts('Cancel')) + )); + + parent::buildQuickForm(); + } + + /** + * Function to set default values (overrides parent function) + * + * @return array $defaults + * @access public + */ + function setDefaultValues() { + $defaults = array(); + $defaults['id'] = $this->dataProcessorId; + if (!empty($this->dataProcessor) && !empty($this->dataProcessorId)) { + $defaults['title'] = E::ts('Clone of %1', [1=>$this->dataProcessor['title']]); + if (isset($this->dataProcessor['description'])) { + $defaults['description'] = $this->dataProcessor['description']; + } else { + $defaults['description'] = ''; + } + $defaults['is_active'] = $this->dataProcessor['is_active']; + } + return $defaults; + } + + public function postProcess() { + $session = CRM_Core_Session::singleton(); + $values = $this->exportValues(); + $params['name'] = $values['name']; + $params['title'] = $values['title']; + $params['description'] = $values['description']; + $params['is_active'] = !empty($values['is_active']) ? 1 : 0; + + $result = civicrm_api3('DataProcessor', 'create', $params); + $newId = $result['id']; + + $sources = civicrm_api3('DataProcessorSource', 'get', array('data_processor_id' => $this->dataProcessorId, 'options' => array('limit' => 0))); + $dataProcessor['data_sources'] = array(); + foreach($sources['values'] as $i => $datasource) { + unset($datasource['id']); + unset($datasource['data_processor_id']); + $datasource['data_processor_id'] = $newId; + civicrm_api3('DataProcessorSource', 'create', $datasource); + } + $filters = civicrm_api3('DataProcessorFilter', 'get', array('data_processor_id' => $this->dataProcessorId, 'options' => array('limit' => 0))); + $dataProcessor['filters'] = array(); + foreach($filters['values'] as $i => $filter) { + unset($filter['id']); + unset($filter['data_processor_id']); + $filter['data_processor_id'] = $newId; + civicrm_api3('DataProcessorFilter', 'create', $filter); + } + $fields = civicrm_api3('DataProcessorField', 'get', array('data_processor_id' => $this->dataProcessorId, 'options' => array('limit' => 0))); + $dataProcessor['fields'] = array(); + foreach($fields['values'] as $i => $field) { + unset($field['id']); + unset($field['data_processor_id']); + $field['data_processor_id'] = $newId; + civicrm_api3('DataProcessorField', 'create', $field); + } + $outputs = $outputs = civicrm_api3('DataProcessorOutput', 'get', array('data_processor_id' => $this->dataProcessorId, 'options' => array('limit' => 0))); + $dataProcessor['outputs'] = array(); + foreach($outputs['values'] as $i => $output) { + unset($output['id']); + unset($output['data_processor_id']); + $output['data_processor_id'] = $newId; + civicrm_api3('DataProcessorOutput', 'create', $output); + } + + $redirectUrl = CRM_Utils_System::url('civicrm/dataprocessor/form/edit', array('reset' => 1, 'action' => 'update', 'id' => $result['id'])); + CRM_Utils_System::redirect($redirectUrl); + } + + /** + * Function to add validation rules (overrides parent function) + * + * @access public + */ + function addRules() { + if ($this->_action != CRM_Core_Action::DELETE) { + $this->addFormRule(array( + 'CRM_Dataprocessor_Form_DataProcessor', + 'validateName' + )); + } + } + + /** + * Function to validate if rule label already exists + * + * @param array $fields + * @return array|bool + * @access static + */ + static function validateName($fields) { + /* + * if id not empty, edit mode. Check if changed before check if exists + */ + $id = false; + if (empty($fields['name'])) { + $fields['name'] = CRM_Dataprocessor_BAO_DataProcessor::checkName($fields['title'], $id); + } + if (!CRM_Dataprocessor_BAO_DataProcessor::isNameValid($fields['name'], $id)) { + $errors['name'] = E::ts('There is already a data processor with this name'); + return $errors; + } + return TRUE; + } + +} diff --git a/CRM/Dataprocessor/Form/DataProcessor.php b/CRM/Dataprocessor/Form/DataProcessor.php index 41ad721c..edd4f7ad 100644 --- a/CRM/Dataprocessor/Form/DataProcessor.php +++ b/CRM/Dataprocessor/Form/DataProcessor.php @@ -146,18 +146,22 @@ class CRM_Dataprocessor_Form_DataProcessor extends CRM_Core_Form { $this->add('checkbox', 'is_active', E::ts('Enabled')); } if ($this->_action == CRM_Core_Action::ADD) { + CRM_Utils_System::setTitle(E::ts('Add data processor')); $this->addButtons(array( array('type' => 'next', 'name' => E::ts('Next'), 'isDefault' => TRUE,), array('type' => 'cancel', 'name' => E::ts('Cancel')))); } elseif ($this->_action == CRM_Core_Action::DELETE) { + CRM_Utils_System::setTitle(E::ts('Delete data processor: %1', [1=>$this->dataProcessor['title']])); $this->addButtons(array( array('type' => 'next', 'name' => E::ts('Delete'), 'isDefault' => TRUE,), array('type' => 'cancel', 'name' => E::ts('Cancel')))); } elseif ($this->_action == CRM_Core_Action::EXPORT) { + CRM_Utils_System::setTitle(E::ts('Export data processor: %1', [1=>$this->dataProcessor['title']])); $this->addButtons(array( array('type' => 'cancel', 'name' => E::ts('Go back'), 'isDefault' => TRUE), )); } else { + CRM_Utils_System::setTitle(E::ts('Edit data processor: %1', [1=>$this->dataProcessor['title']])); $this->addButtons(array( array('type' => 'next', 'name' => E::ts('Save'), 'isDefault' => TRUE,), array('type' => 'cancel', 'name' => E::ts('Cancel')))); diff --git a/api/v3/DataProcessor.php b/api/v3/DataProcessor.php index 13a9412b..7c0b50c7 100644 --- a/api/v3/DataProcessor.php +++ b/api/v3/DataProcessor.php @@ -28,6 +28,9 @@ function civicrm_api3_data_processor_create($params) { if (isset($params['id'])) { $id = $params['id']; } + if (!isset($params['id']) && !isset($params['status'])) { + $params['status'] = CRM_Dataprocessor_Status::STATUS_IN_DATABASE; + } if (isset($params['title'])) { $params['name'] = CRM_Dataprocessor_BAO_DataProcessor::checkName($params['title'], $id, $params['name']); } diff --git a/templates/CRM/Dataprocessor/Form/CloneDataProcessor.tpl b/templates/CRM/Dataprocessor/Form/CloneDataProcessor.tpl new file mode 100644 index 00000000..d2a72df3 --- /dev/null +++ b/templates/CRM/Dataprocessor/Form/CloneDataProcessor.tpl @@ -0,0 +1,64 @@ +{crmScope extensionKey='dataprocessor'} +<div class="crm-submit-buttons"> + {include file="CRM/common/formButtons.tpl" location="top"} +</div> + +<h3>{ts 1=$dataProcessor.title}Clone Data Processor '%1'{/ts}</h3> +<div class="crm-block crm-form-block crm-data-processor_title-block"> + <div class="crm-section"> + <div class="label">{$form.title.label}</div> + <div class="content"> + {$form.title.html} + <span class=""> + {ts}System name:{/ts} + <span id="systemName" style="font-style: italic;"></span> + <a href="javascript:void(0);" onclick="jQuery('#nameSection').removeClass('hiddenElement'); jQuery(this).parent().addClass('hiddenElement'); return false;"> + {ts}Change{/ts} + </a> + </span> + </div> + <div class="clear"></div> + </div> + <div id="nameSection" class="crm-section hiddenElement"> + <div class="label">{$form.name.label}</div> + <div class="content"> + {$form.name.html} + <p class="description">{ts}Leave empty to let the system generate a name. The name should consist of lowercase letters, numbers and underscore. E.g team_captains.{/ts}</p> + </div> + <div class="clear"></div> + </div> + <div class="crm-section"> + <div class="label">{$form.description.label}</div> + <div class="content">{$form.description.html}</div> + <div class="clear"></div> + </div> + <div class="crm-section"> + <div class="label">{$form.is_active.label}</div> + <div class="content">{$form.is_active.html}</div> + <div class="clear"></div> + </div> +</div> + +<script type="text/javascript"> + {literal} + CRM.$(function($) { + $('#title').on('blur', function() { + var title = $('#title').val(); + if ($('#nameSection').hasClass('hiddenElement')) { + CRM.api3('DataProcessor', 'check_name', { + 'title': title + }).done(function (result) { + $('#systemName').html(result.name); + $('#name').val(result.name); + }); + } + }); + }); + {/literal} +</script> + + +<div class="crm-submit-buttons"> + {include file="CRM/common/formButtons.tpl" location="bottom"} +</div> +{/crmScope} diff --git a/templates/CRM/Dataprocessor/Form/DataProcessor.tpl b/templates/CRM/Dataprocessor/Form/DataProcessor.tpl index de1a0d67..bb912069 100644 --- a/templates/CRM/Dataprocessor/Form/DataProcessor.tpl +++ b/templates/CRM/Dataprocessor/Form/DataProcessor.tpl @@ -12,7 +12,7 @@ {else} -<h3>Data Processor</h3> +<h3>{ts}Data Processor{/ts}</h3> <div class="crm-block crm-form-block crm-data-processor_title-block"> <div class="crm-section"> <div class="label">{$form.title.label}</div> diff --git a/templates/CRM/Dataprocessor/Form/DataProcessorBlocks/Fields.tpl b/templates/CRM/Dataprocessor/Form/DataProcessorBlocks/Fields.tpl index c5ce6b2b..4eec7f69 100644 --- a/templates/CRM/Dataprocessor/Form/DataProcessorBlocks/Fields.tpl +++ b/templates/CRM/Dataprocessor/Form/DataProcessorBlocks/Fields.tpl @@ -12,11 +12,12 @@ <td>{$field.title} <br /><span class="description">{$field.name}</span></td> <td style="width: 60px">{if ($field.weight && !is_numeric($field.weight))}{$field.weight}{/if}</td> <td class="right nowrap" style="width: 100px;"> - <span class="btn-slide crm-hover-button">{ts}Configure{/ts} - <ul class="panel"> - <li><a class="action-item crm-hover-button" href="{crmURL p="civicrm/dataprocessor/form/field" q="reset=1&action=update&data_processor_id=`$field.data_processor_id`&id=`$field.id`"}">{ts}Edit{/ts}</a></li> - <li><a class="action-item crm-hover-button" href="{crmURL p="civicrm/dataprocessor/form/field" q="reset=1&action=delete&data_processor_id=`$field.data_processor_id`&id=`$field.id`"}">{ts}Remove{/ts}</a></li> - </ul> + <span class="btn-slide crm-hover-button">{ts}Configure{/ts} + <ul class="panel"> + <li><a class="action-item crm-hover-button" href="{crmURL p="civicrm/dataprocessor/form/field" q="reset=1&action=update&data_processor_id=`$field.data_processor_id`&id=`$field.id`"}">{ts}Edit{/ts}</a></li> + <li><a class="action-item crm-hover-button" href="{crmURL p="civicrm/dataprocessor/form/field" q="reset=1&action=delete&data_processor_id=`$field.data_processor_id`&id=`$field.id`"}">{ts}Remove{/ts}</a></li> + </ul> + </span> </td> </tr> {/foreach} @@ -27,4 +28,4 @@ <i class='crm-i fa-plus-circle'></i> {ts}Add Field{/ts}</a> </div> </div> -{/crmScope} \ No newline at end of file +{/crmScope} diff --git a/templates/CRM/Dataprocessor/Form/ManageDataProcessors.tpl b/templates/CRM/Dataprocessor/Form/ManageDataProcessors.tpl index e4fe7bf1..ad044c1b 100644 --- a/templates/CRM/Dataprocessor/Form/ManageDataProcessors.tpl +++ b/templates/CRM/Dataprocessor/Form/ManageDataProcessors.tpl @@ -96,16 +96,15 @@ {/foreach} {/if} </td> - <td> - <span> - <a href="{crmURL p='civicrm/dataprocessor/form/edit' q="reset=1&action=update&id=`$data_processor.id`"}" - class="action-item crm-hover-button" title="{ts}Edit Data Processor{/ts}">{ts}Edit{/ts}</a> - <a href="{crmURL p='civicrm/dataprocessor/form/edit' q="reset=1&action=export&id=`$data_processor.id`"}" - class="action-item crm-hover-button" title="{ts}Export Data Processor{/ts}">{ts}Export{/ts}</a> - <a href="{crmURL p='civicrm/dataprocessor/form/edit' q="reset=1&action=delete&id=`$data_processor.id`"}" - class="action-item crm-hover-button" title="{ts}Delete Data Processor{/ts}">{ts}Delete{/ts}</a> - </span> - + <td class="right nowrap" style="width: 100px;"> + <span class="btn-slide crm-hover-button">{ts}Actions{/ts} + <ul class="panel"> + <li><a class="action-item crm-hover-button" href="{crmURL p='civicrm/dataprocessor/form/edit' q="reset=1&action=update&id=`$data_processor.id`"}"title="{ts}Edit Data Processor{/ts}">{ts}Edit{/ts}</a></li> + <li><a class="action-item crm-hover-button" href="{crmURL p='civicrm/dataprocessor/form/clone' q="reset=1&action=add&id=`$data_processor.id`"}" title="{ts}Clone Data Processor{/ts}">{ts}Clone{/ts}</a></li> + <li><a class="action-item crm-hover-button" href="{crmURL p='civicrm/dataprocessor/form/edit' q="reset=1&action=export&id=`$data_processor.id`"}" title="{ts}Export Data Processor{/ts}">{ts}Export{/ts}</a></li> + <li><a class="action-item crm-hover-button" href="{crmURL p='civicrm/dataprocessor/form/edit' q="reset=1&action=delete&id=`$data_processor.id`"}" title="{ts}Delete Data Processor{/ts}">{ts}Delete{/ts}</a></li> + </ul> + </span> </td> </tr> {/foreach} @@ -115,4 +114,4 @@ {include file="CRM/common/pager.tpl" location="bottom"} </div> </div> -{/crmScope} \ No newline at end of file +{/crmScope} diff --git a/xml/Menu/dataprocessor.xml b/xml/Menu/dataprocessor.xml index e8f44a8a..7ef77365 100644 --- a/xml/Menu/dataprocessor.xml +++ b/xml/Menu/dataprocessor.xml @@ -14,6 +14,13 @@ <access_arguments>access CiviCRM</access_arguments> <access_arguments>administer CiviCRM</access_arguments> </item> + <item> + <path>civicrm/dataprocessor/form/clone</path> + <page_callback>CRM_Dataprocessor_Form_CloneDataProcessor</page_callback> + <title>Clone DataProcessor</title> + <access_arguments>access CiviCRM</access_arguments> + <access_arguments>administer CiviCRM</access_arguments> + </item> <item> <path>civicrm/dataprocessor/form/import</path> <page_callback>CRM_Dataprocessor_Form_Import</page_callback> -- GitLab