PluginProbe
Elementor Website Builder – more than just a page builder / 3.25.2
Elementor Website Builder – more than just a page builder v3.25.2
4.3.1 4.3.0 4.3.0-beta3 4.3.0-beta2 4.3.0-beta1 4.2.4 4.2.3 4.2.2 4.2.1 4.2.0 4.1.5 4.2.0-beta2 4.2.0-dev2 4.2.0-beta1 4.1.4 4.1.3 4.1.2 4.1.1 4.1.0 4.1.0-beta3 4.1.0-dev3 4.0.9 4.1.0-beta2 4.1.0-dev2 4.0.8 All 454 releases
← All changes | modules/atomic-widgets/props-resolver/props-resolver.php +81 -56 4.1.0-beta1 → 3.25.2 View file →
@@ -1,12 +1,9 @@
1 1 <?php
2 2
3 3 namespace Elementor\Modules\AtomicWidgets\PropsResolver;
4 4
5 -use Elementor\Modules\AtomicWidgets\PropTypes\Base\Array_Prop_Type;
6 -use Elementor\Modules\AtomicWidgets\PropTypes\Base\Object_Prop_Type;
7 -use Elementor\Modules\AtomicWidgets\PropTypes\Contracts\Prop_Type;
8 -use Elementor\Modules\AtomicWidgets\PropTypes\Union_Prop_Type;
5 +use Elementor\Modules\AtomicWidgets\PropTypes\Prop_Type;
9 6 use Exception;
10 7
11 8 if ( ! defined( 'ABSPATH' ) ) {
12 9 exit; // Exit if accessed directly.
@@ -11,77 +8,105 @@
11 8 if ( ! defined( 'ABSPATH' ) ) {
12 9 exit; // Exit if accessed directly.
13 10 }
14 11
15 -abstract class Props_Resolver {
16 - protected static array $instances = [];
12 +class Props_Resolver {
13 + /**
14 + * Each transformer can return a value that is also a transformable value,
15 + * which means that it can be transformed again by another transformer.
16 + * This constant defines the maximum depth of transformations to avoid infinite loops.
17 + */
18 + const TRANSFORM_DEPTH_LIMIT = 3;
17 19
18 - protected Transformers_Registry $transformers_registry;
20 + const CONTEXT_SETTINGS = 'settings';
21 + const CONTEXT_STYLES = 'styles';
19 22
20 - protected function __construct( Transformers_Registry $transformers_registry ) {
21 - $this->transformers_registry = $transformers_registry;
23 + /**
24 + * @var array<string, Props_Resolver>
25 + */
26 + private static array $instances = [];
27 +
28 + private Transformers_Registry $transformers;
29 +
30 + private function __construct( Transformers_Registry $transformers ) {
31 + $this->transformers = $transformers;
22 32 }
23 33
24 - protected static function instance( string $context ) {
25 - if ( ! isset( static::$instances[ $context ] ) ) {
26 - $instance = new static( new Transformers_Registry() );
34 + public static function for_styles() {
35 + return self::instance( self::CONTEXT_STYLES );
36 + }
27 37
28 - static::$instances[ $context ] = $instance;
38 + public static function for_settings() {
39 + return self::instance( self::CONTEXT_SETTINGS );
40 + }
29 41
30 - do_action(
31 - "elementor/atomic-widgets/$context/transformers/register",
32 - $instance->get_transformers_registry(),
33 - $instance
34 - );
42 + private static function instance( string $context, bool $fresh = false ): self {
43 + if ( ! isset( self::$instances[ $context ] ) || $fresh ) {
44 + $registry = new Transformers_Registry();
45 +
46 + do_action( "elementor/atomic-widgets/{$context}/transformers/register", $registry );
47 +
48 + self::$instances[ $context ] = new self( $registry );
35 49 }
36 50
37 - return static::$instances[ $context ];
51 + return self::$instances[ $context ];
38 52 }
39 53
40 - public static function reset(): void {
41 - static::$instances = [];
42 - }
54 + public function resolve( array $schema, array $props ): array {
55 + $resolved_props = [];
43 56
44 - public function get_transformers_registry(): Transformers_Registry {
45 - return $this->transformers_registry;
46 - }
57 + foreach ( $schema as $key => $prop_type ) {
58 + if ( ! ( $prop_type instanceof Prop_Type ) ) {
59 + continue;
60 + }
47 61
48 - protected function transform( $value, $key, Prop_Type $prop_type ) {
49 - if ( $prop_type instanceof Union_Prop_Type ) {
50 - $prop_type = $prop_type->get_prop_type( $value['$$type'] );
62 + if ( ! array_key_exists( $key, $props ) ) {
63 + $resolved_props[ $key ] = $prop_type->get_default();
64 + continue;
65 + }
51 66
52 - if ( ! $prop_type ) {
53 - return null;
67 + $resolved_props[ $key ] = $props[ $key ];
68 +
69 + // Merge the top-level defaults for transformable props.
70 + if (
71 + $this->is_nested_transformable( $resolved_props[ $key ] ) &&
72 + $this->is_nested_transformable( $prop_type->get_default() )
73 + ) {
74 + $resolved_props[ $key ]['value'] = array_merge(
75 + $prop_type->get_default()['value'],
76 + $resolved_props[ $key ]['value']
77 + );
54 78 }
55 79 }
56 80
57 - if ( $value['$$type'] !== $prop_type::get_key() ) {
81 + return array_map(
82 + fn( $value ) => $this->transform( $value ),
83 + $resolved_props
84 + );
85 + }
86 +
87 + private function transform( $value, int $depth = 0 ) {
88 + if ( ! $value || ! $this->is_transformable( $value ) ) {
89 + return $value;
90 + }
91 +
92 + if ( $depth >= self::TRANSFORM_DEPTH_LIMIT ) {
58 93 return null;
59 94 }
60 95
61 - if ( $prop_type instanceof Object_Prop_Type ) {
62 - if ( ! is_array( $value['value'] ) ) {
63 - return null;
64 - }
65 -
66 - $value['value'] = $this->resolve(
67 - $prop_type->get_shape(),
68 - $value['value']
69 - );
96 + if ( isset( $value['disabled'] ) && true === $value['disabled'] ) {
97 + return null;
70 98 }
71 99
72 - if ( $prop_type instanceof Array_Prop_Type ) {
73 - if ( ! is_array( $value['value'] ) ) {
74 - return null;
75 - }
76 -
100 + // Transform nested transformable values recursively.
101 + if ( is_array( $value['value'] ) ) {
77 102 $value['value'] = array_map(
78 - fn( $item ) => $this->resolve_item( $item, null, $prop_type->get_item_type() ),
103 + fn( $item ) => $this->transform( $item ),
79 104 $value['value']
80 105 );
81 106 }
82 107
83 - $transformer = $this->transformers_registry->get( $value['$$type'] );
108 + $transformer = $this->transformers->get( $value['$$type'] );
84 109
85 110 if ( ! ( $transformer instanceof Transformer_Base ) ) {
86 111 return null;
87 112 }
@@ -86,20 +111,17 @@
86 111 return null;
87 112 }
88 113
89 114 try {
90 - $context = Props_Resolver_Context::make()
91 - ->set_key( $key )
92 - ->set_disabled( (bool) ( $value['disabled'] ?? false ) )
93 - ->set_prop_type( $prop_type );
115 + $transformed_value = $transformer->transform( $value['value'] );
94 116
95 - return $transformer->transform( $value['value'], $context );
117 + return $this->transform( $transformed_value, $depth + 1 );
96 118 } catch ( Exception $e ) {
97 119 return null;
98 120 }
99 121 }
100 122
101 - protected function is_transformable( $value ): bool {
123 + private function is_transformable( $value ): bool {
102 124 return (
103 125 ! empty( $value['$$type'] ) &&
104 126 array_key_exists( 'value', $value )
105 127 );
@@ -104,8 +126,11 @@
104 126 array_key_exists( 'value', $value )
105 127 );
106 128 }
107 129
108 - abstract public function resolve( array $schema, array $props ): array;
109 -
110 - abstract protected function resolve_item( $value, $key, Prop_Type $prop_type );
130 + private function is_nested_transformable( $value ): bool {
131 + return (
132 + $this->is_transformable( $value ) &&
133 + is_array( $value['value'] )
134 + );
135 + }
111 136 }