Files
roi-theme/wp-content/plugins/wp-marketing-automations/includes/controllers/class-bwfan-traversal-controller.php
root a22573bf0b Commit inicial - WordPress Análisis de Precios Unitarios
- WordPress core y plugins
- Tema Twenty Twenty-Four configurado
- Plugin allow-unfiltered-html.php simplificado
- .gitignore configurado para excluir wp-config.php y uploads

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-03 21:04:30 -06:00

462 lines
13 KiB
PHP
Executable File

<?php
#[AllowDynamicProperties]
class BWFAN_Traversal_Controller {
public $current_node_id = 0;
/** For processing of conditional controller */
public $automation_id = 0;
public $contact_id = 0;
public $trail_id = 0;
/** Conditional traversal Result */
public $conditional_result_node_id = null;
/** Split test traversal result */
public $split_result_node_id = null;
protected $steps = array();
protected $links = array();
/** Logging */
protected $step_log = null;
public $automation_contact_ins = null;
/**
* Set steps in the traverser
*
* @param array $db_steps
*
* @return void
*/
public function set_steps( $db_steps ) {
if ( ! is_array( $db_steps ) || empty( $db_steps ) ) {
return;
}
foreach ( $db_steps as $step ) {
$this->steps[ $step['id'] ] = $step;
}
}
/**
* Set links in the traverser
*
* @param array $db_links
*
* @return void
*/
public function set_links( $db_links ) {
if ( ! is_array( $db_links ) || empty( $db_links ) ) {
return;
}
foreach ( $db_links as $link ) {
if ( empty( $link ) || ! isset( $link['source'] ) || ! isset( $link['target'] ) ) {
continue;
}
$this->links[ $link['source'] ] = $link['target'];
}
}
/**
* Get current step id
*
* @return false|mixed
*/
public function get_current_step_id() {
if ( empty( $this->steps ) || empty( $this->current_node_id ) || ! isset( $this->steps[ $this->current_node_id ] ) || ! isset( $this->steps[ $this->current_node_id ]['stepId'] ) ) {
return false;
}
return $this->steps[ $this->current_node_id ]['stepId'];
}
/**
* Check if the current step is an end step
*
* @return bool
*/
public function is_end() {
return $this->current_node_id === 'end';
}
/**
* @param array $step_ids Goal step IDs
* @param $goal_ins BWFAN_Goal_Controller
* @param array $automation_contact
*
* @return array|false
*/
public function try_traverse_to_goal( $step_ids, $goal_ins, $automation_contact ) {
if ( empty( $this->current_node_id ) || empty( $step_ids ) ) {
return false;
}
$goal_ins->goal_steps = $this->get_step_nodes( $step_ids );
$run = 0;
$goal_found_nodes = [];
while ( $run < count( $this->steps ) ) {
$run ++;
$current_step = $this->steps[ $this->current_node_id ];
$this->log( 'current step', 'goal-check' );
$this->log( [ 'id' => $current_step['id'], 'type' => $current_step['type'] ], 'goal-check' );
switch ( $current_step['type'] ) {
case 'action':
case 'wait':
$this->traverse_to_next_step();
$this->log( 'traversed to next action/ wait step', 'goal-check' );
break;
case 'conditional':
$this->process_goal_conditional( $goal_ins, $automation_contact );
$this->traverse_to_next_step();
$this->log( 'traversed to next conditional step', 'goal-check' );
break;
case 'jump':
$this->process_jump( $goal_ins, $automation_contact );
/** No need to traverse to next step as traversing already from process_jump function */
$this->log( 'traversed to next jump step', 'goal-check' );
break;
case 'end':
$this->log( 'end step', 'goal-check' );
$run = count( $this->steps );
break;
case 'benchmark':
if ( in_array( $current_step['id'], $goal_ins->goal_steps ) ) {
$goal_found_nodes[] = $current_step['id'];
$this->log( 'goal step found during traverse. goal step id: ' . $current_step['id'], 'goal-check' );
}
$this->traverse_to_next_step();
$this->log( 'traversed to next step from goal step', 'goal-check' );
break;
case 'split':
if ( in_array( $current_step['id'], $goal_ins->goal_steps ) ) {
$goal_found_nodes[] = $current_step['id'];
$this->log( 'split step found during traverse. split step id: ' . $current_step['id'], 'goal-check' );
}
$this->process_split_path( $automation_contact );
$this->traverse_to_next_step();
/** No need to traverse to next step as traversing already from process_jump function */
$this->log( 'traversed to next split step', 'goal-check' );
break;
default:
break;
}
}
$goal_found_nodes = array_unique( $goal_found_nodes );
sort( $goal_found_nodes );
return $goal_found_nodes;
}
/**
* Return current step data by step id
*
* @param int $step_id
*
* @return false|mixed
*/
public function get_step_by_step_id( $step_id ) {
if ( empty( $step_id ) ) {
return false;
}
foreach ( $this->steps as $step ) {
if ( isset( $step['stepId'] ) && ( absint( $step['stepId'] ) === absint( $step_id ) ) ) {
return $step;
}
}
return false;
}
/**
* Get node ids from step ids
*
* @param $step_ids
*
* @return array|false
*/
public function get_step_nodes( $step_ids ) {
if ( empty( $step_ids ) ) {
return false;
}
$nodes = [];
foreach ( $this->steps as $step ) {
if ( 'benchmark' !== $step['type'] ) {
continue;
}
if ( isset( $step['stepId'] ) && in_array( $step['stepId'], $step_ids ) ) {
$nodes[ $step['stepId'] ] = $step['id'];
}
}
return empty( $nodes ) ? false : $nodes;
}
/**
* Traverse to next step node
*
* @return bool
*/
public function traverse_to_next_step() {
$current_step = $this->get_current_step();
$this->log( $this->trail_id . ' - current step id: ' . $current_step['stepId'] . ' and node id: ' . $current_step['id'] . ' and type: ' . $current_step['type'] );
if ( empty( $current_step ) || empty( $this->links ) ) {
return false;
}
if ( 'conditional' === $current_step['type'] ) {
/** Traverse conditional step */
$next_step = $this->traverse_conditional_step();
if ( empty( $next_step ) ) {
return false;
}
$this->current_node_id = $next_step;
$this->log( $this->trail_id . ' - traverse to next step from conditional step. New node id: ' . $this->current_node_id );
return true;
}
/** If current step is split */
if ( 'split' === $current_step['type'] ) {
/** Traverse split step */
$next_step = $this->traverse_split_step();
if ( empty( $next_step ) ) {
return false;
}
$this->current_node_id = $next_step;
$this->log( $this->trail_id . ' - traverse to next path from split step. New node id: ' . $this->current_node_id );
return true;
}
if ( ! isset( $this->links[ $this->current_node_id ] ) ) {
return false;
}
$this->current_node_id = $this->links[ $this->current_node_id ];
$this->log( $this->trail_id . ' - traverse to next step. New node id: ' . $this->current_node_id );
return true;
}
/**
* Get current step data
*
* @return false|mixed
*/
public function get_current_step() {
return ! empty( $this->steps ) && ! empty( $this->current_node_id ) && isset( $this->steps[ $this->current_node_id ] ) ? $this->steps[ $this->current_node_id ] : false;
}
/**
* Return step id after processing conditional step result
*
* @return false|mixed
*/
public function traverse_conditional_step() {
$conditional_node_id = $this->conditional_result_node_id;
if ( isset( $this->links[ $conditional_node_id ] ) ) {
return $this->links[ $conditional_node_id ];
}
/** Maybe check if set in the database */
if ( $this->automation_contact_ins instanceof BWFAN_Automation_Controller ) {
$data = $this->automation_contact_ins->automation_contact_data;
if ( isset( $data['node_id'] ) && isset( $this->links[ $data['node_id'] ] ) ) {
/** Removing saved node id from the DB */
$this->automation_contact_ins->update_conditional_step_result();
return $this->links[ $data['node_id'] ];
}
}
/** If somehow conditional step is deleted from table but its step node id exists in links then return target step of NO node */
if ( isset( $this->links[ $this->links[ $this->current_node_id ] ] ) ) {
return $this->links[ $this->links[ $this->current_node_id ] ];
}
BWFAN_Common::log_test_data( 'not able to traverse to condition next step ' . $this->current_node_id, 'traverse_conditional_failed' );
BWFAN_Common::log_test_data( 'conditional_node_id: ' . $conditional_node_id, 'traverse_conditional_failed' );
BWFAN_Common::log_test_data( $this->links, 'traverse_conditional_failed' );
return false;
}
/**
* Return step id after processing split next path result
*
* @return false|mixed
*/
public function traverse_split_step() {
$path_node_id = $this->split_result_node_id;
if ( isset( $this->links[ $path_node_id ] ) ) {
return $this->links[ $path_node_id ];
}
BWFAN_Common::log_test_data( 'not able to traverse to split next path ' . $this->current_node_id, 'traverse_split_failed' );
BWFAN_Common::log_test_data( 'split_path_node_id: ' . $path_node_id, 'traverse_split_failed' );
BWFAN_Common::log_test_data( $this->links, 'traverse_split_failed' );
return false;
}
/**
* Process conditional step data for goal only
*
* @param $goal_ins BWFAN_Goal_Controller
* @param array $automation_contact automation contact row
*
* @return void
*/
public function process_goal_conditional( $goal_ins, $automation_contact ) {
$current_step = $this->get_current_step();
$ins = new BWFAN_Conditional_Controller();
$ins->contact_id = $goal_ins->contact_id;
$ins->automation_id = $goal_ins->automation_id;
$ins->step_id = absint( $current_step['stepId'] );
$ins->populate_step_data( $current_step );
$ins->populate_automation_contact_data( $automation_contact );
$result = $ins->is_match();
$this->conditional_result_node_id = $current_step['id'] . ( ( true === $result ) ? 'yes' : 'no' );
}
/**
* Process jump step
*
* @param $goal_ins
* @param $automation_contact
*
* @return void
*/
public function process_jump( $goal_ins, $automation_contact ) {
$current_step = $this->get_current_step();
$ins = new BWFAN_Jump_Controller();
$ins->step_id = absint( $current_step['stepId'] );
$ins->populate_step_data( $current_step );
$jump_step_id = $ins->get_jump_step_id();
if ( empty( $jump_step_id ) ) {
return;
}
/** Set current node to jump step */
$this->set_node_id_from_step_id( $jump_step_id );
}
/**
* Maybe traverse back to valid step
*
* @return void
*/
public function maybe_traverse_back() {
global $wpdb;
/** @var BWFAN_Automation_Controller $ins */
$ins = $this->automation_contact_ins;
$step_id = $ins->step_id;
$query = $wpdb->prepare( "SELECT `ID` FROM `{$wpdb->prefix}bwfan_automation_contact_trail` WHERE `tid` = %s AND `sid` = %d LIMIT 0,1;", $ins->automation_contact['trail'], $step_id );
$result = $wpdb->get_var( $query ); //phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
$valid_step_id = 0;
if ( ! empty( $result ) ) {
$query = $wpdb->prepare( "SELECT t.`sid` FROM `{$wpdb->prefix}bwfan_automation_contact_trail` as t INNER JOIN `{$wpdb->prefix}bwfan_automation_step` as s ON s.`ID` = t.`sid` WHERE t.`tid` = %s AND t.`ID` < %d AND s.`status` IN (%d, %d) ORDER BY t.ID DESC LIMIT 0,1;", $ins->automation_contact['trail'], $result, 0, 1 );
$result = $wpdb->get_var( $query ); //phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
if ( ! empty( $result ) ) {
$valid_step_id = strval( $result );
}
}
if ( empty( $valid_step_id ) ) {
/** Step not found, start from the first node */
$ins->step_id = $ins->automation['start'];
$this->set_node_id_from_step_id( $ins->step_id );
$ins->automation_contact['last'] = 0;
return;
}
$this->set_node_id_from_step_id( $valid_step_id );
}
/**
* Set step node ID from the step ID
*
* @param int $step_id
*
* @return bool
*/
public function set_node_id_from_step_id( $step_id ) {
$step = $this->get_step_by_step_id( $step_id );
if ( empty( $step ) || ! isset( $step['id'] ) ) {
return false;
}
$this->current_node_id = $step['id'];
return true;
}
/**
* Process split step for goal only
*
* @param $automation_contact
*
* @return void
*/
public function process_split_path( $automation_contact ) {
$current_step = $this->get_current_step();
$ins = new BWFAN_Split_Test_Controller();
$ins->current_node_id = $this->current_node_id;
$ins->automation_id = $this->automation_id;
$ins->step_id = absint( $current_step['stepId'] );
$ins->populate_step_data( $current_step );
$ins->populate_automation_contact_data( $automation_contact );
$path = $ins->get_next_path();
$this->split_result_node_id = $current_step['id'] . '-path-' . $path;
}
/**
* Special log function for step execution
*
* @param $log
* @param $name
*
* @return void
*/
public function log( $log, $name = 'fka-automation-step-id' ) {
if ( empty( $log ) ) {
return;
}
if ( false === $this->step_log ) {
return;
}
if ( is_null( $this->step_log ) && false === apply_filters( 'bwfan_allow_automation_step_logging', BWFAN_Common::is_log_enabled( 'bwfan_step_logging' ) ) ) {
$this->step_log = false;
return;
}
$this->step_log = true;
BWFAN_Common::log_test_data( $log, $name, true );
}
}