Add gravity flow demo

This commit is contained in:
Almira Krdzic
2018-06-28 10:02:07 +02:00
parent 1b5076bf2f
commit 12a5066018
1106 changed files with 317603 additions and 4720 deletions

View File

@@ -0,0 +1,65 @@
<?php
/**
* Allows values to be injected into filters and actions.
*
* @since 1.3.1
*
* Class Gravity_Flow_Form_Connector_Dynamic_Hook
*/
class Gravity_Flow_Form_Connector_Dynamic_Hook {
/**
* @since 1.3.1
*
* @var mixed
*/
private $values;
/**
* @since 1.3.1
*
* @var mixed
*/
private $class = null;
/**
* Stores the values for later use.
*
* @since 1.3.1
*
* @param mixed $values
* @param null $class
*/
public function __construct( $values, $class = null ) {
$this->values = $values;
if ( $class ) {
$this->class = $class;
}
}
/**
* Runs the hook callback function.
*
* @since 1.3.1
*
* @param string $callback The name of the method.
* @param array $filter_args The args called by the filter.
*
* @return mixed
*/
public function __call( $callback, $filter_args ) {
$args = array( $filter_args, $this->values );
if ( $this->class ) {
if ( is_callable( array( $this->class, $callback ) ) ) {
return call_user_func_array( array( $this->class, $callback ), $args );
}
}
if ( is_callable( $callback ) ) {
return call_user_func_array( $callback, $args );
}
}
}

View File

@@ -0,0 +1,268 @@
<?php
/**
* Gravity Flow Delete Entry Step
*
*
* @package GravityFlow
* @subpackage Classes/Step
* @copyright Copyright (c) 2015-2018, Steven Henty S.L.
* @license http://opensource.org/licenses/gpl-3.0.php GNU Public License
* @since 1.3.1-dev
*/
if ( ! class_exists( 'Gravity_Flow_Step_New_Entry' ) ) {
require_once( 'class-step-new-entry.php' );
}
class Gravity_Flow_Step_Delete_Entry extends Gravity_Flow_Step_New_Entry {
public $_step_type = 'delete_entry';
public function get_label() {
return esc_html__( 'Delete an Entry', 'gravityflowformconnector' );
}
/**
* Returns the array of settings for this step.
*
* @return array
*/
public function get_settings() {
$settings = array(
'title' => esc_html__( 'Delete an Entry', 'gravityflow' ),
'fields' => array(
array(
'name' => 'server_type',
'label' => esc_html__( 'Site', 'gravityflowformconnector' ),
'type' => 'radio',
'default_value' => 'local',
'horizontal' => true,
'onchange' => 'jQuery(this).closest("form").submit();',
'choices' => array(
array( 'label' => esc_html__( 'This site', 'gravityflowformconnector' ), 'value' => 'local' ),
array(
'label' => esc_html__( 'A different site', 'gravityflowformconnector' ),
'value' => 'remote'
),
),
),
array(
'name' => 'remote_site_url',
'label' => esc_html__( 'Site Url', 'gravityflowformconnector' ),
'type' => 'text',
'dependency' => array(
'field' => 'server_type',
'values' => array( 'remote' ),
),
),
array(
'name' => 'remote_public_key',
'label' => esc_html__( 'Public Key', 'gravityflowformconnector' ),
'type' => 'text',
'dependency' => array(
'field' => 'server_type',
'values' => array( 'remote' ),
),
),
array(
'name' => 'remote_private_key',
'label' => esc_html__( 'Private Key', 'gravityflowformconnector' ),
'type' => 'text',
'dependency' => array(
'field' => 'server_type',
'values' => array( 'remote' ),
),
),
array(
'name' => 'delete_action',
'label' => esc_html__( 'Delete Action', 'gravityflowformconnector' ),
'type' => 'radio',
'default_value' => 'permanently',
'horizontal' => true,
'choices' => array(
array(
'label' => esc_html__( 'Permanently delete the entry', 'gravityflowformconnector' ),
'value' => 'permanently',
),
array(
'label' => esc_html__( 'Move the entry to the trash', 'gravityflowformconnector' ),
'value' => 'trash',
),
),
'dependency' => array(
'field' => 'server_type',
'values' => array( 'local' ),
),
),
),
);
$entry_id_field = array(
'name' => 'delete_entry_id',
'label' => esc_html__( 'Entry ID Field', 'gravityflowformconnector' ),
'type' => 'field_select',
'tooltip' => __( 'Select the field which will contain the entry ID of the entry that will be deleted. This is used to lookup the entry so it can be deleted.', 'gravityflowformconnector' ),
'required' => true,
);
if ( function_exists( 'gravity_flow_parent_child' ) ) {
$parent_form_choices = array();
$entry_meta = gravity_flow_parent_child()->get_entry_meta( array(), rgget( 'id' ) );
foreach ( $entry_meta as $meta_key => $meta ) {
$parent_form_choices[] = array( 'value' => $meta_key, 'label' => $meta['label'] );
}
if ( ! empty( $parent_form_choices ) ) {
$entry_id_field['args']['append_choices'] = $parent_form_choices;
}
}
$self_entry_id_choice = array(
array(
'label' => esc_html__( 'Entry ID (Self)', 'gravityflowformconnector' ),
'value' => 'id',
),
);
if ( ! isset( $entry_id_field['args']['append_choices'] ) ) {
$entry_id_field['args']['append_choices'] = array();
}
$entry_id_field['args']['append_choices'] = array_merge( $entry_id_field['args']['append_choices'], $self_entry_id_choice );
$settings['fields'][] = $entry_id_field;
return $settings;
}
/**
* Returns the ID of the entry to be deleted.
*/
public function get_target_entry_id() {
$entry = $this->get_entry();
$form = $this->get_form();
$target_entry_id = rgar( $entry, $this->delete_entry_id );
/**
* Allow the ID of the entry to be deleted to be overidden.
*
* @param string|int $target_entry_id The ID of the entry to be deleted.
* @param array $entry The entry being processed by the current step.
* @param array $form The form which created the current entry.
* @param Gravity_Flow_Step_Delete_Entry $step The step currently being processed.
*/
$target_entry_id = apply_filters( 'gravityflowformconnector_delete_entry_id', $target_entry_id, $entry, $form, $this );
return $target_entry_id;
}
/**
* Deletes a local entry.
*
* @return bool Has the step finished?
*/
public function process_local_action() {
$target_entry_id = $this->get_target_entry_id();
if ( empty( $target_entry_id ) ) {
return true;
}
$this->log_debug( __METHOD__ . '(): running for entry #' . $target_entry_id );
if ( $this->delete_action === 'trash' ) {
$result = GFAPI::update_entry_property( $target_entry_id, 'status', 'trash' );
$this->log_debug( __METHOD__ . '() trashed entry: ' . var_export( $result, 1 ) );
if ( $result ) {
$this->add_note( esc_html__( 'Moved entry to the trash.', 'gravityflowformconnector' ) );
}
} elseif ( $target_entry_id == $this->get_entry_id() ) {
gform_add_meta( $target_entry_id, 'workflow_delete_entry', 1 );
$this->log_debug( __METHOD__ . '(): scheduled for deletion.' );
$this->add_note( esc_html__( 'Scheduled entry for deletion on workflow completion.', 'gravityflowformconnector' ) );
} else {
$result = GFAPI::delete_entry( $target_entry_id );
$this->log_debug( __METHOD__ . '(): deleted entry => ' . var_export( $result, 1 ) );
}
return true;
}
/**
* Deletes a remote entry.
*
* @return bool Has the step finished?
*/
public function process_remote_action() {
$target_entry_id = $this->get_target_entry_id();
if ( empty( $target_entry_id ) ) {
return true;
}
$this->delete_remote_entry( $target_entry_id );
return true;
}
/**
* Sends a request to delete a remote entry.
*
* @param int $entry_id The ID of the entry to be deleted.
*
* @return bool
*/
public function delete_remote_entry( $entry_id ) {
$route = 'entries/' . absint( $entry_id );
$method = 'DELETE';
$this->log_debug( __METHOD__ . '(): running for entry #' . $entry_id );
$result = $this->remote_request( $route, $method );
$this->log_debug( __METHOD__ . '(): result => ' . print_r( $result, 1 ) );
return $result;
}
/**
* Deletes the local entries when the Gravity Flow cron is processed.
*
* @return void
*/
public static function cron_delete_local_entries() {
gravity_flow_form_connector()->log_debug( __METHOD__ . '(): Starting.' );
$form_ids = gravity_flow()->get_workflow_form_ids();
if ( empty( $form_ids ) ) {
gravity_flow_form_connector()->log_debug( __METHOD__ . '(): aborting; no applicable forms.' );
return;
}
$criteria = array(
'status' => 'active',
'field_filters' => array(
array(
'key' => 'workflow_delete_entry',
'value' => 1,
),
array(
'key' => 'workflow_final_status',
'operator' => 'not in',
'value' => array( 'pending', 'cancelled' ),
)
),
);
$entry_ids = GFAPI::get_entry_ids( 0, $criteria );
foreach ( $entry_ids as $entry_id ) {
gravity_flow_form_connector()->log_debug( __METHOD__ . '(): deleting entry #' . $entry_id );
$result = GFAPI::delete_entry( $entry_id );
gravity_flow_form_connector()->log_debug( __METHOD__ . '(): result => ' . print_r( $result, 1 ) );
}
gravity_flow_form_connector()->log_debug( __METHOD__ . '(): Finished. Processed: ' . count( $entry_ids ) );
}
}

View File

@@ -0,0 +1,797 @@
<?php
/**
* Gravity Flow Form Submission Step
*
*
* @package GravityFlow
* @subpackage Classes/Step
* @copyright Copyright (c) 2015-2018, Steven Henty S.L.
* @license http://opensource.org/licenses/gpl-3.0.php GNU Public License
* @since 1.0
*/
if ( class_exists( 'Gravity_Flow_Step' ) ) {
class Gravity_Flow_Step_Form_Submission extends Gravity_Flow_Step {
public $_step_type = 'form_submission';
public function get_label() {
return esc_html__( 'Form Submission', 'gravityflowformconnector' );
}
public function get_settings() {
$settings_api = $this->get_common_settings_api();
$forms = $this->get_forms();
$form_choices[] = array( 'label' => esc_html__( 'Select a Form', 'gravityflowformconnector' ), 'value' => '' );
foreach ( $forms as $form ) {
$form_choices[] = array( 'label' => $form->title, 'value' => $form->id );
}
$account_choices = gravity_flow()->get_users_as_choices();
$type_field_choices = array(
array( 'label' => __( 'Select', 'gravityflowformconnector' ), 'value' => 'select' ),
array( 'label' => __( 'Conditional Routing', 'gravityflowformconnector' ), 'value' => 'routing' ),
);
$page_choices = $this->get_page_choices();
$settings = array(
'title' => esc_html__( 'Form Submission', 'gravityflowformconnector' ),
'fields' => array(
$settings_api->get_setting_assignee_type(),
$settings_api->get_setting_assignees(),
$settings_api->get_setting_assignee_routing(),
array(
'id' => 'assignee_policy',
'name' => 'assignee_policy',
'label' => __( 'Assignee Policy', 'gravityflowformconnector' ),
'tooltip' => __( 'Define how this step should be processed. If all assignees must complete this step then the entry will require input from every assignee before the step can be completed. If the step is assigned to a role only one user in that role needs to complete the step.', 'gravityflowformconnector' ),
'type' => 'radio',
'default_value' => 'all',
'choices' => array(
array(
'label' => __( 'At least one assignee must complete this step', 'gravityflowformconnector' ),
'value' => 'any',
),
array(
'label' => __( 'All assignees must complete this step', 'gravityflowformconnector' ),
'value' => 'all',
),
),
),
$settings_api->get_setting_instructions(),
$settings_api->get_setting_display_fields(),
$settings_api->get_setting_notification_tabs( array(
array(
'label' => __( 'Assignee email', 'gravityflowformconnector' ),
'id' => 'tab_assignee_notification',
'fields' => $settings_api->get_setting_notification( array(
'checkbox_default_value' => true,
'default_message' => __( 'Please submit the following form: {workflow_form_submission_link}', 'gravityflowformconnector' ),
) ),
),
) ),
array(
'name' => 'target_form_id',
'label' => esc_html__( 'Form', 'gravityflowformconnector' ),
'tooltip' => __( 'Select the form to be used for this form submission step.', 'gravityflowformconnector' ),
'type' => 'select',
'onchange' => "jQuery(this).closest('form').submit();",
'choices' => $form_choices,
),
array(
'name' => 'submit_page',
'tooltip' => __( 'Select the page to be used for the form submission. This can be the Workflow Submit Page in the WordPress Admin Dashboard or you can choose a page with either a Gravity Flow submit shortcode or a Gravity Forms shortcode.', 'gravityflowformconnector' ),
'label' => __( 'Submission Page', 'gravityflowformconnector' ),
'type' => 'select',
'default_value' => 'admin',
'choices' => $page_choices,
),
),
);
// Use Generic Map setting to allow custom values.
$mapping_field = array(
'name' => 'mappings',
'label' => esc_html__( 'Field Mapping', 'gravityflowformconnector' ),
'type' => 'generic_map',
'enable_custom_key' => false,
'enable_custom_value' => true,
'key_field_title' => esc_html__( 'Field', 'gravityflowformconnector' ),
'value_field_title' => esc_html__( 'Value', 'gravityflowformconnector' ),
'value_choices' => $this->value_mappings(),
'key_choices' => $this->field_mappings(),
'tooltip' => '<h6>' . esc_html__( 'Mapping', 'gravityflowformconnector' ) . '</h6>' . esc_html__( 'Map the fields of this form to the selected form. Values from this form will be saved in the entry in the selected form' , 'gravityflowformconnector' ),
'dependency' => array(
'field' => 'target_form_id',
'values' => array( '_notempty_' ),
),
);
$settings['fields'][] = $mapping_field;
return $settings;
}
/**
* Prepare field map.
*
* @return array
*/
public function field_mappings() {
$target_form_id = $this->get_setting( 'target_form_id' );
if ( empty( $target_form_id ) ) {
return false;
}
$target_form = $this->get_target_form();
if ( empty( $target_form ) ) {
return false;
}
$fields = $this->get_field_map_choices( $target_form );
return $fields;
}
/**
* Prepare value map.
*
* @return array
*/
public function value_mappings() {
$form = $this->get_form();
$fields = $this->get_field_map_choices( $form );
return $fields;
}
function process() {
$this->log_debug( __METHOD__ . '() starting' );
$complete = $this->assign();
$note = $this->get_name() . ': ' . esc_html__( 'Pending.', 'gravityflowformconnector' );
$this->add_note( $note );
$this->log_debug( __METHOD__ . '() complete: ' . $complete );
return $complete;
}
public function status_evaluation() {
$assignee_details = $this->get_assignees();
$step_status = 'complete';
foreach ( $assignee_details as $assignee ) {
$user_status = $assignee->get_status();
if ( $this->type == 'select' && $this->assignee_policy == 'any' ) {
if ( $user_status == 'complete' ) {
$step_status = 'complete';
break;
} else {
$step_status = 'pending';
}
} else if ( empty( $user_status ) || $user_status == 'pending' ) {
$step_status = 'pending';
}
}
return $step_status;
}
public function get_forms() {
$forms = GFFormsModel::get_forms();
return $forms;
}
public function get_target_form() {
$target_form_id = $this->get_setting( 'target_form_id' );
$form = GFAPI::get_form( $target_form_id );
return $form;
}
public function get_field_map_choices( $form, $field_type = null, $exclude_field_types = null ) {
$fields = array();
// Setup first choice
if ( rgblank( $field_type ) || ( is_array( $field_type ) && count( $field_type ) > 1 ) ) {
$first_choice_label = __( 'Select a Field', 'gravityflowformconnector' );
} else {
$type = is_array( $field_type ) ? $field_type[0] : $field_type;
$type = ucfirst( GF_Fields::get( $type )->get_form_editor_field_title() );
$first_choice_label = sprintf( __( 'Select a %s Field', 'gravityflowformconnector' ), $type );
}
$fields[] = array( 'value' => '', 'label' => $first_choice_label );
// if field types not restricted add the default fields and entry meta
if ( is_null( $field_type ) ) {
$fields[] = array( 'value' => 'id', 'label' => esc_html__( 'Entry ID', 'gravityflowformconnector' ) );
$fields[] = array( 'value' => 'date_created', 'label' => esc_html__( 'Entry Date', 'gravityflowformconnector' ) );
$fields[] = array( 'value' => 'ip', 'label' => esc_html__( 'User IP', 'gravityflowformconnector' ) );
$fields[] = array( 'value' => 'source_url', 'label' => esc_html__( 'Source Url', 'gravityflowformconnector' ) );
$fields[] = array( 'value' => 'created_by', 'label' => esc_html__( 'Created By', 'gravityflowformconnector' ) );
$entry_meta = GFFormsModel::get_entry_meta( $form['id'] );
foreach ( $entry_meta as $meta_key => $meta ) {
$fields[] = array( 'value' => $meta_key, 'label' => rgars( $entry_meta, "{$meta_key}/label" ) );
}
}
// Populate form fields
if ( is_array( $form['fields'] ) ) {
foreach ( $form['fields'] as $field ) {
$input_type = $field->get_input_type();
$inputs = $field->get_entry_inputs();
$field_is_valid_type = ( empty( $field_type ) || ( is_array( $field_type ) && in_array( $input_type, $field_type ) ) || ( ! empty( $field_type ) && $input_type == $field_type ) );
if ( is_null( $exclude_field_types ) ) {
$exclude_field = false;
} elseif ( is_array( $exclude_field_types ) ) {
if ( in_array( $input_type, $exclude_field_types ) ) {
$exclude_field = true;
} else {
$exclude_field = false;
}
} else {
//not array, so should be single string
if ( $input_type == $exclude_field_types ) {
$exclude_field = true;
} else {
$exclude_field = false;
}
}
if ( is_array( $inputs ) && $field_is_valid_type && ! $exclude_field ) {
//If this is an address field, add full name to the list
if ( $input_type == 'address' ) {
$fields[] = array(
'value' => $field->id,
'label' => GFCommon::get_label( $field ) . ' (' . esc_html__( 'Full', 'gravityflowformconnector' ) . ')',
);
}
//If this is a name field, add full name to the list
if ( $input_type == 'name' ) {
$fields[] = array(
'value' => $field->id,
'label' => GFCommon::get_label( $field ) . ' (' . esc_html__( 'Full', 'gravityflowformconnector' ) . ')',
);
}
//If this is a checkbox field, add to the list
if ( $input_type == 'checkbox' ) {
$fields[] = array(
'value' => $field->id,
'label' => GFCommon::get_label( $field ) . ' (' . esc_html__( 'Selected', 'gravityflowformconnector' ) . ')',
);
}
foreach ( $inputs as $input ) {
$fields[] = array(
'value' => $input['id'],
'label' => GFCommon::get_label( $field, $input['id'] ),
);
}
} elseif ( $input_type == 'list' && $field->enableColumns && $field_is_valid_type && ! $exclude_field ) {
$fields[] = array(
'value' => $field->id,
'label' => GFCommon::get_label( $field ) . ' (' . esc_html__( 'Full', 'gravityflowformconnector' ) . ')',
);
$col_index = 0;
foreach ( $field->choices as $column ) {
$fields[] = array(
'value' => $field->id . '.' . $col_index,
'label' => GFCommon::get_label( $field ) . ' (' . esc_html( rgar( $column, 'text' ) ) . ')',
);
$col_index ++;
}
} elseif ( ! rgar( $field, 'displayOnly' ) && $field_is_valid_type && ! $exclude_field ) {
$fields[] = array( 'value' => $field->id, 'label' => GFCommon::get_label( $field ) );
}
}
}
return $fields;
}
/**
* Maps the field values of the entry to the target form.
*
* @param $form
* @param $entry
*
* @return array $new_entry
*/
public function do_mapping( $form, $entry ) {
$new_entry = array();
if ( ! is_array( $this->mappings ) ) {
return $new_entry;
}
$target_form = $this->get_target_form();
if ( ! $target_form ) {
$this->log_debug( __METHOD__ . '(): aborting; unable to get target form.' );
return $new_entry;
}
foreach ( $this->mappings as $mapping ) {
if ( rgblank( $mapping['key'] ) ) {
continue;
}
$new_entry = $this->add_mapping_to_entry( $mapping, $entry, $new_entry, $form, $target_form );
}
return apply_filters( 'gravityflowformconnector_' . $this->get_type(), $new_entry, $entry, $form, $target_form, $this );
}
/**
* Add the mapped value to the new entry.
*
* @param array $mapping The properties for the mapping being processed.
* @param array $entry The entry being processed by this step.
* @param array $new_entry The entry to be added or updated.
* @param array $form The form being processed by this step.
* @param array $target_form The target form for the entry being added or updated.
*
* @return array
*/
public function add_mapping_to_entry( $mapping, $entry, $new_entry, $form, $target_form ) {
$target_field_id = trim( $mapping['key'] );
$source_field_id = (string) $mapping['value'];
$source_field = GFFormsModel::get_field( $form, $source_field_id );
if ( is_object( $source_field ) ) {
$is_full_source = $source_field_id === (string) intval( $source_field_id );
$source_field_inputs = $source_field->get_entry_inputs();
$target_field = GFFormsModel::get_field( $target_form, $target_field_id );
if ( $is_full_source && is_array( $source_field_inputs ) ) {
$is_full_target = $target_field_id === (string) intval( $target_field_id );
$target_field_inputs = is_object( $target_field ) ? $target_field->get_entry_inputs() : false;
if ( $is_full_target && is_array( $target_field_inputs ) ) {
foreach ( $source_field_inputs as $input ) {
$input_id = str_replace( $source_field_id . '.', $target_field_id . '.', $input['id'] );
$source_field_value = $this->get_source_field_value( $entry, $source_field, $input['id'] );
$new_entry[ $input_id ] = $this->get_target_field_value( $source_field_value, $target_field, $input_id );
}
} else {
$new_entry[ $target_field_id ] = $source_field->get_value_export( $entry, $source_field_id, true );
}
} else {
$source_field_value = $this->get_source_field_value( $entry, $source_field, $source_field_id );
$new_entry[ $target_field_id ] = $this->get_target_field_value( $source_field_value, $target_field, $target_field_id );
}
} elseif ( $source_field_id == 'gf_custom' ) {
$new_entry[ $target_field_id ] = GFCommon::replace_variables( $mapping['custom_value'], $form, $entry, false, false, false, 'text' );
} else {
$new_entry[ $target_field_id ] = $entry[ $source_field_id ];
}
return $new_entry;
}
/**
* Get the source field value.
*
* Returns the choice text instead of the unique value for choice based poll, quiz and survey fields.
*
* The source field choice unique value will not match the target field unique value.
*
* @param array $entry The entry being processed by this step.
* @param GF_Field $source_field The source field being processed.
* @param string $source_field_id The ID of the source field or input.
*
* @return string
*/
public function get_source_field_value( $entry, $source_field, $source_field_id ) {
if ( ! isset( $entry[ $source_field_id ] ) ) {
return '';
}
$field_value = $entry[ $source_field_id ];
if ( in_array( $source_field->type, array( 'poll', 'quiz', 'survey' ) ) ) {
if ( $source_field->inputType == 'rank' ) {
$values = explode( ',', $field_value );
foreach ( $values as &$value ) {
$value = $this->get_source_choice_text( $value, $source_field );
}
return implode( ',', $values );
}
if ( $source_field->inputType == 'likert' && $source_field->gsurveyLikertEnableMultipleRows ) {
list( $row_value, $field_value ) = rgexplode( ':', $field_value, 2 );
}
return $this->get_source_choice_text( $field_value, $source_field );
}
return $field_value;
}
/**
* Get the value to be set for the target field.
*
* Returns the target fields choice unique value instead of the source field choice text for choice based poll, quiz and survey fields.
*
* @param string $field_value The source field value.
* @param GF_Field $target_field The target field being processed.
* @param string $target_field_id The ID of the target field or input.
*
* @return string
*/
public function get_target_field_value( $field_value, $target_field, $target_field_id ) {
if ( is_object( $target_field ) && in_array( $target_field->type, array( 'poll', 'quiz', 'survey' ) ) ) {
if ( $target_field->inputType == 'rank' ) {
$values = explode( ',', $field_value );
foreach ( $values as &$value ) {
$value = $this->get_target_choice_value( $value, $target_field );
}
return implode( ',', $values );
}
$field_value = $this->get_target_choice_value( $field_value, $target_field );
if ( $target_field->inputType == 'likert' && $target_field->gsurveyLikertEnableMultipleRows ) {
$row_value = $target_field->get_row_id( $target_field_id );
$field_value = sprintf( '%s:%s', $row_value, $field_value );
}
}
return $field_value;
}
/**
* Gets the choice text for the supplied choice value.
*
* @param string $selected_choice The choice value from the source field.
* @param GF_Field $source_field The source field being processed.
*
* @return string
*/
public function get_source_choice_text( $selected_choice, $source_field ) {
return $this->get_choice_property( $selected_choice, $source_field->choices, 'value', 'text' );
}
/**
* Gets the choice value for the supplied choice text.
*
* @param string $selected_choice The choice text from the source field.
* @param GF_Field $target_field The target field being processed.
*
* @return string
*/
public function get_target_choice_value( $selected_choice, $target_field ) {
return $this->get_choice_property( $selected_choice, $target_field->choices, 'text', 'value' );
}
/**
* Helper to get the specified choice property for the selected choice.
*
* @param string $selected_choice The selected choice value or text.
* @param array $choices The field choices.
* @param string $compare_property The choice property the $selected_choice is to be compared against.
* @param string $return_property The choice property to be returned.
*
* @return string
*/
public function get_choice_property( $selected_choice, $choices, $compare_property, $return_property ) {
if ( $selected_choice && is_array( $choices ) ) {
foreach ( $choices as $choice ) {
if ( $choice[ $compare_property ] == $selected_choice ) {
return $choice[ $return_property ];
}
}
}
return $selected_choice;
}
/**
* Display the workflow detail box for this step.
*
* @param array $form The current form.
* @param array $args The page arguments.
*/
public function workflow_detail_box( $form, $args ) {
?>
<div>
<?php
$this->maybe_display_assignee_status_list( $args, $form );
$assignee_status = $this->get_current_assignee_status();
list( $role, $role_status ) = $this->get_current_role_status();
$can_submit = $assignee_status == 'pending' || $role_status == 'pending';
if ( $can_submit ) {
$assignee_key = gravity_flow()->get_current_user_assignee_key();
$assignee = new Gravity_Flow_Assignee( $assignee_key );
$url = $this->get_target_form_url( $this->submit_page, $assignee );
$text = esc_html__( 'Open Form', 'gravityflowformconnector' );
echo '<br /><div class="gravityflow-action-buttons">';
echo sprintf( '<a href="%s" target="_blank" class="button button-large button-primary">%s</a><br><br>', $url, $text );
echo '</div>';
}
?>
</div>
<?php
}
/**
* If applicable display the assignee status list.
*
* @param array $args The page arguments.
* @param array $form The current form.
*/
public function maybe_display_assignee_status_list( $args, $form ) {
$display_step_status = (bool) $args['step_status'];
/**
* Allows the assignee status list to be hidden.
*
* @param array $form
* @param array $entry
* @param Gravity_Flow_Step $current_step
*/
$display_assignee_status_list = apply_filters( 'gravityflow_assignee_status_list_form_submission', $display_step_status, $form, $this );
if ( ! $display_assignee_status_list ) {
return;
}
echo sprintf( '<h4 style="margin-bottom:10px;">%s (%s)</h4>', $this->get_name(), $this->get_status_string() );
echo '<ul>';
$assignees = $this->get_assignees();
$this->log_debug( __METHOD__ . '(): assignee details: ' . print_r( $assignees, true ) );
foreach ( $assignees as $assignee ) {
$assignee_status = $assignee->get_status();
$this->log_debug( __METHOD__ . '(): showing status for: ' . $assignee->get_key() );
$this->log_debug( __METHOD__ . '(): assignee status: ' . $assignee_status );
if ( ! empty( $assignee_status ) ) {
$assignee_type = $assignee->get_type();
$assignee_id = $assignee->get_id();
if ( $assignee_type == 'user_id' ) {
$user_info = get_user_by( 'id', $assignee_id );
$status_label = $this->get_status_label( $assignee_status );
echo sprintf( '<li>%s: %s (%s)</li>', esc_html__( 'User', 'gravityflowformconnector' ), $user_info->display_name, $status_label );
} elseif ( $assignee_type == 'email' ) {
$email = $assignee_id;
$status_label = $this->get_status_label( $assignee_status );
echo sprintf( '<li>%s: %s (%s)</li>', esc_html__( 'Email', 'gravityflowformconnector' ), $email, $status_label );
} elseif ( $assignee_type == 'role' ) {
$status_label = $this->get_status_label( $assignee_status );
$role_name = translate_user_role( $assignee_id );
echo sprintf( '<li>%s: (%s)</li>', esc_html__( 'Role', 'gravityflowformconnector' ), $role_name, $status_label );
echo '<li>' . $role_name . ': ' . $assignee_status . '</li>';
}
}
}
echo '</ul>';
}
/**
* Get the status string, including icon (if complete).
*
* @return string
*/
public function get_status_string() {
$input_step_status = $this->get_status();
$status_str = __( 'Pending Submission', 'gravityflowformconnector' );
if ( $input_step_status == 'complete' ) {
$approve_icon = '<i class="fa fa-check" style="color:green"></i>';
$status_str = $approve_icon . __( 'Complete', 'gravityflowformconnector' );
} elseif ( $input_step_status == 'queued' ) {
$status_str = __( 'Queued', 'gravityflowformconnector' );
}
return $status_str;
}
/**
* Returns the URL for the target form.
*
* @param int|string $page_id
* @param null $assignee
* @param string $access_token
*
* @return string
*/
public function get_target_form_url( $page_id = null, $assignee = null, $access_token = '' ) {
$args = array(
'id' => $this->target_form_id,
'workflow_parent_entry_id' => $this->get_entry_id(),
'workflow_hash' => gravity_flow_form_connector()->get_workflow_hash( $this->get_entry_id(), $this ),
);
if ( $page_id == 'admin' ) {
$args['page'] = 'gravityflow-submit';
}
return Gravity_Flow_Common::get_workflow_url( $args, $page_id, $assignee, $access_token );
}
public function supports_expiration() {
return true;
}
/**
* @param $text
* @param Gravity_Flow_Assignee $assignee
*
* @return mixed
*/
public function replace_variables( $text, $assignee ) {
$text = parent::replace_variables( $text, $assignee );
$comment = rgpost( 'gravityflow_note' );
$text = str_replace( '{workflow_note}', $comment, $text );
preg_match_all( '/{workflow_form_submission_url(:(.*?))?}/', $text, $matches, PREG_SET_ORDER );
if ( is_array( $matches ) ) {
foreach ( $matches as $match ) {
$full_tag = $match[0];
$options_string = isset( $match[2] ) ? $match[2] : '';
$options = shortcode_parse_atts( $options_string );
$args = shortcode_atts(
array(
'page_id' => $this->submit_page,
'token' => false,
), $options
);
$token = $this->get_workflow_access_token( $args, $assignee );
$submission_url = $this->get_target_form_url( $args['page_id'], $assignee, $token );
$submission_url = esc_url_raw( $submission_url );
$text = str_replace( $full_tag, $submission_url, $text );
}
}
preg_match_all( '/{workflow_form_submission_link(:(.*?))?}/', $text, $matches, PREG_SET_ORDER );
if ( is_array( $matches ) ) {
foreach ( $matches as $match ) {
$full_tag = $match[0];
$options_string = isset( $match[2] ) ? $match[2] : '';
$options = shortcode_parse_atts( $options_string );
$target_form_id = $this->get_setting( 'target_form_id' );
$form = GFAPI::get_form( $target_form_id );
$args = shortcode_atts(
array(
'page_id' => $this->submit_page,
'text' => $form['title'],
'token' => false,
), $options
);
$token = $this->get_workflow_access_token( $args, $assignee );
$submission_url = $this->get_target_form_url( $args['page_id'], $assignee, $token );
$submission_url = esc_url_raw( $submission_url );
$submission_link = sprintf( '<a href="%s">%s</a>', $submission_url, esc_html( $args['text'] ) );
$text = str_replace( $full_tag, $submission_link, $text );
}
}
return $text;
}
/**
* Returns the choices for the Submit Page setting.
*
* @return array
*/
public function get_page_choices() {
$choices = array(
array(
'label' => __( 'Default - WordPress Admin Dashboard: Workflow Submit Page', 'gravityflowformconnector' ),
'value' => 'admin',
),
);
$pages = get_pages();
foreach( $pages as $page ) {
$choices[] = array(
'label' => $page->post_title,
'value' => $page->ID,
);
}
return $choices;
}
/**
* Get the access token for the workflow_entry_ and workflow_inbox_ merge tags.
*
* @param array $a The merge tag attributes.
*
* @param null|Gravity_Flow_Assignee $assignee
*
* @return string
*/
public function get_workflow_access_token( $a, $assignee = null ) {
$force_token = $a['token'] == 'true';
$token = '';
if ( $assignee && $force_token ) {
$token_lifetime_days = apply_filters( 'gravityflowformconnector_form_submission_token_expiration_days', 30, $assignee );
$token_expiration_timestamp = strtotime( '+' . (int) $token_lifetime_days . ' days' );
$token = gravity_flow()->generate_access_token( $assignee, null, $token_expiration_timestamp );
}
return $token;
}
/**
* Process a status change for an assignee.
*
* @param Gravity_Flow_Assignee $assignee
* @param string $new_status
* @param array $form
*
* @return string|bool Return a success feedback message safe for page output or false.
*/
public function process_assignee_status( $assignee, $new_status, $form ) {
if ( $new_status != 'complete' ) {
$this->log_debug( __METHOD__ . '() bailing - assignee ' . $assignee->get_key() . ' ' . $new_status );
return false;
}
$current_user_status = $assignee->get_status();
list( $role, $current_role_status ) = $this->get_current_role_status();
if ( $current_user_status == 'pending' ) {
$assignee->update_status( $new_status );
}
if ( $current_role_status == 'pending' ) {
$this->update_role_status( $role, $new_status );
}
$this->log_debug( __METHOD__ . '() assignee ' . $assignee->get_key() . ' complete' );
$note = $this->get_name() . ': ' . esc_html__( 'Processed', 'gravityflow' );
$this->add_note( $note );
return $note;
}
}
}

View File

@@ -0,0 +1,698 @@
<?php
/**
* Gravity Flow Add Entry Step
*
*
* @package GravityFlow
* @subpackage Classes/Step
* @copyright Copyright (c) 2015-2018, Steven Henty S.L.
* @license http://opensource.org/licenses/gpl-3.0.php GNU Public License
* @since 1.0
*/
if ( class_exists( 'Gravity_Flow_Step' ) ) {
class Gravity_Flow_Step_New_Entry extends Gravity_Flow_Step {
public $_step_type = 'new_entry';
public function get_label() {
return esc_html__( 'New Entry', 'gravityflowformconnector' );
}
public function get_settings() {
$forms = $this->get_forms();
$form_choices[] = array( 'label' => esc_html__( 'Select a Form', 'gravityflowformconnector' ), 'value' => '' );
foreach ( $forms as $form ) {
$form_choices[] = array( 'label' => $form->title, 'value' => $form->id );
}
$settings = array(
'title' => esc_html__( 'New Entry', 'gravityflow' ),
'fields' => array(
array(
'name' => 'server_type',
'label' => esc_html__( 'Site', 'gravityflowformconnector' ),
'type' => 'radio',
'default_value' => 'local',
'horizontal' => true,
'onchange' => 'jQuery(this).closest("form").submit();',
'choices' => array(
array( 'label' => esc_html__( 'This site', 'gravityflowformconnector' ), 'value' => 'local' ),
array( 'label' => esc_html__( 'A different site', 'gravityflowformconnector' ), 'value' => 'remote' ),
),
),
array(
'name' => 'remote_site_url',
'label' => esc_html__( 'Site Url', 'gravityflowformconnector' ),
'type' => 'text',
'dependency' => array(
'field' => 'server_type',
'values' => array( 'remote' ),
),
),
array(
'name' => 'remote_public_key',
'label' => esc_html__( 'Public Key', 'gravityflowformconnector' ),
'type' => 'text',
'dependency' => array(
'field' => 'server_type',
'values' => array( 'remote' ),
),
),
array(
'name' => 'remote_private_key',
'label' => esc_html__( 'Private Key', 'gravityflowformconnector' ),
'type' => 'text',
'dependency' => array(
'field' => 'server_type',
'values' => array( 'remote' ),
),
),
array(
'name' => 'target_form_id',
'label' => esc_html__( 'Form', 'gravityflowformconnector' ),
'type' => 'select',
'onchange' => "jQuery(this).closest('form').submit();",
'choices' => $form_choices,
),
),
);
if ( version_compare( gravity_flow()->_version, '1.3.0.10', '>=' ) ) {
// Use Generic Map setting to allow custom values.
$mapping_field = array(
'name' => 'mappings',
'label' => esc_html__( 'Field Mapping', 'gravityflowformconnector' ),
'type' => 'generic_map',
//'callback' => array( gravity_flow_form_connector(), 'generic_map' ),
'enable_custom_key' => false,
'enable_custom_value' => true,
'key_field_title' => esc_html__( 'Field', 'gravityflowformconnector' ),
'value_field_title' => esc_html__( 'Value', 'gravityflowformconnector' ),
'value_choices' => $this->value_mappings(),
'key_choices' => $this->field_mappings(),
'tooltip' => '<h6>' . esc_html__( 'Mapping', 'gravityflowformconnector' ) . '</h6>' . esc_html__( 'Map the fields of this form to the selected form. Values from this form will be saved in the entry in the selected form' , 'gravityflowformconnector' ),
'dependency' => array(
'field' => 'target_form_id',
'values' => array( '_notempty_' ),
),
);
} else {
$mapping_field = array(
'name' => 'mappings',
'label' => esc_html__( 'Field Mapping', 'gravityflowformconnector' ),
'type' => 'dynamic_field_map',
'disable_custom' => true,
'field_map' => $this->field_mappings(),
'tooltip' => '<h6>' . esc_html__( 'Mapping', 'gravityflowformconnector' ) . '</h6>' . esc_html__( 'Map the fields of this form to the selected form. Values from this form will be saved in the entry in the selected form' , 'gravityflowformconnector' ),
'dependency' => array(
'field' => 'target_form_id',
'values' => array( '_notempty_' ),
),
);
}
$settings['fields'][] = $mapping_field;
$entry_id_field = array(
'name' => 'store_new_entry_id',
'label' => esc_html__( 'Store New Entry ID', 'gravityflowformconnector' ),
'type' => 'checkbox_and_container',
'checkbox' => array(
'label' => esc_html__( 'Store the ID of the new entry.', 'gravityflowformconnector' ),
),
'settings' => array(
array(
'name' => 'new_entry_id_field',
'type' => 'field_select',
'args' => array(
'input_types' => array(
'text',
'textarea',
'hidden',
),
),
),
),
);
$settings['fields'][] = $entry_id_field;
return $settings;
}
/**
* Prepare field map.
*
* @return array
*/
public function field_mappings() {
$target_form_id = $this->get_setting( 'target_form_id' );
if ( empty( $target_form_id ) ) {
return false;
}
$target_form = $this->get_target_form( $target_form_id );
if ( empty( $target_form ) ) {
return false;
}
$fields = $this->get_field_map_choices( $target_form );
return $fields;
}
/**
* Prepare value map.
*
* @return array
*/
public function value_mappings() {
$form = $this->get_form();
$fields = $this->get_field_map_choices( $form );
return $fields;
}
function process() {
$server_type = $this->server_type;
if ( $server_type == 'remote' ) {
$result = $this->process_remote_action();
} else {
$result = $this->process_local_action();
}
$note = $this->get_name() . ': ' . esc_html__( 'Processed.', 'gravityflow' );
$this->add_note( $note );
return $result;
}
public function process_local_action() {
$entry = $this->get_entry();
$form = $this->get_form();
$new_entry = $this->do_mapping( $form, $entry );
if ( ! empty( $new_entry ) ) {
$new_entry['form_id'] = $this->target_form_id;
$new_entry['workflow_parent_entry_id'] = $this->get_entry_id();
$entry_id = GFAPI::add_entry( $new_entry );
if ( is_wp_error( $entry_id ) ) {
$this->log_debug( __METHOD__ .'(): failed to add entry' );
} else {
$this->maybe_store_new_entry_id( $entry_id );
}
}
return true;
}
public function process_remote_action() {
$entry = $this->get_entry();
$form = $this->get_form();
$new_entry = $this->do_mapping( $form, $entry );
if ( ! empty( $new_entry ) ) {
$new_entry['form_id'] = $this->target_form_id;
$entry_id = $this->add_remote_entry( $new_entry );
$this->maybe_store_new_entry_id( $entry_id );
}
return true;
}
/**
* Stores the specified entry ID if the setting is enabled.
*
* @param $entry_id
*/
public function maybe_store_new_entry_id( $entry_id ) {
if ( ! $this->store_new_entry_idEnable ) {
$this->log_debug( __METHOD__ .'(): not storing the new entry ID because the setting is not enabled' );
return;
}
$entry_id = absint( $entry_id );
if ( empty( $entry_id ) ) {
$this->log_debug( __METHOD__ .'(): failed to store new entry ID' );
return;
}
$field_id = $this->new_entry_id_field;
GFAPI::update_entry_field( $this->get_entry_id(), $field_id, $entry_id );
}
public function get_forms() {
$server_type = $this->get_setting( 'server_type' );
if ( $server_type == 'remote' ) {
$forms = $this->get_remote_forms();
$forms = json_decode( json_encode( $forms ) );
} else {
$forms = GFFormsModel::get_forms();
}
return $forms;
}
public function get_remote_forms() {
$forms = $this->remote_request( 'forms' );
if ( empty( $forms ) || is_wp_error( $forms ) ) {
$forms = array();
}
return $forms;
}
function calculate_signature( $string, $private_key ) {
$hash = hash_hmac( 'sha1', $string, $private_key, true );
$sig = rawurlencode( base64_encode( $hash ) );
return $sig;
}
public function get_target_form( $form_id ) {
$server_type = $this->get_setting( 'server_type' );
if ( $server_type == 'remote' ) {
$form = $this->get_remote_form( $form_id );
} else {
$form = GFAPI::get_form( $form_id );
}
return $form;
}
public function get_remote_form( $form_id ) {
$form = $this->remote_request( 'forms/' . $form_id );
if ( empty( $form ) || is_wp_error( $form ) ) {
$form = false;
}
$form = GFFormsModel::convert_field_objects( $form );
return $form;
}
public function remote_request( $route, $method = 'GET', $body = null, $query_args = array() ) {
$this->log_debug( __METHOD__ . '(): starting.' );
$site_url = $this->get_setting( 'remote_site_url' );
$api_key = $this->get_setting( 'remote_public_key' );
$private_key = $this->get_setting( 'remote_private_key' );
if ( empty( $site_url ) || empty( $api_key ) || empty( $private_key ) ) {
return false;
}
$expires = strtotime( '+5 mins' );
$string_to_sign = sprintf( '%s:%s:%s:%s', $api_key, $method, $route, $expires );
$this->log_debug( __METHOD__ . '(): string to sign: ' . $string_to_sign );
$sig = $this->calculate_signature( $string_to_sign, $private_key );
$site_url = trailingslashit( $site_url );
$route = trailingslashit( $route );
$url = $site_url . 'gravityformsapi/' . $route . '?api_key=' . $api_key . '&signature=' . $sig . '&expires=' . $expires;
if ( ! empty( $query_args ) ) {
$url .= '&' . http_build_query( $query_args );
}
$args = array( 'method' => $method );
if ( in_array( $method, array( 'POST', 'PUT' ) ) ) {
$args['body'] = $body;
}
$response = wp_remote_request( $url, $args );
$this->log_debug( __METHOD__ . '(): response: ' . print_r( $response, true ) );
$response_body = wp_remote_retrieve_body( $response );
if ( wp_remote_retrieve_response_code( $response ) != 200 || ( empty( $response_body ) ) ) {
return false;
}
$body = json_decode( wp_remote_retrieve_body( $response ), true );
if ( $body['status'] > 202 ) {
return false;
}
return $body['response'];
}
/**
* Add the remote entry
*
* @param $entry
*
* @return int The new Entry ID
*/
public function add_remote_entry( $entry ) {
$target_form_id = $this->target_form_id;
$route = 'forms/' . $target_form_id . '/entries';
$method = 'POST';
$body = json_encode( array( $entry ) );
$entry_ids = $this->remote_request( $route, $method, $body );
return $entry_ids[0];
}
/**
* Returns the field map choices.
*
* @param array $form
* @param null|array|string $field_type
* @param null|array $exclude_field_types
*
* @return array
*/
public function get_field_map_choices( $form, $field_type = null, $exclude_field_types = null ) {
$fields = array();
// Setup first choice
if ( rgblank( $field_type ) || ( is_array( $field_type ) && count( $field_type ) > 1 ) ) {
$first_choice_label = __( 'Select a Field', 'gravityflowformconnector' );
} else {
$type = is_array( $field_type ) ? $field_type[0] : $field_type;
$type = ucfirst( GF_Fields::get( $type )->get_form_editor_field_title() );
$first_choice_label = sprintf( __( 'Select a %s Field', 'gravityflowformconnector' ), $type );
}
$fields[] = array( 'value' => '', 'label' => $first_choice_label );
// if field types not restricted add the default fields and entry meta
if ( is_null( $field_type ) ) {
$fields[] = array( 'value' => 'id', 'label' => esc_html__( 'Entry ID', 'gravityflowformconnector' ) );
$fields[] = array( 'value' => 'date_created', 'label' => esc_html__( 'Entry Date', 'gravityflowformconnector' ) );
$fields[] = array( 'value' => 'ip', 'label' => esc_html__( 'User IP', 'gravityflowformconnector' ) );
$fields[] = array( 'value' => 'source_url', 'label' => esc_html__( 'Source Url', 'gravityflowformconnector' ) );
$fields[] = array( 'value' => 'created_by', 'label' => esc_html__( 'Created By', 'gravityflowformconnector' ) );
$server_type = $this->get_setting( 'server_type' );
$entry_meta = $server_type == 'remote' ? array() : GFFormsModel::get_entry_meta( $form['id'] );
foreach ( $entry_meta as $meta_key => $meta ) {
$fields[] = array( 'value' => $meta_key, 'label' => rgars( $entry_meta, "{$meta_key}/label" ) );
}
}
// Populate form fields
if ( is_array( $form['fields'] ) ) {
foreach ( $form['fields'] as $field ) {
$input_type = $field->get_input_type();
$inputs = $field->get_entry_inputs();
$field_is_valid_type = ( empty( $field_type ) || ( is_array( $field_type ) && in_array( $input_type, $field_type ) ) || ( ! empty( $field_type ) && $input_type == $field_type ) );
if ( is_null( $exclude_field_types ) ) {
$exclude_field = false;
} elseif ( is_array( $exclude_field_types ) ) {
if ( in_array( $input_type, $exclude_field_types ) ) {
$exclude_field = true;
} else {
$exclude_field = false;
}
} else {
//not array, so should be single string
if ( $input_type == $exclude_field_types ) {
$exclude_field = true;
} else {
$exclude_field = false;
}
}
if ( is_array( $inputs ) && $field_is_valid_type && ! $exclude_field ) {
//If this is an address field, add full name to the list
if ( $input_type == 'address' ) {
$fields[] = array(
'value' => $field->id,
'label' => GFCommon::get_label( $field ) . ' (' . esc_html__( 'Full', 'gravityflowformconnector' ) . ')',
);
}
//If this is a name field, add full name to the list
if ( $input_type == 'name' ) {
$fields[] = array(
'value' => $field->id,
'label' => GFCommon::get_label( $field ) . ' (' . esc_html__( 'Full', 'gravityflowformconnector' ) . ')',
);
}
//If this is a checkbox field, add to the list
if ( $input_type == 'checkbox' ) {
$fields[] = array(
'value' => $field->id,
'label' => GFCommon::get_label( $field ) . ' (' . esc_html__( 'Selected', 'gravityflowformconnector' ) . ')',
);
}
foreach ( $inputs as $input ) {
$fields[] = array(
'value' => $input['id'],
'label' => GFCommon::get_label( $field, $input['id'] )
);
}
} elseif ( $input_type == 'list' && $field->enableColumns && $field_is_valid_type && ! $exclude_field ) {
$fields[] = array(
'value' => $field->id,
'label' => GFCommon::get_label( $field ) . ' (' . esc_html__( 'Full', 'gravityflowformconnector' ) . ')',
);
$col_index = 0;
foreach ( $field->choices as $column ) {
$fields[] = array(
'value' => $field->id . '.' . $col_index,
'label' => GFCommon::get_label( $field ) . ' (' . esc_html( rgar( $column, 'text' ) ) . ')',
);
$col_index ++;
}
} elseif ( ! rgar( $field, 'displayOnly' ) && $field_is_valid_type && ! $exclude_field ) {
$fields[] = array( 'value' => $field->id, 'label' => GFCommon::get_label( $field ) );
}
}
}
return $fields;
}
/**
* @param $form
* @param $entry
*
* @return array $new_entry
*/
public function do_mapping( $form, $entry ) {
$new_entry = array();
if ( ! is_array( $this->mappings ) ) {
return $new_entry;
}
$target_form = $this->get_target_form( $this->target_form_id );
if ( ! $target_form ) {
$this->log_debug( __METHOD__ . '(): aborting; unable to get target form.' );
return $new_entry;
}
foreach ( $this->mappings as $mapping ) {
if ( rgblank( $mapping['key'] ) ) {
continue;
}
$new_entry = $this->add_mapping_to_entry( $mapping, $entry, $new_entry, $form, $target_form );
}
return apply_filters( 'gravityflowformconnector_' . $this->get_type(), $new_entry, $entry, $form, $target_form, $this );
}
/**
* Add the mapped value to the new entry.
*
* @param array $mapping The properties for the mapping being processed.
* @param array $entry The entry being processed by this step.
* @param array $new_entry The entry to be added or updated.
* @param array $form The form being processed by this step.
* @param array $target_form The target form for the entry being added or updated.
*
* @return array
*/
public function add_mapping_to_entry( $mapping, $entry, $new_entry, $form, $target_form ) {
$target_field_id = (string) trim( $mapping['key'] );
$source_field_id = (string) $mapping['value'];
$source_field = GFFormsModel::get_field( $form, $source_field_id );
if ( is_object( $source_field ) ) {
$is_full_source = $source_field_id === (string) intval( $source_field_id );
$source_field_inputs = $source_field->get_entry_inputs();
$target_field = GFFormsModel::get_field( $target_form, $target_field_id );
if ( $is_full_source && is_array( $source_field_inputs ) ) {
$is_full_target = $target_field_id === (string) intval( $target_field_id );
$target_field_inputs = is_object( $target_field ) ? $target_field->get_entry_inputs() : false;
if ( $is_full_target && is_array( $target_field_inputs ) ) {
foreach ( $source_field_inputs as $input ) {
$input_id = str_replace( $source_field_id . '.', $target_field_id . '.', $input['id'] );
$source_field_value = $this->get_source_field_value( $entry, $source_field, $input['id'] );
$new_entry[ $input_id ] = $this->get_target_field_value( $source_field_value, $target_field, $input_id );
}
} else {
$new_entry[ $target_field_id ] = $this->get_source_field_value( $entry, $source_field, $source_field_id );
}
} else {
$source_field_value = $this->get_source_field_value( $entry, $source_field, $source_field_id );
$new_entry[ $target_field_id ] = $this->get_target_field_value( $source_field_value, $target_field, $target_field_id );
}
} elseif ( $source_field_id == 'gf_custom' ) {
$new_entry[ $target_field_id ] = GFCommon::replace_variables( $mapping['custom_value'], $form, $entry, false, false, false, 'text' );
} else {
$new_entry[ $target_field_id ] = $entry[ $source_field_id ];
}
return $new_entry;
}
/**
* Get the source field value.
*
* Returns the choice text instead of the unique value for choice based poll, quiz and survey fields.
*
* The source field choice unique value will not match the target field unique value.
*
* @param array $entry The entry being processed by this step.
* @param GF_Field $source_field The source field being processed.
* @param string $source_field_id The ID of the source field or input.
*
* @return string
*/
public function get_source_field_value( $entry, $source_field, $source_field_id ) {
if ( in_array( $source_field->type, array( 'poll', 'quiz', 'survey' ) ) ) {
$field_value = $entry[ $source_field_id ];
if ( $source_field->inputType == 'rank' ) {
$values = explode( ',', $field_value );
foreach ( $values as &$value ) {
$value = $this->get_source_choice_text( $value, $source_field );
}
return implode( ',', $values );
}
if ( $source_field->inputType == 'likert' && $source_field->gsurveyLikertEnableMultipleRows ) {
list( $row_value, $field_value ) = rgexplode( ':', $field_value, 2 );
}
return $this->get_source_choice_text( $field_value, $source_field );
} else {
/**
* Allow choice text to be returned when retrieving the source field value.
*
* @since 1.3.1-dev
*
* @param bool $use_choice_text When processing choice based fields should the choice text be returned instead of the value. Default is false.
* @param GF_Field $source_field The source field being processed.
* @param array $entry The entry being processed by this step.
* @param Gravity_Flow_Step $this The current step.
*/
$use_choice_text = apply_filters( 'gravityflowformconnector_' . $this->get_type() . '_use_choice_text', false, $source_field, $entry, $this );
$field_value = $source_field->get_value_export( $entry, $source_field_id, $use_choice_text );
}
return $field_value;
}
/**
* Get the value to be set for the target field.
*
* Returns the target fields choice unique value instead of the source field choice text for choice based poll, quiz and survey fields.
*
* @param string $field_value The source field value.
* @param GF_Field $target_field The target field being processed.
* @param string $target_field_id The ID of the target field or input.
*
* @return string
*/
public function get_target_field_value( $field_value, $target_field, $target_field_id ) {
if ( is_object( $target_field ) && in_array( $target_field->type, array( 'poll', 'quiz', 'survey' ) ) ) {
if ( $target_field->inputType == 'rank' ) {
$values = explode( ',', $field_value );
foreach ( $values as &$value ) {
$value = $this->get_target_choice_value( $value, $target_field );
}
return implode( ',', $values );
}
$field_value = $this->get_target_choice_value( $field_value, $target_field );
if ( $target_field->inputType == 'likert' && $target_field->gsurveyLikertEnableMultipleRows ) {
$row_value = $target_field->get_row_id( $target_field_id );
$field_value = sprintf( '%s:%s', $row_value, $field_value );
}
}
return $field_value;
}
/**
* Gets the choice text for the supplied choice value.
*
* @param string $selected_choice The choice value from the source field.
* @param GF_Field $source_field The source field being processed.
*
* @return string
*/
public function get_source_choice_text( $selected_choice, $source_field ) {
return $this->get_choice_property( $selected_choice, $source_field->choices, 'value', 'text' );
}
/**
* Gets the choice value for the supplied choice text.
*
* @param string $selected_choice The choice text from the source field.
* @param GF_Field $target_field The target field being processed.
*
* @return string
*/
public function get_target_choice_value( $selected_choice, $target_field ) {
return $this->get_choice_property( $selected_choice, $target_field->choices, 'text', 'value' );
}
/**
* Helper to get the specified choice property for the selected choice.
*
* @param string $selected_choice The selected choice value or text.
* @param array $choices The field choices.
* @param string $compare_property The choice property the $selected_choice is to be compared against.
* @param string $return_property The choice property to be returned.
*
* @return string
*/
public function get_choice_property( $selected_choice, $choices, $compare_property, $return_property ) {
if ( $selected_choice && is_array( $choices ) ) {
foreach ( $choices as $choice ) {
if ( $choice[ $compare_property ] == $selected_choice ) {
return $choice[ $return_property ];
}
}
}
return $selected_choice;
}
}
}

View File

@@ -0,0 +1,525 @@
<?php
/**
* Gravity Flow Update Entry Step
*
*
* @package GravityFlow
* @subpackage Classes/Step
* @copyright Copyright (c) 2015-2018, Steven Henty S.L.
* @license http://opensource.org/licenses/gpl-3.0.php GNU Public License
* @since 1.0
*/
if ( class_exists( 'Gravity_Flow_Step' ) ) {
class Gravity_Flow_Step_Update_Entry extends Gravity_Flow_Step_New_Entry {
public $_step_type = 'update_entry';
public function get_label() {
return esc_html__( 'Update an Entry', 'gravityflowformconnector' );
}
/**
* Returns the array of settings for this step.
*
* @return array
*/
public function get_settings() {
$forms = $this->get_forms();
$form_choices[] = array(
'label' => esc_html__( 'Select a Form', 'gravityflowformconnector' ),
'value' => '',
);
foreach ( $forms as $form ) {
$form_choices[] = array( 'label' => $form->title, 'value' => $form->id );
}
$action_choices = $this->action_choices();
$settings = array(
'title' => esc_html__( 'Update an Entry', 'gravityflow' ),
'fields' => array(
array(
'name' => 'server_type',
'label' => esc_html__( 'Site', 'gravityflowformconnector' ),
'type' => 'radio',
'default_value' => 'local',
'horizontal' => true,
'onchange' => 'jQuery(this).closest("form").submit();',
'choices' => array(
array( 'label' => esc_html__( 'This site', 'gravityflowformconnector' ), 'value' => 'local' ),
array( 'label' => esc_html__( 'A different site', 'gravityflowformconnector' ), 'value' => 'remote' ),
),
),
array(
'name' => 'remote_site_url',
'label' => esc_html__( 'Site Url', 'gravityflowformconnector' ),
'type' => 'text',
'dependency' => array(
'field' => 'server_type',
'values' => array( 'remote' ),
),
),
array(
'name' => 'remote_public_key',
'label' => esc_html__( 'Public Key', 'gravityflowformconnector' ),
'type' => 'text',
'dependency' => array(
'field' => 'server_type',
'values' => array( 'remote' ),
),
),
array(
'name' => 'remote_private_key',
'label' => esc_html__( 'Private Key', 'gravityflowformconnector' ),
'type' => 'text',
'dependency' => array(
'field' => 'server_type',
'values' => array( 'remote' ),
),
),
array(
'name' => 'target_form_id',
'label' => esc_html__( 'Form', 'gravityflowformconnector' ),
'type' => 'select',
'onchange' => "jQuery('#action').val('update');jQuery(this).closest('form').submit();",
'choices' => $form_choices,
),
array(
'name' => 'action',
'label' => esc_html__( 'Action', 'gravityflowformconnector' ),
'type' => count( $action_choices ) == 1 ? 'hidden' : 'select',
'default_value' => 'update',
'horizontal' => true,
'onchange' => "jQuery(this).closest('form').submit();",
'choices' => $action_choices,
),
),
);
$entry_id_field = array(
'name' => 'update_entry_id',
'label' => esc_html__( 'Entry ID Field', 'gravityflowformconnector' ),
'type' => 'field_select',
'tooltip' => __( 'Select the field which will contain the entry ID of the entry that will be updated. This is used to lookup the entry so it can be updated.', 'gravityflowformconnector' ),
'required' => true,
'dependency' => array(
'field' => 'action',
'values' => array( 'update', 'approval', 'user_input' ),
),
);
if ( function_exists( 'gravity_flow_parent_child' ) ) {
$parent_form_choices = array();
$entry_meta = gravity_flow_parent_child()->get_entry_meta( array(), rgget( 'id' ) );
foreach ( $entry_meta as $meta_key => $meta ) {
$parent_form_choices[] = array( 'value' => $meta_key, 'label' => $meta['label'] );
}
if ( ! empty( $parent_form_choices ) ) {
$entry_id_field['args']['append_choices'] = $parent_form_choices;
}
}
if ( $this->get_setting( 'target_form_id' ) == $this->get_form_id() ) {
$self_entry_id_choice = array( array( 'label' => esc_html__( 'Entry ID (Self)', 'gravityflowformconnector' ), 'value' => 'id' ) );
if ( ! isset( $entry_id_field['args']['append_choices'] ) ) {
$entry_id_field['args']['append_choices'] = array();
}
$entry_id_field['args']['append_choices'] = array_merge( $entry_id_field['args']['append_choices'], $self_entry_id_choice );
}
$settings['fields'][] = $entry_id_field;
$settings['fields'][] = array(
'name' => 'approval_status_field',
'label' => esc_html__( 'Approval Status Field', 'gravityflowformconnector' ),
'type' => 'field_select',
'dependency' => array(
'field' => 'action',
'values' => array( 'approval' ),
),
);
$mapping_field = array(
'name' => 'mappings',
'label' => esc_html__( 'Field Mapping', 'gravityflowformconnector' ),
'type' => 'generic_map',
'enable_custom_key' => false,
'enable_custom_value' => true,
'key_field_title' => esc_html__( 'Field', 'gravityflowformconnector' ),
'value_field_title' => esc_html__( 'Value', 'gravityflowformconnector' ),
'value_choices' => $this->value_mappings(),
'key_choices' => $this->field_mappings(),
'tooltip' => '<h6>' . esc_html__( 'Mapping', 'gravityflowformconnector' ) . '</h6>' . esc_html__( 'Map the fields of this form to the selected form. Values from this form will be saved in the entry in the selected form', 'gravityflowformconnector' ),
'dependency' => array(
'field' => 'action',
'values' => array( 'update', 'user_input' ),
),
);
$settings['fields'][] = $mapping_field;
$action = $this->get_setting( 'action' );
if ( $this->get_setting( 'server_type' ) == 'remote' && in_array( $action, array(
'approval',
'user_input',
) )
) {
$target_form_id = $this->get_setting( 'target_form_id' );
if ( ! empty ( $target_form_id ) ) {
$settings['fields'][] = array(
'name' => 'remote_assignee',
'label' => esc_html__( 'Assignee', 'gravityflowformconnector' ),
'type' => 'select',
'choices' => $this->get_remote_assignee_choices( $target_form_id ),
);
}
} elseif ( $this->get_setting( 'server_type' ) == 'local' && $this->get_setting( 'action' ) == 'user_input' ) {
$target_form_id = $this->get_setting( 'target_form_id' );
if ( ! empty ( $target_form_id ) ) {
$settings['fields'][] = array(
'name' => 'local_assignee',
'label' => esc_html__( 'Assignee', 'gravityflowformconnector' ),
'type' => 'select',
'choices' => $this->get_local_assignee_choices( $target_form_id ),
);
}
}
return $settings;
}
/**
* Returns the array of choices for the action setting.
*
* @return array
*/
public function action_choices() {
$choices = array(
array( 'label' => esc_html__( 'Update an Entry', 'gravityflow' ), 'value' => 'update' ),
);
$target_form_id = $this->get_setting( 'target_form_id' );
if ( empty( $target_form_id ) ) {
return $choices;
}
$has_approval_step = false;
$has_user_input_step = false;
if ( $this->get_setting( 'server_type' ) == 'remote' ) {
$steps = $this->get_remote_steps( $target_form_id );
if ( $steps ) {
foreach ( $steps as $step ) {
if ( $step['type'] == 'approval' ) {
$has_approval_step = true;
} elseif ( $step['type'] == 'user_input' ) {
$has_user_input_step = true;
}
}
}
} else {
$api = new Gravity_Flow_API( $target_form_id );
$steps = $api->get_steps();
foreach ( $steps as $step ) {
if ( $step->get_type() == 'approval' ) {
$has_approval_step = true;
} elseif ( $step->get_type() == 'user_input' ) {
$has_user_input_step = true;
}
}
}
if ( $has_approval_step ) {
$choices[] = array( 'label' => esc_html__( 'Approval', 'gravityflow' ), 'value' => 'approval' );
}
if ( $has_user_input_step ) {
$choices[] = array( 'label' => esc_html__( 'User Input', 'gravityflow' ), 'value' => 'user_input' );
}
return $choices;
}
/**
* Updates a local entry.
*
* @return bool Has the step finished?
*/
public function process_local_action() {
$entry = $this->get_entry();
$target_form_id = $this->target_form_id;
$api = new Gravity_Flow_API( $target_form_id );
$steps = $api->get_steps();
$form = $this->get_form();
$target_entry_id = rgar( $entry, $this->update_entry_id );
$target_entry_id = apply_filters( 'gravityflowformconnector_update_entry_id', $target_entry_id, $target_form_id, $entry, $form, $this );
if ( empty( $target_entry_id ) ) {
return true;
}
$target_entry = GFAPI::get_entry( $target_entry_id );
if ( is_wp_error( $target_entry ) ) {
return true;
}
$new_entry = $this->do_mapping( $form, $entry );
$new_entry['form_id'] = $this->target_form_id;
if ( in_array( $this->action, array( 'update', 'user_input' ) ) ) {
if ( ! is_wp_error( $target_entry ) ) {
foreach ( $new_entry as $key => $value ) {
$target_entry[ (string) $key ] = $value;
}
GFAPI::update_entry( $target_entry );
}
}
if ( in_array( $this->action, array( 'approval', 'user_input' ) ) && $steps ) {
if ( empty( $target_entry['workflow_final_status'] ) || $target_entry['workflow_final_status'] == 'pending' ) {
$current_step = $api->get_current_step( $target_entry );
if ( $current_step ) {
$status = ( $this->action == 'approval' ) ? strtolower( rgar( $entry, $this->approval_status_field ) ) : 'complete';
if ( empty( $this->local_assignee ) || $this->local_assignee == 'created_by') {
$assignee_key = gravity_flow()->get_current_user_assignee_key();
if ( ! $assignee_key && rgar( $entry, 'created_by' ) ) {
$assignee_key = 'user_id|' . $entry['created_by'];
}
} else {
$assignee_key = $this->local_assignee;
}
$assignees = array();
if ( $assignee_key ) {
$is_assignee = $current_step->is_assignee( $assignee_key );
if ( $is_assignee ) {
$assignee = new Gravity_Flow_Assignee( $assignee_key, $current_step );
$assignees = array( $assignee );
} else {
// Assignee not set by the local_assignee setting or by current user.
// Could be legacy settings triggered by cron or anonymous form submission.
// Complete step for all assignees.
$assignees = $current_step->get_assignees();
}
}
$form = GFAPI::get_form( $this->target_form_id );
$process_required = false;
foreach ( $assignees as $assignee ) {
$result = $current_step->process_assignee_status( $assignee, $status, $form );
if ( $result ) {
$process_required = true;
}
}
if ( $process_required ) {
$api->process_workflow( $target_entry_id );
}
}
}
}
return true;
}
/**
* Updates a remote entry.
*
*
* @return bool Has the step finished?
*/
public function process_remote_action() {
$entry = $this->get_entry();
$form = $this->get_form();
$new_entry = $this->do_mapping( $form, $entry );
$target_form_id = $this->target_form_id;
$new_entry['form_id'] = $target_form_id;
$target_entry_id = rgar( $entry, $this->update_entry_id );
$target_entry_id = apply_filters( 'gravityflowformconnector_update_entry_id', $target_entry_id, $target_form_id, $entry, $form, $this );
if ( empty( $target_entry_id ) ) {
return true;
}
switch ( $this->action ) {
case 'update' :
case 'user_input' :
$target_entry = $this->get_remote_entry( $target_entry_id );
foreach ( $new_entry as $key => $value ) {
$target_entry[ (string) $key ] = $value;
}
$result = $this->update_remote_entry( $target_entry );
$this->log_debug( __METHOD__ . '(): update result - ' . print_r( $result, true ) );
if ( $this->action == 'user_input' ) {
$assignee_key = strtolower( urlencode( sanitize_text_field( $this->remote_assignee ) ) );
$route = 'entries/' . $target_entry_id . '/assignees/' . $assignee_key;
$body = json_encode( array( 'status' => 'complete' ) );
$assignee_update_result = $this->remote_request( $route, 'POST', $body );
$this->log_debug( __METHOD__ . '(): update assignee result - ' . print_r( $assignee_update_result, true ) );
}
break;
case 'approval' :
$assignee_key = strtolower( urlencode( sanitize_text_field( $this->remote_assignee ) ) );
$status = sanitize_text_field( strtolower( rgar( $entry, $this->approval_status_field ) ) );
$route = sprintf( 'entries/%d/assignees/%s', $target_entry_id, $assignee_key );
$body = json_encode( array( 'status' => $status ) );
$this->remote_request( $route, 'POST', $body );
}
return true;
}
/**
* Returns a remote entry.
*
* @param $entry_id
*
* @return bool
*/
public function get_remote_entry( $entry_id ) {
$route = 'entries/' . $entry_id;
$result = $this->remote_request( $route );
return $result;
}
/**
* Updates a remote entry.
*
* @param $entry
*
* @return bool
*/
public function update_remote_entry( $entry ) {
$route = 'entries/' . absint( $entry['id'] );
$method = 'PUT';
$body = json_encode( $entry );
$result = $this->remote_request( $route, $method, $body );
return $result;
}
/**
* Returns the steps for the remote entry.
*
* @param $form_id
*
* @return bool
*/
public function get_remote_steps( $form_id ) {
$route = 'forms/' . $form_id . '/steps';
$steps = $this->remote_request( $route );
return $steps;
}
/**
* Returns the remote assignees.
*
* @param $form_id
*
* @return array
*/
public function get_remote_assignee_choices( $form_id ) {
$steps = $this->get_remote_steps( $form_id );
if ( empty( $steps ) ) {
return array();
}
$assignee_keys = $choices = array();
foreach ( $steps as $step ) {
foreach ( $step['assignees'] as $assignee ) {
$assignee_keys[ $assignee['key'] ] = $assignee['display_name'];
}
}
foreach ( $assignee_keys as $assignee_key => $display_name ) {
$choices[] = array( 'label' => $display_name, 'value' => $assignee_key );
}
return $choices;
}
/**
* Returns the remote assignees.
*
* @param $form_id
*
* @return array
*/
public function get_local_assignee_choices( $form_id ) {
$steps = gravity_flow()->get_steps( $form_id );
if ( empty( $steps ) ) {
return array();
}
$assignee_keys = $choices = array();
foreach ( $steps as $step ) {
$assignees = $step->get_assignees();
foreach ( $assignees as $assignee ) {
$assignee_keys[ $assignee->get_key() ] = $assignee->get_display_name();
}
}
$source_form = $this->get_form();
$choices[] = array(
'label' => __( 'Select an assignee', 'gravityflow' ),
'value' => '',
);
if ( rgar( $source_form, 'requireLogin' ) ) {
$choices[] = array(
'label' => __( 'User (created_by)', 'gravityflow' ),
'value' => 'created_by',
);
}
foreach ( $assignee_keys as $assignee_key => $display_name ) {
$choices[] = array( 'label' => $display_name, 'value' => $assignee_key );
}
return $choices;
}
}
}