spivurno
10/26/2014 - 3:46 PM

Gravity Wiz // Gravity Forms // AJAX Popluation

Gravity Wiz // Gravity Forms // AJAX Popluation

<?php
/**
 * Gravity Wiz // Gravity Forms // AJAX Population
 *
 * Populate one or many fields from a remote data source (only .csv files are currently supported) based on the selected value of a field on the form.
 *
 * Example: You have multiple brands of lumber. The lumber comes in different sizes. You can store each lumber brand and its corresponding length, width, and height in a spreadsheet (csv format) and then populate this data into separate length, width and height fields on the form when a lumber brand is selectd from a drop down field on the form.
 *
 * @version	  1.1
 * @author    David Smith <david@gravitywiz.com>
 * @license   GPL-2.0+
 * @link      http://gravitywiz.com/...
 */
class GW_AJAX_Population {

	protected static $is_script_output = false;

	public function __construct( $args = array() ) {

		// set our default arguments, parse against the provided arguments, and store for use throughout the class
		$this->_args = wp_parse_args( $args, array(
			'form_id'          => false,
			'target_form_id'   => false,
			'trigger_field_id' => false,
			'data_map'         => array()
		) );

		// map synonyms
		if( $this->_args['target_form_id'] ) {
			$this->_args['form_id'] = $this->_args['target_form_id'];
		}

		// do version check in the init to make sure if GF is going to be loaded, it is already loaded
		add_action( 'init', array( $this, 'init' ) );

	}

	function init() {

		// make sure we're running the required minimum version of Gravity Forms
		if( ! property_exists( 'GFCommon', 'version' ) || ! version_compare( GFCommon::$version, '1.8', '>=' ) ) {
			return;
		}

		// time for hooks
		add_filter( 'gform_pre_render', array( $this, 'load_form_script' ) );
		add_filter( 'gform_register_init_scripts', array( $this, 'add_init_script' ) );

		add_action( 'wp_ajax_gwap_request_data', array( $this, 'ajax_request_data' ) );
		add_action( 'wp_ajax_nopriv_gwap_request_data', array( $this, 'ajax_request_data' ) );

	}

	function load_form_script( $form ) {

		if( $this->is_applicable_form( $form ) && ! self::$is_script_output ) {
			$this->output_script();
		}

		return $form;
	}

	function output_script() {
		?>

		<script type="text/javascript">

			( function( $ ) {

				window.GWAJAXPop = function( args ) {

					var self = this;

					// copy all args to current object: (list expected props)
					for( prop in args ) {
						if( args.hasOwnProperty( prop ) )
							self[prop] = args[prop];
					}

					self.init = function() {

						$triggerField = $( '#input_' + self.formId + '_' + self.triggerFieldId );

						$triggerField.change( function() {

							var value = $( this ).val();

							if( ! value ) {
								self.populateValues( self.getEmptyMapping() );
								return;
							}

							$.post( self.ajaxUrl, {
								action:           'gwap_request_data',
								form_id:          self.formId,
								trigger_field_id: self.triggerFieldId,
								trigger_value:    $( this ).val()
							}, function( response ) {

								response = $.parseJSON( response );

								if( response.is_error ) {
									self.populateValues( self.getEmptyMapping() );
								} else {
									var mapping = response.data;
									self.populateValues( mapping );
								}

							} );

						} );

					};

					self.populateValues = function( values ) {
						$.each( values, function( fieldId, value ) {
							$( '#input_' + self.formId + '_' + fieldId ).val( value );
						} );
					};

					self.getEmptyMapping = function() {

						var mapping = {};

						$.each( self.dataMap, function( column, fieldId ) {
							mapping[ fieldId ] = '';
						} );

						return mapping;
					};

					self.init();

				}

			} )( jQuery );

		</script>

		<?php

		self::$is_script_output = true;

	}

	function add_init_script( $form ) {

		if( ! $this->is_applicable_form( $form ) ) {
			return;
		}

		$args = array(
			'formId'         => $this->_args['form_id'],
			'triggerFieldId' => $this->_args['trigger_field_id'],
			'dataMap'        => $this->_args['data_map'],
			'ajaxUrl'        => admin_url( 'admin-ajax.php' )
		);

		$script = 'new GWAJAXPop( ' . json_encode( $args ) . ' );';
		$slug   = implode( '_', array( 'gw_ajax_pop', $this->_args['form_id'], $this->_args['trigger_field_id'] ) );

		GFFormDisplay::add_init_script( $this->_args['form_id'], $slug, GFFormDisplay::ON_PAGE_RENDER, $script );

	}

	function ajax_request_data() {

		$form_id = rgpost( 'form_id' );
		$trigger_field_id = rgpost( 'trigger_field_id' );

		if( $form_id != $this->_args['form_id'] || $trigger_field_id != $this->_args['trigger_field_id'] ) {
			return;
		}

		$trigger_value = rgpost( 'trigger_value' );
		$data          = $this->get_data( $trigger_value );
		$response      = array();

		if( empty( $data ) ) {
			$response['is_error'] = true;
			$response['message'] = __( 'No data found.' );
		} else {
			$response['is_error'] = false;
			$response['data'] = $data;
		}

		die( json_encode( $response ) );
	}

	function get_data( $source_value ) {

		if( is_callable( $this->_args['ajax_callback'] ) ) {
			$data = call_user_func( $this->_args['ajax_callback'], $source_value, $this );
		} else if( $this->_args['file'] ) {
			$file_data = $this->get_data_from_file( $source_value );
			$data      = $this->sub_columns_for_field_ids( $this->get_row_by_value( $source_value, array_search( $trigger_field_id, $this->_args['data_map'] ), $file_data ) );
		}

		return $data;
	}

	function get_data_from_file( $file ) {

		$data = array();
		$contents = file_get_contents( $file );
		$lines = strpos( $contents, "\n" ) ? explode( "\n", $contents ) : explode( "\r", $contents );

		foreach( $lines as $line ) {
			$bits = explode( ',', $line );
			$row = array();
			foreach( $bits as $index => $bit ) {
				$row[ $this->digits_to_letters( $index ) ] = $bit;
			}
			$data[] = $row;
		}

		return $data;
	}

	function get_row_by_value( $value, $column, $data ) {

		foreach( $data as $row ) {
			if( $row[ $column ] == $value ) {
				return $row;
			}
		}

		return false;
	}

	function sub_columns_for_field_ids( $row ) {
		$_row = array();
		foreach( $row as $column => $value ) {
			$_row[ $this->sub_column_for_field_id( $column ) ] = $value;
		}
		return $_row;
	}

	function sub_column_for_field_id( $column ) {
		$field_id = rgar( $this->_args['data_map'], $column );
		return $field_id ? $field_id : $column;
	}

	function digits_to_letters( $input ) {
		return strtr( $input, '0123456789', 'ABCDEFGHIJ' );
	}

	function is_applicable_form( $form ) {

		$form_id = isset( $form['id'] ) ? $form['id'] : $form;

		return $form_id == $this->_args['form_id'];
	}

}

# Configuration

$tt_ajax_pop = new GW_AJAX_Population( array(
	'source_form_id'   => 1108,  // form on which the unique ID was generated
	'source_field_id'  => 15,    // the field ID of the unique ID
	'target_form_id'   => 1109,  // the form that data will be populated into
	'trigger_field_id' => 9,     // the field that the unique ID will be entered into and trigger the population
	'data_map'  => array(        // a map of field IDs from the source form that should be mapped into field IDs on the target form
		11 => 10                 // 11 = source form field ID, 10 = target form field ID
	),
	'ajax_callback'    => function( $source_value, $ajax_pop_obj ) {

		$entries = GFAPI::get_entries( $ajax_pop_obj->_args['source_form_id'], array(
			'field_filters' => array(
				array(
					'key' => $ajax_pop_obj->_args['source_field_id'],
					'value' => $source_value
				)
			)
		) );

		if( empty( $entries ) ) {
			$entry = array();
		} else {
			$entry = array_shift( $entries );
		}

		$data = array();

		foreach( $ajax_pop_obj->_args['data_map'] as $source_field_id => $target_field_id ) {
			$data[ $target_field_id ] = rgar( $entry, $source_field_id );
		}

		return $data;
	}
) );

new GW_AJAX_Population( array(
	'form_id' => 636,
	'trigger_field_id' => 99,
	// an array of CSV column names and their corresponding field IDs (from the form)
	'data_map' => array(
		'A' => 99,
		'B' => 147,
		'C' => 148
	),
	'file' => ABSPATH . '/wp-content/uploads/Accent Band Sheet.csv'
) );

new GW_AJAX_Population( array(
	'form_id' => 636,
	'trigger_field_id' => 100,
	// an array of CSV column names and their corresponding field IDs (from the form)
	'data_map' => array(
		'A' => 100,
		'B' => 149,
		'C' => 150
	),
	'file' => ABSPATH . '/wp-content/uploads/Accent Band Sheet.csv'
) );

new GW_AJAX_Population( array(
	'form_id' => 636,
	'trigger_field_id' => 101,
	'data_map' => array(
		'A' => 101,
		'B' => 152,
		'C' => 151
	),
	'file' => ABSPATH . '/wp-content/uploads/Accent Band Sheet.csv'
) );