Automator_Recipe_Process_Complete

Class Automator_Recipe_Process_Complete

Contents

  • Methods

  • Source Source

    File: src/core/lib/process/class-automator-recipe-process-complete.php

    class Automator_Recipe_Process_Complete {
    	/**
    	 * @var
    	 */
    	public static $instance;
    	/**
    	 * @var $this
    	 */
    	public $user;
    
    	/**
    	 * Automator_Recipe_Process constructor.
    	 */
    	public function __construct() {
    		$this->user = $this;
    	}
    
    	/**
    	 * @return Automator_Recipe_Process_Complete
    	 */
    	public static function get_instance() {
    
    		if ( null === self::$instance ) {
    			self::$instance = new self();
    		}
    
    		return self::$instance;
    	}
    
    	/**
    	 * Complete the trigger for the user
    	 *
    	 * @param array $args
    	 *
    	 * @return null
    	 */
    	public function trigger( $args = array() ) {
    
    		$user_id        = absint( $args['user_id'] );
    		$trigger_id     = absint( $args['trigger_id'] );
    		$recipe_id      = absint( $args['recipe_id'] );
    		$trigger_log_id = absint( $args['trigger_log_id'] );
    		$recipe_log_id  = absint( $args['recipe_log_id'] );
    
    		// Set user ID
    		if ( is_null( $user_id ) ) {
    			$user_id = get_current_user_id();
    		}
    
    		if ( null === $trigger_id || ! is_numeric( $trigger_id ) ) {
    			Automator()->error->add_error( 'complete_trigger', 'ERROR: You are trying to complete a trigger without providing a trigger_id.', $this );
    
    			return null;
    		}
    
    		if ( null === $recipe_id || ! is_numeric( $recipe_id ) ) {
    			Automator()->error->add_error( 'complete_trigger', 'ERROR: You are trying to complete a trigger without providing a recipe_id.', $this );
    
    			return null;
    		}
    		// The trigger is about to be completed
    		do_action_deprecated(
    			'uap_before_trigger_completed',
    			array( $user_id, $trigger_id, $recipe_id, $trigger_log_id, $args ),
    			'3.0',
    			'automator_before_trigger_completed'
    		);
    		do_action( 'automator_before_trigger_completed', $user_id, $trigger_id, $recipe_id, $trigger_log_id, $args );
    
    		$trigger_code        = get_post_meta( $trigger_id, 'code', true );
    		$trigger_integration = Automator()->get->trigger_integration_from_trigger_code( $trigger_code );
    		if ( 0 === Automator()->plugin_status->get( $trigger_integration ) ) {
    			// The plugin for this action is NOT active
    			Automator()->error->add_error( 'complete_trigger', 'ERROR: You are trying to complete ' . $trigger_code . ' and the plugin ' . $trigger_integration . ' is not active.', $this );
    
    			return null;
    		}
    
    		Automator()->db->trigger->mark_complete( $trigger_id, $user_id, $recipe_id, $recipe_log_id, $trigger_log_id );
    
    		$maybe_continue  = true;
    		$process_further = array(
    			'maybe_continue_recipe_process' => $maybe_continue,
    			'recipe_id'                     => $recipe_id,
    			'user_id'                       => $user_id,
    			'recipe_log_id'                 => $recipe_log_id,
    			'trigger_log_id'                => $trigger_log_id,
    			'trigger_id'                    => $trigger_id,
    			'args'                          => $args,
    		);
    
    		//New filter.. see usage in pro
    		$process_further = apply_filters_deprecated( 'uap_maybe_continue_recipe_process', array( $process_further ), '3.0', 'automator_maybe_continue_recipe_process' );
    		$process_further = apply_filters( 'automator_maybe_continue_recipe_process', $process_further );
    
    		extract( $process_further, EXTR_OVERWRITE ); //phpcs:ignore WordPress.PHP.DontExtract.extract_extract
    
    		// The trigger is now completed
    		do_action_deprecated( 'uap_trigger_completed', array( $process_further ), '3.0', 'automator_trigger_completed' );
    		do_action( 'automator_trigger_completed', $process_further );
    
    		// If all triggers for the recipe are completed
    		if ( $maybe_continue && $this->triggers_completed( $recipe_id, $user_id, $recipe_log_id, $args ) ) {
    			$this->complete_actions( $recipe_id, $user_id, $recipe_log_id, $args );
    		}
    
    		return true;
    	}
    
    	/**
    	 * Are all triggers in the recipe completed
    	 *
    	 * @param int $recipe_id null||int
    	 * @param int $user_id null||int
    	 * @param int $recipe_log_id null||int
    	 *
    	 * @param array $args
    	 *
    	 * @return bool|null
    	 */
    	public function triggers_completed( $recipe_id = 0, $user_id = 0, $recipe_log_id = 0, $args = array() ) {
    
    		if ( null === $recipe_id || ! is_numeric( $recipe_id ) ) {
    			Automator()->error->add_error( 'triggers_completed', 'ERROR: You are trying to check if triggers are completed without providing a recipe_id.', $this );
    
    			return null;
    		}
    		// Set user ID
    		if ( is_null( $user_id ) ) {
    			$user_id = get_current_user_id();
    		}
    
    		$recipe_triggers = Automator()->get_recipe_data( 'uo-trigger', $recipe_id );
    
    		// By default the recipe will complete unless there is a trigger that is live(publish status) and its NOT completed
    		$triggers_completed = true;
    
    		foreach ( $recipe_triggers as $recipe_trigger ) {
    			if ( 'publish' === (string) $recipe_trigger['post_status'] ) {
    				$trigger_integration = $recipe_trigger['meta']['integration'];
    
    				if ( 0 === Automator()->plugin_status->get( $trigger_integration ) ) {
    					// The plugin for this trigger is NOT active
    					Automator()->error->add_error( 'complete_trigger', 'ERROR: You are trying to complete ' . $recipe_trigger['meta']['code'] . ' and the plugin ' . $trigger_integration . ' is not active. @recipe_id ' . $recipe_id, $this );
    				}
    
    				$trigger_completed = Automator()->db->trigger->is_completed( $user_id, $recipe_trigger['ID'], $recipe_id, $recipe_log_id, true, $args );
    				if ( ! $trigger_completed ) {
    					return false;
    				}
    			}
    		}
    
    		return $triggers_completed;
    	}
    
    	/**
    	 * Complete all actions in recipe
    	 *
    	 * @param null $recipe_id
    	 * @param null $user_id
    	 * @param null $recipe_log_id
    	 * @param array $args
    	 *
    	 * @return bool
    	 */
    	public function complete_actions( $recipe_id = null, $user_id = null, $recipe_log_id = null, $args = array() ) {
    		$recipe_action_data = Automator()->get_recipe_data( 'uo-action', $recipe_id );
    
    		foreach ( $recipe_action_data as $action_data ) {
    
    			$action_code                  = $action_data['meta']['code'];
    			$action_status                = $action_data['post_status'];
    			$action_data['recipe_log_id'] = $recipe_log_id;
    			$action_integration           = Automator()->get->action_integration_from_action_code( $action_code );
    
    			if ( 1 === Automator()->plugin_status->get( $action_integration ) && 'publish' === $action_status ) {
    				// The plugin for this action is active .. execute
    				$action_execution_function = Automator()->get->action_execution_function_from_action_code( $action_code );
    
    				$valid_function = true;
    				if ( null === $action_execution_function ) {
    					$valid_function = false;
    				} elseif ( is_array( $action_execution_function ) && ! method_exists( $action_execution_function[0], $action_execution_function[1] ) ) {
    					$valid_function = false;
    				} elseif ( is_string( $action_execution_function ) && ! function_exists( $action_execution_function ) ) {
    					$valid_function = false;
    				}
    
    				if ( ! $valid_function ) {
    					$error_message                       = Automator()->error_message->get( 'action-function-not-exist' );
    					$action_data['complete_with_errors'] = true;
    					$this->action( $user_id, $action_data, $recipe_id, $error_message, $recipe_log_id, $args );
    				} else {
    
    					//fallback...
    					$action_data['args'] = $args;
    
    					/*
    					 * See function notes
    					 *
    					 * @since 2.8
    					 */
    					$action_data = $this->parse_custom_value( $action_data, $user_id, $recipe_id, $args );
    
    					$action = array(
    						'user_id'     => $user_id,
    						'action_data' => $action_data,
    						'recipe_id'   => $recipe_id,
    						'args'        => $args,
    					);
    
    					$action = apply_filters( 'automator_before_action_executed', $action );
    
    					if ( isset( $action['process_further'] ) && $action['process_further'] === false ) {
    						Utilities::log( 'Action was skipped by uap_before_action_executed filter.' );
    						continue;
    					}
    
    					call_user_func_array( $action_execution_function, $action );
    				}
    			} elseif ( 0 === Automator()->plugin_status->get( $action_integration ) ) {
    				$error_message                       = Automator()->error_message->get( 'action-not-active' );
    				$action_data['complete_with_errors'] = true;
    				$this->action( $user_id, $action_data, $recipe_id, $error_message, $recipe_log_id, $args );
    			} elseif ( 0 === Automator()->plugin_status->get( $action_integration ) ) {
    				$error_message                       = Automator()->error_message->get( 'plugin-not-active' );
    				$action_data['complete_with_errors'] = true;
    				$this->action( $user_id, $action_data, $recipe_id, $error_message, $recipe_log_id, $args );
    			} elseif ( 1 === Automator()->plugin_status->get( $action_integration ) && 'draft' === $action_status ) {
    				continue;
    			} else {
    				$error_message                       = esc_attr__( 'Unknown error occurred.', 'uncanny-automator' );
    				$action_data['complete_with_errors'] = true;
    				Automator()->error->add_error( 'complete_action', $error_message, array( $action_data, $this ) );
    				$this->action( $user_id, $action_data, $recipe_id, $error_message, $recipe_log_id, $args );
    			}
    		}
    
    		$this->closures( $recipe_id, $user_id, $recipe_log_id, $args );
    
    		return true;
    	}
    
    	/**
    	 * Complete the action for the user
    	 *
    	 * @param null $user_id
    	 * @param null $action_data
    	 * @param null $recipe_id
    	 * @param string $error_message
    	 * @param null $recipe_log_id
    	 * @param array $args
    	 *
    	 * @return null
    	 */
    	public function action( $user_id = null, $action_data = null, $recipe_id = null, $error_message = '', $recipe_log_id = null, $args = array() ) {
    
    		// Set user ID
    		if ( is_null( $user_id ) ) {
    			$user_id = get_current_user_id();
    		}
    
    		$action_id = (int) $action_data['ID'];
    
    		if ( null === $action_id || ! is_numeric( $action_id ) ) {
    			Automator()->error->add_error( 'complete_action', 'ERROR: You are trying to complete an action without providing a action_id.', $this );
    
    			return null;
    		}
    
    		if ( null === $recipe_id || ! is_numeric( $recipe_id ) ) {
    			Automator()->error->add_error( 'complete_action', 'ERROR: You are trying to complete an action without providing a recipe_id.', $this );
    
    			return null;
    		}
    
    		if ( is_null( $recipe_log_id ) && array_key_exists( 'recipe_log_id', $action_data ) ) {
    			$recipe_log_id = absint( $action_data['recipe_log_id'] );
    		}
    
    		if ( is_null( $recipe_log_id ) || empty( $recipe_log_id ) ) {
    			Automator()->error->add_error( 'complete_action', 'ERROR: You are trying to complete an action without providing a recipe_log_id.', $this );
    
    			return null;
    		}
    
    		if ( empty( $args ) && array_key_exists( 'args', $action_data ) ) {
    			$args = $action_data['args'];
    		}
    
    		$action_data['completed'] = $this->get_action_completed_status( $user_id, $action_data, $recipe_id, $error_message, $recipe_log_id, $args );
    
    		// The action is about to be completed
    		do_action_deprecated(
    			'uap_before_action_completed',
    			array(
    				$user_id,
    				$action_id,
    				$recipe_id,
    				$error_message,
    				$recipe_log_id,
    				$args,
    			),
    			'3.0',
    			'automator_before_action_completed'
    		);
    		$do_action_args = array(
    			'user_id'       => $user_id,
    			'action_id'     => $action_id,
    			'recipe_id'     => $recipe_id,
    			'error_message' => $error_message,
    			'recipe_log_id' => $recipe_log_id,
    			'args'          => $args,
    		);
    		do_action( 'automator_before_action_completed', $do_action_args );
    
    		$error_message = $this->get_action_error_message( $user_id, $action_data, $recipe_id, $error_message, $recipe_log_id, $args );
    
    		$process_further = apply_filters( 'automator_before_action_created', true, $user_id, $action_data, $recipe_id, $error_message, $recipe_log_id, $args );
    
    		if ( ! $process_further ) {
    			return;
    		}
    
    		$action_log_id = $this->create_action( $user_id, $action_data, $recipe_id, $error_message, $recipe_log_id, $args );
    
    		// The action is about to be completed
    		do_action_deprecated(
    			'uap_action_completed',
    			array(
    				$user_id,
    				$action_id,
    				$recipe_id,
    				$error_message,
    				$args,
    			),
    			'3.0',
    			'automator_action_created'
    		);
    
    		$do_action_args = array(
    			'user_id'       => $user_id,
    			'action_id'     => $action_id,
    			'action_data'   => $action_data,
    			'action_log_id' => $action_log_id,
    			'recipe_id'     => $recipe_id,
    			'error_message' => $error_message,
    			'recipe_log_id' => $recipe_log_id,
    			'args'          => $args,
    		);
    
    		do_action( 'automator_action_created', $do_action_args );
    
    		$this->recipe( $recipe_id, $user_id, $recipe_log_id, $args );
    
    	}
    
    	/**
    	 * @param null $user_id
    	 * @param null $action_data
    	 * @param null $recipe_id
    	 * @param string $error_message
    	 * @param null $recipe_log_id
    	 * @param array $args
    	 *
    	 * @return mixed|string
    	 */
    	public function get_action_error_message( $user_id = null, $action_data = null, $recipe_id = null, $error_message = '', $recipe_log_id = null, $args = array() ) {
    
    		if ( ! empty( $error_message ) && key_exists( 'complete_with_errors', $action_data ) ) {
    			return $error_message;
    		}
    
    		if ( key_exists( 'user_action_message', $args ) && ! empty( $args['user_action_message'] ) ) {
    			return $args['user_action_message'];
    		}
    
    		return '';
    
    	}
    
    	/**
    	 * @param null $user_id
    	 * @param null $action_data
    	 * @param null $recipe_id
    	 * @param string $error_message
    	 * @param null $recipe_log_id
    	 * @param array $args
    	 *
    	 * @return mixed|void
    	 */
    	public function get_action_completed_status( $user_id = null, $action_data = null, $recipe_id = null, $error_message = '', $recipe_log_id = null, $args = array() ) {
    
    		/**
    		 * @var $completed
    		 * Meaning of each number
    		 *
    		 * 0 = not completed
    		 * 1 = completed
    		 * 2 = completed with errors, error message provided
    		 * 5 = scheduled
    		 * 9 = completed, do nothing
    		 *
    		 */
    		$completed = 0;
    
    		if ( is_array( $action_data ) && ! empty( $error_message ) && key_exists( 'complete_with_errors', $action_data ) ) {
    			$completed = 2;
    		} else if ( ( is_array( $action_data ) && key_exists( 'do-nothing', $action_data ) ) ) {
    			$completed = 9;
    		} else if ( empty( $error_message ) ) {
    			$completed = 1;
    		}
    
    		return apply_filters( 'automator_get_action_completed_status', $completed, $user_id, $action_data, $recipe_id, $error_message, $recipe_log_id, $args );
    	}
    
    	/**
    	 * @param null $user_id
    	 * @param null $action_data
    	 * @param null $recipe_id
    	 * @param string $error_message
    	 * @param null $recipe_log_id
    	 * @param array $args
    	 *
    	 * @return bool
    	 */
    	public function create_action( $user_id = null, $action_data = null, $recipe_id = null, $error_message = '', $recipe_log_id = null, $args = array() ) {
    
    		$action_id     = (int) $action_data['ID'];
    		$completed     = (int) $action_data['completed'];
    		$date_time     = apply_filters( 'automator_action_log_date_time', null, $action_data );
    		$values        = array(
    			'user_id'       => $user_id,
    			'action_id'     => $action_id,
    			'recipe_id'     => $recipe_id,
    			'recipe_log_id' => $recipe_log_id,
    			'completed'     => $completed,
    			'error_message' => $error_message,
    			'date_time'     => $date_time,
    		);
    		$action_log_id = Automator()->db->action->add( $values );
    		$sentences     = Automator()->get->action_sentence( $action_id );
    		if ( ! empty( $sentences ) ) {
    			foreach ( $sentences as $meta_key => $meta_value ) {
    				if ( ! empty( $meta_value ) ) {
    					Automator()->db->action->add_meta( $user_id, $action_log_id, $action_id, $meta_key, maybe_serialize( $meta_value ) );
    				}
    			}
    		}
    
    		return $action_log_id;
    	}
    
    	/**
    	 * this code is to parse new "Use custom value" functionality before an action
    	 * function is called. We will not have to modify each integration to support it.
    	 *
    	 * @param $action_data
    	 * @param $user_id
    	 * @param $recipe_id
    	 * @param $args
    	 *
    	 * @return mixed
    	 * @since  2.8
    	 *
    	 * @author Saad
    	 */
    	public function parse_custom_value( $action_data, $user_id, $recipe_id, $args ) {
    
    		if ( ! isset( $action_data['meta'] ) ) {
    			return $action_data;
    		}
    		$updated_values = array();
    		$meta           = $action_data['meta'];
    		// use regex to see if there's a _custom key
    		$custom_keys = preg_grep( '/(automator_custom_value)/', $meta );
    
    		if ( ! $custom_keys ) {
    			return $action_data;
    		}
    
    		foreach ( $custom_keys as $action_meta => $custom_value ) {
    			$k = "{$action_meta}_custom";
    			if ( ! key_exists( $k, $meta ) ) {
    				continue;
    			}
    			// parse token here
    			$v = Automator()->parse->text( $action_data['meta'][ $k ], $recipe_id, $user_id, $args );
    			if ( $v ) {
    				$action_data['meta'][ $action_meta ] = $v;
    				$updated_values[ $action_meta ]      = $v;
    			}
    		}
    
    		if ( $updated_values ) {
    			foreach ( $updated_values as $meta_key => $meta_value ) {
    				$pass_args = array(
    					'user_id'        => $user_id,
    					'trigger_id'     => $args['trigger_id'],
    					'meta_key'       => $meta_key,
    					'meta_value'     => $meta_value,
    					'run_number'     => $args['run_number'], //get run number
    					'trigger_log_id' => $args['trigger_log_id'],
    				);
    				Automator()->db->trigger->add_meta( $args['trigger_id'], $args['trigger_log_id'], $args['run_number'], $pass_args );
    			}
    		}
    
    		return $action_data;
    	}
    
    	/**
    	 * Complete a recipe
    	 *
    	 * @param null $recipe_id
    	 * @param null $user_id
    	 * @param null $recipe_log_id
    	 *
    	 * @param array $args
    	 *
    	 * @return null|true
    	 */
    	public function recipe( $recipe_id = null, $user_id = null, $recipe_log_id = null, $args = array() ) {
    
    		/**
    		 * @var $completed
    		 * Meaning of each number
    		 *
    		 * 0 = not completed
    		 * 1 = completed
    		 * 2 = completed with errors, error message provided
    		 * 5 = in progress (some actions are scheduled)
    		 * 9 = completed, do nothing
    		 *
    		 */
    
    		$run_number = Automator()->get->next_run_number( $recipe_id, $user_id, true );
    		if ( $recipe_log_id && Automator()->db->recipe->get_scheduled_actions_count( $recipe_log_id, $args ) > 0 ) {
    			$completed = 5;
    		} elseif ( ( is_array( $args ) && key_exists( 'do-nothing', $args ) ) ) {
    			$completed  = 9;
    			$run_number = 1;
    		} else {
    			$completed = 1;
    		}
    
    		do_action_deprecated(
    			'uap_before_recipe_completed',
    			array(
    				$recipe_id,
    				$user_id,
    				$recipe_log_id,
    				$args,
    			),
    			'3.0',
    			'automator_before_recipe_completed'
    		);
    		do_action( 'automator_before_recipe_completed', $recipe_id, $user_id, $recipe_log_id, $args );
    
    		if ( null === $recipe_log_id ) {
    			if ( null === $recipe_id || ! is_numeric( $recipe_id ) ) {
    				Automator()->error->add_error( 'complete_recipe', 'ERROR: You are trying to completed a recipe without providing a recipe_id', $this );
    
    				return null;
    			}
    
    			$recipe_log_id = Automator()->db->recipe->add( $user_id, $recipe_id, $completed, $run_number );
    		} else {
    			Automator()->db->recipe->mark_complete( $recipe_log_id, $completed );
    		}
    
    		// If actions error occurred, change the recipe status to 2
    		$maybe_error = Automator()->db->action->get_error_message( $recipe_log_id );
    
    		if ( ! empty( $maybe_error ) ) {
    			$skip     = false;
    			$message  = $maybe_error->error_message;
    			$complete = $maybe_error->completed;
    
    			if ( strpos( $message, 'Existing user found matching' ) || strpos( $message, 'User not found matching' ) || strpos( $message, 'User found matching' ) ) {
    				$skip = true;
    			} elseif ( strpos( $message, 'New user created' ) || strpos( $message, 'Create new user failed' ) ) {
    				$skip = true;
    			} elseif ( 9 === (int) $complete ) {
    				$skip = true;
    			}
    
    			if ( ! $skip ) {
    				$comp = 9 === absint( $completed ) ? 9 : $complete;
    				do_action( 'automator_recipe_completed_with_errors', $recipe_id, $user_id, $recipe_log_id, $args );
    				Automator()->db->recipe->mark_complete_with_error( $recipe_id, $recipe_log_id, $comp );
    			}
    		}
    
    		do_action_deprecated(
    			'uap_recipe_completed',
    			array(
    				$recipe_id,
    				$user_id,
    				$recipe_log_id,
    				$args,
    			),
    			'3.0',
    			'automator_recipe_completed'
    		);
    		do_action( 'automator_recipe_completed', $recipe_id, $user_id, $recipe_log_id, $args );
    
    		return true;
    	}
    
    	/**
    	 * Complete all closures in recipe
    	 *
    	 * @param null $recipe_id
    	 * @param null $user_id
    	 * @param null $recipe_log_id
    	 * @param array $args
    	 *
    	 * @return bool
    	 *
    	 */
    	public function closures( $recipe_id = null, $user_id = null, $recipe_log_id = null, $args = array() ) {
    
    		$recipe_closure_data = Automator()->get_recipe_data( 'uo-closure', $recipe_id );
    		foreach ( $recipe_closure_data as $closure_data ) {
    
    			$closure_code                  = $closure_data['meta']['code'];
    			$closure_status                = $closure_data['post_status'];
    			$closure_data['recipe_log_id'] = $recipe_log_id;
    			$closure_integration           = Automator()->get->closure_integration_from_closure_code( $closure_code );
    
    			if ( 1 === Automator()->plugin_status->get( $closure_integration ) && 'publish' === $closure_status ) {
    
    				// The plugin for this action is active .. execute
    				$closure_execution_function = Automator()->get->closure_execution_function_from_closure_code( $closure_code );
    				call_user_func_array(
    					$closure_execution_function,
    					array(
    						$user_id,
    						$closure_data,
    						$recipe_id,
    						$args,
    					)
    				);
    			} else {
    
    				// The plugin for this action is NOT active
    				Automator()->error->add_error( 'complete_closures', 'ERROR: You are trying to complete ' . $closure_code . ' and the plugin ' . $closure_integration . ' is not active.', $this );
    			}
    		}
    
    		do_action_deprecated(
    			'uap_closures_completed',
    			array(
    				$recipe_id,
    				$user_id,
    				$args,
    			),
    			'3.0',
    			'automator_closures_completed'
    		);
    		do_action( 'automator_closures_completed', $recipe_id, $user_id, $args );
    
    		return true;
    	}
    }
    

    Methods Methods