spivurno
3/9/2014 - 8:09 PM

Gravity Wiz // Gravity Forms Calculation Range

Gravity Wiz // Gravity Forms Calculation Range

<?php

# Default Usage
new GW_Calculation_Range( array(
    'form_id' => 437,
    'field_id' => 1,
    'min' => 3,
    'max' => 4
) );

# Auto-enforce Enabled
new GW_Calculation_Range( array(
    'form_id' => 437,
    'field_id' => 2,
    'min' => 3,
    'max' => 4,
    'auto_enforce' => true
) );
<?php
/**
* Gravity Wiz // Gravity Forms Calculation Range
* 
* Set a minimum and maximum range for your calculation fields.
* 
* @version	 1.0
* @author    David Smith <david@gravitywiz.com>
* @license   GPL-2.0+
* @link      http://gravitywiz.com/...
* @copyright 2013 Gravity Wiz
*/
class GW_Calculation_Range {

    public static $script_output = false;

    public function __construct( $args = array() ) {
        
        // make sure we're running the required minimum version of Gravity Forms
        if( ! property_exists( 'GFCommon', 'version' ) || ! version_compare( GFCommon::$version, '1.8', '>=' ) )
            return;
        
        // 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,
            'field_id'      => false,
            'min'           => false,
            'max'           => false,
            'auto_enforce' => false
        ) );

        extract( $this->_args );

        if( $auto_enforce && ! in_array( GFForms::get_page(), array( 'entry_detail', 'entry_detail_edit' ) ) ) {
            add_action( 'gform_save_field_value', array( $this, 'auto_enforce_range' ), 10, 5 );
            add_action( "gform_pre_render_{$form_id}", array( $this, 'maybe_output_script' ) );
            add_action( "gform_register_init_scripts_{$form_id}", array( $this, 'add_init_script' ) );
        } else {
            add_action( "gform_field_validation_{$form_id}_{$field_id}", array( $this, 'validate_field' ), 10, 4 );
        }

        
    }

    public function maybe_output_script( $form ) {

        if( ! self::$script_output ) {
            $this->script();
            self::$script_output = true;
        }

        return $form;
    }

    public function script() {
        ?>

        <script type="text/javascript">

            var GWCalcRange;

            (function($){

                GWCalcRange = function( args ) {

                    var self = this;

                    // copy all args to current object: formId, fieldId
                    for( prop in args ) {
                        if( args.hasOwnProperty( prop ) )
                            self[prop] = args[prop];
                    }

                    self.init = function() {
                        gform.addFilter( 'gform_calculation_result', function( result, field, formId, GFCalcObj ) {

                            if( field.field_id != self.fieldId )
                                return result;

                            if( self.hasMin() && result < self.min ) {
                                result = self.min;
                            } else if( self.hasMax() && result > self.max ) {
                                result = self.max;
                            }

                            return result;
                        } );
                    }

                    self.hasMin = function() {
                        return self.min !== false;
                    }

                    self.hasMax = function() {
                        return self.max !== false;
                    }

                    self.init();

                }

            })(jQuery);

        </script>

        <?php
    }

    public function add_init_script( $form ) {

        $args = array(
            'formId' => $this->_args['form_id'],
            'fieldId' => $this->_args['field_id'],
            'min' => $this->_args['min'],
            'max' => $this->_args['max']
        );

        $script = '; new GWCalcRange( ' . json_encode( $args ) . ' );';
        $slug = "gw_calc_range_{$this->_args['form_id']}_{$this->_args['field_id']}";

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

    }

    public function auto_enforce_range( $value, $lead, $field, $form, $input_id ) {

        if( $form['id'] != $this->_args['form_id'] )
            return $value;

        if( $field['id'] != $this->_args['field_id'] )
            return $value;

        $input_type = GFFormsModel::get_input_type( $field );
        if( $input_type == 'calculation' && $input_id != "{$field['id']}.2" )
            return $value;

        $value = $this->get_clean_value( GFFormsModel::get_field_value( $field ), $field );

        if( $this->is_min_subceeded( $value ) ) {
            $value = $this->get_min();
        } else if( $this->is_max_exceeded( $value ) ) {
            $value = $this->get_max();
        }

        if( GFFormsModel::get_input_type( $field ) == 'calculation' )
            $value = GFCommon::to_money( $value );

        return $value;
    }
    
    public function validate_field( $result, $value, $form, $field ) {

        $value = $this->get_clean_value( $value, $field );

        if( $this->is_min_subceeded( $value ) || $this->is_max_exceeded( $value ) ) {
            $result = array(
                'is_valid' => false,
                'message' => $this->get_validation_message()
            );
        }

        return $result;
    }

    /**
     * Check if the minimum range has not been met. I know "subceeded" isn't a real word...
     *
     * @param $value
     *
     * @return bool
     */
    public function is_min_subceeded( $value ) {
        return $this->has_min() && $value < $this->get_min();
    }

    public function is_max_exceeded( $value ) {
        return $this->has_max() && $value > $this->get_max();
    }

    public function get_clean_value( $value, $field ) {

        if( GFFormsModel::get_input_type( $field ) != 'calculation' )
            return $value;

        if( is_array( $value ) )
            $value = rgar( $value, "{$field['id']}.2" );

        $value = GFCommon::to_number( $value );

        return $value;
    }

    public function get_validation_message() {

        if( $this->has_max() && $this->has_min() )
            return sprintf( __( 'Please enter a value between <strong>%1$d</strong> and <strong>%2$d</strong>.' ), $this->get_min(), $this->get_max() );

        if( $this->has_min() )
            return sprintf( __( 'Please enter a value greater than or equal to <strong>%d</strong>.' ), $this->get_min() );

        if( $this->has_max() )
            return sprintf( __( 'Please enter a value less than or equal to <strong>%d</strong>.' ), $this->get_max() );

        return false;
    }

    public function has_max() {
        return $this->get_max() !== false;
    }

    public function get_max() {
        return $this->_args['max'];
    }

    public function has_min() {
        return $this->get_min() !== false;
    }

    public function get_min() {
        return $this->_args['min'];
    }

}