xlplugins
12/3/2016 - 1:26 PM

Schedule Export for Gravity Forms Entries

Schedule Export for Gravity Forms Entries

<?php
/**
 * @package Gravity XL Scheduled Entries Export
 * @version 1.0
 * @name gravityxl -scheduled-entries-export
 * @author Gravity XL
 */
/**
 * Schedule gform Entry export
 *
 */


    class Gravity_XL_Scheduled_Entries_Export
    {


        public $field_type = null;

        public static $args = null;


        public static $default_meta_keys = array('created_by', 'id', 'date_created', 'source_url', 'transaction_id', 'payment_amount', 'payment_date', 'payment_status', 'post_id', 'user_agent', 'ip');

        /**
         * Class construct to initiate all hooks & loading dependencies
         */
        public function __construct($configs)
        {

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

            self::$args = wp_parse_args($configs, array(
                'form_id' => false,
                'frequency' => 'daily',
                'day_of_week' => '',
                'day_of_month' => '',
                'options' => 'all',
                'email_to' => false,
                'email_from_name' => '',
                'email_from_email' => get_bloginfo('admin_email'),
                'email_timings' => '00:00',
                'email_subject' => __('Your lead export report is ready.'),
                'email_body' => ("Here are your leads export(s) from {start_date} to {end_date}. <br/> <br/> Please Find the attachments."),

            ));


            add_action('init', array(__CLASS__, 'initHooks'));

            add_action('wp', array(__CLASS__, 'maybe_initiate_crons'));


        }

        public static function maybe_initiate_crons()
        {
            if (isset(self::$args['form_id']) && self::$args['form_id'] !== false && !wp_next_scheduled('gxl_scheduled_entry_export_' . self::$args['form_id'])) {
                wp_schedule_event(self::crontimings(self::$args), 'daily', 'gxl_scheduled_entry_export_' . self::$args['form_id'], array(self::$args));
            }

            //try and run it
            self::maybe_init_scheduled_export(self::$args);
        }

        public static function crontimings($args)
        {
            $local_timestamp = strtotime(date("Y-m-d") . " " . self::get_timing($args));
            $gmt_timestamp = self::get_gmt_timestamp($local_timestamp);
            return $gmt_timestamp;
        }

        public static function initHooks()
        {


            add_action('gxl_scheduled_entry_export_' . self::$args['form_id'], array(__CLASS__, 'maybe_init_scheduled_export'));
        }


        /**
         * Controller function
         * @param $args
         */
        public static function maybe_init_scheduled_export($args)
        {


            if (!self::maybe_run_export($args)) {
                return;
            }

            $form = RGFormsModel::get_form_meta($args['form_id']);


            $options = self::prepere_options_and_fields($form, $args);

            ob_start();
            if (!empty($options)) {

                self::start_export($form, $options, $args);

            }
            $expected_csv_data = ob_get_clean();


            $get_file = self::try_and_savefile($expected_csv_data, $args);


            self::send_mail($args['email_from_email'], $args['email_to'], "", "", $args['email_subject'], self::parse_body($args['email_body'], $args, $options), $args['email_from_name'], "html", $get_file);


        }

        public static function parse_body($body, $args, $data)
        {
            $body = str_replace("{start_date}", $data['export_date_start'], $body);
            $body = str_replace("{end_date}", $data['export_date_end'], $body);

            return $body;

        }


        public static function prepere_options_and_fields($form, $args)
        {

            $data_return = array();
            $data_return['export_field'] = array();


            if (!empty($form['fields']) && $args['options'] == "all") {


                foreach ($form['fields'] as $fields) {

                    if ($fields->displayOnly === true) {
                        continue;
                    }
                    array_push($data_return['export_field'], $fields->id);
                }
            }


            if ($args['options'] == "all") {
                foreach (self::$default_meta_keys as $keys) {
                    array_push($data_return['export_field'], $keys);
                }
            } else {
                foreach ($args['options'] as $keys) {
                    array_push($data_return['export_field'], $keys);
                }
            }


            $data_return = array_merge($data_return, self::get_dates($args));


            return $data_return;
        }


        private static function try_and_savefile($data, $args)
        {

            $path = self::get_upload_root();

            if (!file_exists($path)) {
                wp_mkdir_p($path);
                touch($path . 'index.php');
            }

            $file = fopen($path . self::get_file_name($args), 'w');

            fwrite($file, $data);

            fclose($file);

            return self::get_upload_root() . self::get_file_name($args);


        }

        private static function get_file_name($args)
        {
            $form = RGFormsModel::get_form_meta($args['form_id']);
            $filename = sanitize_title_with_dashes($form['title']) . '-' . gmdate('Y-m-d', GFCommon::get_local_timestamp(time())) . '.csv';
            return $filename;
        }

        private static function get_upload_root_url()
        {
            $dir = wp_upload_dir();

            if ($dir['error']) {
                return null;
            }

            return $dir['baseurl'] . '/gxl_scheduled_entries_export/';
        }

        private static function get_upload_root()
        {
            $dir = wp_upload_dir();

            if ($dir['error']) {
                return null;
            }

            return $dir['basedir'] . '/gxl_scheduled_entries_export/';
        }

        public static function start_export($form, $data, $args)
        {

            $form_id = $form['id'];
            $fields = $data['export_field'];


            $start_date = empty($data['export_date_start']) ? '' : self::get_gmt_date($data['export_date_start'] . ' ' . self::get_timing($args));
            $end_date = empty($data['export_date_end']) ? '' : self::get_gmt_date($data['export_date_end'] . ' ' . self::get_timing($args));


            $search_criteria['status'] = 'active';
            $search_criteria['field_filters'] = GFCommon::get_field_filters_from_post($form);
            if (!empty($start_date)) {
                $search_criteria['start_date'] = $start_date;
            }

            if (!empty($end_date)) {
                $search_criteria['end_date'] = $end_date;
            }

            $sorting = array('key' => 'date_created', 'direction' => 'DESC', 'type' => 'info');


            $form = self::add_default_export_fields($form);


            $entry_count = GFAPI::count_entries($form_id, $search_criteria);

            $page_size = 100;
            $offset = 0;

            //Adding BOM marker for UTF-8
            $lines = chr(239) . chr(187) . chr(191);

            // set the separater
            $separator = gf_apply_filters(array('gform_export_separator', $form_id), ',', $form_id);

            $field_rows = self::get_field_row_count($form, $fields, $entry_count);

            //writing header
            $headers = array();
            foreach ($fields as $field_id) {
                $field = RGFormsModel::get_field($form, $field_id);
                $label = gf_apply_filters(array('gform_entries_field_header_pre_export', $form_id, $field_id), GFCommon::get_label($field, $field_id), $form, $field);
                $value = str_replace('"', '""', $label);


                if (strpos($value, '=') === 0) {
                    // Prevent Excel formulas
                    $value = "'" . $value;
                }

                $headers[$field_id] = $value;

                $subrow_count = isset($field_rows[$field_id]) ? intval($field_rows[$field_id]) : 0;
                if ($subrow_count == 0) {
                    $lines .= '"' . $value . '"' . $separator;
                } else {
                    for ($i = 1; $i <= $subrow_count; $i++) {
                        $lines .= '"' . $value . ' ' . $i . '"' . $separator;
                    }
                }


            }
            $lines = substr($lines, 0, strlen($lines) - 1) . "\n";

            //paging through results for memory issues
            while ($entry_count > 0) {

                $paging = array(
                    'offset' => $offset,
                    'page_size' => $page_size,
                );
                $leads = GFAPI::get_entries($form_id, $search_criteria, $sorting, $paging);

                $leads = gf_apply_filters(array('gform_leads_before_export', $form_id), $leads, $form, $paging);

                foreach ($leads as $lead) {
                    foreach ($fields as $field_id) {
                        switch ($field_id) {
                            case 'date_created' :
                                $lead_gmt_time = mysql2date('G', $lead['date_created']);
                                $lead_local_time = GFCommon::get_local_timestamp($lead_gmt_time);
                                $value = date_i18n('Y-m-d H:i:s', $lead_local_time, true);
                                break;
                            default :
                                $field = RGFormsModel::get_field($form, $field_id);

                                $value = is_object($field) ? $field->get_value_export($lead, $field_id, false, true) : rgar($lead, $field_id);
                                $value = apply_filters('gform_export_field_value', $value, $form_id, $field_id, $lead);

                                GFCommon::log_debug("GFExport::start_export(): Value for field ID {$field_id}: {$value}");
                                break;
                        }

                        if (isset($field_rows[$field_id])) {
                            $list = empty($value) ? array() : unserialize($value);

                            foreach ($list as $row) {
                                $row_values = array_values($row);
                                $row_str = implode('|', $row_values);

                                if (strpos($row_str, '=') === 0) {
                                    // Prevent Excel formulas
                                    $row_str = "'" . $row_str;
                                }

                                $lines .= '"' . str_replace('"', '""', $row_str) . '"' . $separator;
                            }

                            //filling missing subrow columns (if any)
                            $missing_count = intval($field_rows[$field_id]) - count($list);
                            for ($i = 0; $i < $missing_count; $i++) {
                                $lines .= '""' . $separator;
                            }
                        } else {
                            $value = maybe_unserialize($value);
                            if (is_array($value)) {
                                $value = implode('|', $value);
                            }

                            if (strpos($value, '=') === 0) {
                                // Prevent Excel formulas
                                $value = "'" . $value;
                            }

                            $lines .= '"' . str_replace('"', '""', $value) . '"' . $separator;
                        }
                    }
                    $lines = substr($lines, 0, strlen($lines) - 1);


                    $lines .= "\n";
                }

                $offset += $page_size;
                $entry_count -= $page_size;

                if (!seems_utf8($lines)) {
                    $lines = utf8_encode($lines);
                }

                $lines = apply_filters('gform_export_lines', $lines);

                echo $lines;

                $lines = '';
            }
        }


        public static function maybe_run_export($args)
        {


            if (!isset($args['frequency'])) {
                return false;
            }

            $maybe_run = false;


            switch ($args['frequency']) {


                case "daily":
                    $maybe_run = true;
                    break;
                case "weekly":
                    if (strtolower(date('l')) == strtolower($args['day_of_week'])) {
                        $maybe_run = true;
                    }


                    break;

                case "monthly":
                    if ((date('D')) == ($args['day_of_month']) || (date('d')) == $args['day_of_month']) {
                        $maybe_run = true;
                    }
                    break;


            }

            return $maybe_run;


        }


        private static function get_dates($args)
        {


            $dates = array();
            $dates['export_date_start'] = '';
            $dates['export_date_end'] = '';


            switch ($args['frequency']) {


                case "daily":
                    $dates['export_date_end'] = date('Y-m-d');

                    $phpDateTime = new DateTime();
                    $phpDateTime->setTimestamp(time());
                    $phpDateTime->modify("-1 day");
                    $dates['export_date_start'] = $phpDateTime->format('Y-m-d');
                    break;
                case "weekly":

                    if (strtolower(date('l')) == strtolower($args['day_of_week'])) {

                        $dates['export_date_end'] = date('Y-m-d');

                        $phpDateTime = new DateTime();
                        $phpDateTime->setTimestamp(time());
                        $phpDateTime->modify("-6 days");
                        $dates['export_date_start'] = $phpDateTime->format('Y-m-d');

                    }
                    break;

                case "monthly":
                    if (date('D') == $args['day_of_month'] || date('d') == $args['day_of_month']) {
                        $dates['export_date_end'] = date('Y-m-d');

                        $phpDateTime = new DateTime();
                        $phpDateTime->setTimestamp(time());
                        $phpDateTime->modify("-29 days");
                        $dates['export_date_start'] = $phpDateTime->format('Y-m-d');
                    }
                    break;


            }

            return $dates;


        }

        public static function get_gmt_timestamp($local_timestamp)
        {
            return $local_timestamp - (get_option('gmt_offset') * 3600);
        }

        public static function get_gmt_date($local_date)
        {

            $local_timestamp = strtotime($local_date);
            $gmt_timestamp = self::get_gmt_timestamp($local_timestamp);
            $date = gmdate('Y-m-d H:i:s', $gmt_timestamp);

            return $date;
        }


        public static function add_default_export_fields($form)
        {

            //adding default fields
            array_push($form['fields'], array('id' => 'created_by', 'label' => __('Created By (User Id)', 'gravityforms')));
            array_push($form['fields'], array('id' => 'id', 'label' => __('Entry Id', 'gravityforms')));
            array_push($form['fields'], array('id' => 'date_created', 'label' => __('Entry Date', 'gravityforms')));
            array_push($form['fields'], array('id' => 'source_url', 'label' => __('Source Url', 'gravityforms')));
            array_push($form['fields'], array('id' => 'transaction_id', 'label' => __('Transaction Id', 'gravityforms')));
            array_push($form['fields'], array('id' => 'payment_amount', 'label' => __('Payment Amount', 'gravityforms')));
            array_push($form['fields'], array('id' => 'payment_date', 'label' => __('Payment Date', 'gravityforms')));
            array_push($form['fields'], array('id' => 'payment_status', 'label' => __('Payment Status', 'gravityforms')));
            //array_push($form['fields'],array('id' => 'payment_method' , 'label' => __('Payment Method', 'gravityforms'))); //wait until all payment gateways have been released
            array_push($form['fields'], array('id' => 'post_id', 'label' => __('Post Id', 'gravityforms')));
            array_push($form['fields'], array('id' => 'user_agent', 'label' => __('User Agent', 'gravityforms')));
            array_push($form['fields'], array('id' => 'ip', 'label' => __('User IP', 'gravityforms')));
            $form = self::get_entry_meta($form);

            $form = apply_filters('gform_export_fields', $form);
            $form = GFFormsModel::convert_field_objects($form);

            return $form;
        }

        private static function get_entry_meta($form)
        {
            $entry_meta = GFFormsModel::get_entry_meta($form['id']);
            $keys = array_keys($entry_meta);
            foreach ($keys as $key) {
                array_push($form['fields'], array('id' => $key, 'label' => $entry_meta[$key]['label']));
            }

            return $form;
        }

        public static function get_field_row_count($form, $exported_field_ids, $entry_count)
        {
            $list_fields = GFAPI::get_fields_by_type($form, array('list'), true);

            //only getting fields that have been exported
            $field_ids = '';
            foreach ($list_fields as $field) {
                if (in_array($field->id, $exported_field_ids) && $field->enableColumns) {
                    $field_ids .= $field->id . ',';
                }
            }

            if (empty($field_ids)) {
                return array();
            }

            $field_ids = substr($field_ids, 0, strlen($field_ids) - 1);

            $page_size = 200;
            $offset = 0;

            $row_counts = array();
            global $wpdb;

            $go_to_next_page = true;

            while ($go_to_next_page) {
                $sql = "SELECT d.field_number as field_id, ifnull(l.value, d.value) as value
                    FROM {$wpdb->prefix}rg_lead_detail d
                    LEFT OUTER JOIN {$wpdb->prefix}rg_lead_detail_long l ON d.id = l.lead_detail_id
                    WHERE d.form_id={$form['id']} AND cast(d.field_number as decimal) IN ({$field_ids})
                    LIMIT {$offset}, {$page_size}";

                $results = $wpdb->get_results($sql, ARRAY_A);

                foreach ($results as $result) {
                    $list = unserialize($result['value']);
                    $current_row_count = isset($row_counts[$result['field_id']]) ? intval($row_counts[$result['field_id']]) : 0;

                    if (is_array($list) && count($list) > $current_row_count) {
                        $row_counts[$result['field_id']] = count($list);
                    }
                }

                $offset += $page_size;

                $go_to_next_page = count($results) == $page_size;
            }

            return $row_counts;
        }

        private static function send_mail($from, $to, $bcc, $reply_to, $subject, $message, $from_name = '', $message_format = 'html', $attachments = '', $entry = false, $notification = false)
        {
            global $phpmailer;

            $to = str_replace(' ', '', $to);
            $bcc = str_replace(' ', '', $bcc);
            $error = false;

            if (!GFCommon::is_valid_email($from)) {
                $from = get_bloginfo('admin_email');
            }

            if (!GFCommon::is_valid_email_list($to)) {
                $error = new WP_Error('invalid_to', 'Cannot send email because the TO address is invalid.');
            } else if (empty($subject) && empty($message)) {
                $error = new WP_Error('missing_subject_and_message', 'Cannot send email because there is no SUBJECT and no MESSAGE.');
            } else if (!GFCommon::is_valid_email($from)) {
                $error = new WP_Error('invalid_from', 'Cannot send email because the FROM address is invalid.');
            }

            if (is_wp_error($error)) {

                GFCommon::log_error('GFCommon::send_email(): ' . $error->get_error_message());
                GFCommon::log_error(print_r(compact('to', 'subject', 'message'), true));

                /**
                 * Fires when an email from Gravity Forms has failed to send
                 *
                 * @since 1.8.10
                 *
                 * @param string $error The Error message returned after the email fails to send
                 * @param array $details The details of the message that failed
                 * @param array $entry The Entry object
                 *
                 */
                do_action('gform_send_email_failed', $error, compact('from', 'to', 'bcc', 'reply_to', 'subject', 'message', 'from_name', 'message_format', 'attachments'), $entry);

                return;
            }

            $content_type = $message_format == 'html' ? 'text/html' : 'text/plain';
            $name = empty($from_name) ? $from : $from_name;

            $headers = array();
            $headers['From'] = "From: \"" . wp_strip_all_tags($name, true) . "\" <{$from}>";

            if (GFCommon::is_valid_email_list($reply_to)) {
                $headers['Reply-To'] = "Reply-To: {$reply_to}";
            }

            if (GFCommon::is_valid_email_list($bcc)) {
                $headers['Bcc'] = "Bcc: $bcc";
            }

            $headers['Content-type'] = "Content-type: {$content_type}; charset=" . get_option('blog_charset');

            $abort_email = false;
            extract(apply_filters('gform_pre_send_email', compact('to', 'subject', 'message', 'headers', 'attachments', 'abort_email'), $message_format, $notification));

            $is_success = false;
            if (!$abort_email) {
                GFCommon::log_debug('GFCommon::send_email(): Sending email via wp_mail().');
                GFCommon::log_debug(print_r(compact('to', 'subject', 'message', 'headers', 'attachments', 'abort_email'), true));
                $is_success = wp_mail($to, $subject, $message, $headers, $attachments);
                $result = is_wp_error($is_success) ? $is_success->get_error_message() : $is_success;
                GFCommon::log_debug("GFCommon::send_email(): Result from wp_mail(): {$result}");
                if (!is_wp_error($is_success) && $is_success) {
                    GFCommon::log_debug('GFCommon::send_email(): Mail was passed from WordPress to the mail server.');
                } else {
                    GFCommon::log_error('GFCommon::send_email(): The mail message was passed off to WordPress for processing, but WordPress was unable to send the message.');
                }

                if (has_filter('phpmailer_init')) {
                    GFCommon::log_debug(__METHOD__ . '(): The WordPress phpmailer_init hook has been detected, usually used by SMTP plugins, it can impact mail delivery.');
                }

                if (!empty($phpmailer->ErrorInfo)) {
                    GFCommon::log_debug(__METHOD__ . '(): PHPMailer class returned an error message: ' . $phpmailer->ErrorInfo);
                }
            } else {
                GFCommon::log_debug('GFCommon::send_email(): Aborting. The gform_pre_send_email hook was used to set the abort_email parameter to true.');
            }
        }

        public static function get_timing($args)
        {

            return $args['email_timings'] . ":00";
        }

    }


/**
 * Demo configuration call
 */
if (class_exists('Gravity_XL_Scheduled_Entries_Export')) {
    new Gravity_XL_Scheduled_Entries_Export(array(
        'form_id' => 407,
        'frequency' => 'daily',
        'day_of_week' => '',
        'day_of_month' => '',
        'options' => 'all',
        'email_to' => 'amrtansh.1990@gmail.com',
        'email_timings' => '22:00'
    ));

}