get_contact_id_for_goal( $post_parameters ); if ( empty( $contact_id ) ) { return false; } /** Get Active Automations for current goal */ $automations = $event->get_current_goal_automations(); if ( empty( $automations ) ) { return false; } /** Check if contact is in those automations */ $automation_contact_rows = self::filter_goal_automations_contact( $automations, $contact_id ); if ( empty( $automation_contact_rows ) ) { return false; } /** Process each automation */ foreach ( $automation_contact_rows as $automation_contact ) { $automation = BWFAN_Model_Automations::get_automation_with_data( $automation_contact['aid'] ); if ( empty( $automation ) ) { continue; } $controller = new BWFAN_Goal_Controller(); $controller->automation_id = absint( $automation_contact['aid'] ); $controller->contact_id = absint( $contact_id ); $controller->process_goal( $automation, $event, $automation_contact, self::$captured_data ); } self::$captured_data = array(); } /** * Filter goal automations if contact is active in them * * @param $automations * @param $contact_id * * @return array automation contact row */ public static function filter_goal_automations_contact( $automations, $contact_id ) { global $wpdb; if ( empty( $automations ) || empty( $contact_id ) ) { return []; } $string_placeholder = array_fill( 0, count( $automations ), '%d' ); $placeholder = implode( ', ', $string_placeholder ); $data = array_merge( [ $contact_id ], $automations ); $query = $wpdb->prepare( "SELECT * FROM `{$wpdb->prefix}bwfan_automation_contact` WHERE `cid` = %d AND `aid` IN ($placeholder) AND `status` IN (1,4,6)", $data ); return $wpdb->get_results( $query, ARRAY_A ); //phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching } /** * @param array $automation Automation data * @param BWFAN_Event $event * @param array $automation_contact Automation contact row * @param array $post_parameters * * @return void */ public function process_goal( $automation, $event, $automation_contact, $post_parameters ) { /** Set default values */ $this->traverse_setting = 'continue'; $this->data = null; $this->goal_steps = []; $this->update_status = false; /** Fetching steps trail */ $trail_id = $automation_contact['trail']; if ( empty( $trail_id ) ) { $trail_id = md5( $automation_contact['ID'] . $automation_contact['cid'] . $automation_contact['c_date'] ); $automation_contact['trail'] = $trail_id; BWFAN_Model_Automation_Contact::update( array( 'trail' => $trail_id, ), array( 'ID' => $automation_contact['ID'], ) ); } /** Steps and Links not found */ if ( ! is_array( $automation['meta'] ) || ! is_array( $automation['meta']['steps'] ) || ! is_array( $automation['meta']['links'] ) ) { return; } BWFAN_Common::log_l2_data( 'Trail id: ' . $trail_id, 'goal-check' ); /** Again Checking if the goal and it's step_id exists */ $goal_step_ids = $this->get_goal_step_ids( $this->automation_id, $event->get_slug() ); if ( empty( $goal_step_ids ) ) { BWFAN_Common::log_l2_data( 'no goal step ids found', 'goal-check' ); return; } $this->step_id = ( 0 === absint( $automation_contact['last'] ) ) ? $automation['start'] : $automation_contact['last']; BWFAN_Common::log_l2_data( 'Last run: ' . $this->step_id, 'goal-check' ); BWFAN_Common::log_l2_data( 'Goal step ids: ' . implode( ', ', $goal_step_ids ), 'goal-check' ); $traverse_ins = new BWFAN_Traversal_Controller(); $traverse_ins->set_steps( $automation['meta']['steps'] ); $traverse_ins->set_links( $automation['meta']['links'] ); $traverse_ins->set_node_id_from_step_id( $this->step_id ); $traverse_ins->automation_id = $this->automation_id; $traverse_ins->contact_id = $this->contact_id; /** Try to traverse the goal, if unable to traverse, then return false */ $traversed_goal_node_ids = $traverse_ins->try_traverse_to_goal( $goal_step_ids, $this, $automation_contact ); if ( empty( $traversed_goal_node_ids ) ) { return; } $steps_trail = BWFAN_Model_Automation_Contact_Trail::get_trail( $trail_id ); /** Validate found goal settings */ foreach ( $traversed_goal_node_ids as $node_id ) { $step_id = array_search( $node_id, $this->goal_steps ); if ( empty( $step_id ) || 1 > intval( $step_id ) ) { continue; } $step_data = BWFAN_Model_Automation_Step::get_step_data_by_id( $step_id ); /** Get Benchmark Step Data */ $this->step_id = $step_id; $this->populate_step_data( $step_data ); if ( ! $event->validate_goal_settings( $this->data, $post_parameters ) ) { /** Unable to pass the goal settings */ BWFAN_Common::log_l2_data( 'Goal settings failed for step id ' . $step_id, 'goal-check' ); continue; } BWFAN_Common::log_l2_data( 'Goal achieved: step id ' . $step_id, 'goal-check' ); /** Update existing steps trail status if needed or insert */ $this->maybe_update_trail_status( $steps_trail ); $this->maybe_add_goal_step_trail( $step_id, $steps_trail, $automation_contact ); /** Goal step passed, update automation contact status to active */ BWFAN_Model_Automation_Contact::update( array( 'last' => $step_id, 'attempts' => 0, 'status' => BWFAN_Automation_Controller::$STATUS_ACTIVE, 'last_time' => current_time( 'timestamp', 1 ), 'e_time' => current_time( 'timestamp', 1 ), ), array( 'ID' => $automation_contact['ID'], ) ); } } /** * Get goals step ids in an automation * * @param $automation_id * @param $event_slug * * @return array|int */ public function get_goal_step_ids( $automation_id, $event_slug ) { if ( empty( $automation_id ) || empty( $event_slug ) ) { return 0; } global $wpdb; $query = $wpdb->prepare( "SELECT `ID` FROM `{$wpdb->prefix}bwfan_automation_step` WHERE `aid` = %d AND `type` = 3 AND `status` IN (0, 1) AND `action` LIKE %s", $automation_id, "%{$event_slug}%" ); $step_ids = $wpdb->get_col( $query ); //phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching if ( empty( $step_ids ) ) { return []; } return ! empty( $step_ids ) ? $step_ids : []; } /** * Set step data * * @param array $db_step step data * * @return bool */ public function populate_step_data( $db_step = array() ) { if ( parent::populate_step_data( $db_step ) && isset( $this->step_data['sidebarData'] ) && is_array( $this->step_data['sidebarData'] ) ) { $this->data = $this->step_data['sidebarData']; $this->traverse_setting = $this->data['bwfan_goal_run']; return true; } return false; } /** * Maybe steps trail contains a step with status 2. Update that to 1. * Run once only * * array $steps_trail current contact steps trail * * @return void */ public function maybe_update_trail_status( $steps_trail ) { if ( true === $this->update_status ) { return; } /** Filter steps with status 2 */ $filtered = array_filter( $steps_trail, function ( $row ) { if ( 2 === absint( $row['status'] ) ) { return true; } return false; } ); /** If empty */ if ( ! is_array( $filtered ) || 0 === count( $filtered ) ) { $this->update_status = true; return; } $filtered = array_column( $filtered, 'ID' ); BWFAN_Common::log_l2_data( __FUNCTION__ . ' filtered', 'goal-update-trail-status' ); BWFAN_Common::log_l2_data( implode( ', ', $filtered ), 'goal-update-trail-status' ); global $wpdb; $string_placeholder = array_fill( 0, count( $filtered ), '%d' ); $placeholder = implode( ', ', $string_placeholder ); /** Update status and time */ $data = array_merge( [ 1, time() ], $filtered ); $query = $wpdb->prepare( "UPDATE `{$wpdb->prefix}bwfan_automation_contact_trail` SET `status` = %d, `c_time` = %d WHERE `ID` IN ($placeholder)", $data ); $wpdb->query( $query ); //phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching $this->update_status = true; } /** * Maybe add the goal step trail * * @param int $goal_step_id * @param array $steps_trail current contact steps trail * @param array $automation_contact automation contact row * * @return int|void */ public function maybe_add_goal_step_trail( $goal_step_id, $steps_trail, $automation_contact ) { /** Filter steps if a goal step is already in wait */ $filtered = array_filter( $steps_trail, function ( $row ) use ( $goal_step_id ) { $data = ! empty( $row['data'] ) ? json_decode( $row['data'], true ) : []; return ( ! empty( $data ) && isset( $data['msg'] ) && 'wait' === $data['msg'] && $goal_step_id === intval( $row['sid'] ) ); } ); if ( is_array( $filtered ) && count( $filtered ) > 0 ) { return; } /** Add a goal step trail */ $arr = array( 'tid' => $automation_contact['trail'], 'cid' => $automation_contact['cid'], 'aid' => $automation_contact['aid'], 'sid' => $goal_step_id, 'c_time' => time(), 'status' => BWFAN_Automation_Controller::$STATUS_ACTIVE, ); BWFAN_Model_Automation_Contact_Trail::insert( $arr ); return BWFAN_Model_Automation_Contact_Trail::insert_id(); } }