@@ -81,49 +81,70 @@ public function read(): array
8181 }
8282
8383 /**
84- * Recursively unwrap Symfony YAML TaggedValue objects and handle common tags .
84+ * Recursively normalizes Symfony YAML TaggedValue objects into PHP-native values .
8585 *
86- * This method handles !env, !include, !php/const, and unknown tags,
87- * ensuring all YAML values are normalized to arrays or scalars for safe merging.
86+ * Handles the following YAML tags:
87+ * - !env: resolves environment variables.
88+ * - !include: parses and normalizes included YAML files.
89+ * - !php/const: resolves PHP constants (e.g. !php/const:\PDO::ATTR_ERRMODE).
90+ * - Other or unknown tags: recursively normalize their values.
8891 *
89- * @param mixed $data
90- * @return mixed
92+ * Ensures all YAML data is converted to scalars or arrays suitable for safe merging.
9193 *
92- * @SuppressWarnings("PHPMD.CyclomaticComplexity") Method is intentionally complex due to tag handling.
94+ * @param mixed $data The parsed YAML data (array, scalar, or TaggedValue).
95+ * @return mixed The normalized data structure.
96+ *
97+ * @SuppressWarnings("PHPMD.NPathComplexity")
98+ * @SuppressWarnings("PHPMD.CyclomaticComplexity") Method is intentionally complex due to tag resolution logic.
9399 */
94100 private function normalizeYamlData (mixed $ data ): mixed
95101 {
96102 if ($ data instanceof TaggedValue) {
97- $ tag = $ data ->getTag ();
103+ $ tag = $ data ->getTag (); // e.g. "php/const:\PDO::MYSQL_ATTR_LOCAL_INFILE"
98104 $ value = $ data ->getValue ();
99105
100- switch ($ tag ) {
101- case '!env ' :
102- $ envValue = getenv ((string )$ value );
103- return $ envValue !== false ? $ envValue : null ;
104-
105- case '!include ' :
106- if (file_exists ((string )$ value )) {
107- $ included = Yaml::parseFile ((string )$ value );
108- return $ this ->normalizeYamlData ($ included );
109- }
110- return null ;
111-
112- case '!php/const ' :
113- // Evaluate the PHP constant
114- return defined ($ value ) ? constant ($ value ) : null ;
115-
116- default :
117- $ val = $ this ->normalizeYamlData ($ value );
118- return is_array ($ val ) ? $ val : [$ val ];
106+ // Handle php/const tags (Symfony strips leading '!')
107+ if (str_starts_with ($ tag , 'php/const: ' )) {
108+ // Extract the constant name
109+ $ constName = substr ($ tag , strlen ('php/const: ' ));
110+ $ constName = ltrim ($ constName , '\\' );
111+
112+ // Resolve the constant name to its value if defined
113+ $ constKey = defined ($ constName ) ? constant ($ constName ) : $ constName ;
114+
115+ // Handle YAML quirk where ": 1" is parsed literally
116+ $ raw = is_string ($ value ) ? $ value : (string )$ value ;
117+ $ cleanVal = str_replace ([': ' , ' ' ], '' , $ raw );
118+ $ constVal = is_numeric ($ cleanVal ) ? (int )$ cleanVal : $ cleanVal ;
119+
120+ return [$ constKey => $ constVal ];
121+ }
122+
123+ // Handle !env
124+ if ($ tag === 'env ' ) {
125+ $ envValue = getenv ((string )$ value );
126+ return $ envValue !== false ? $ envValue : null ;
119127 }
128+
129+ // Handle !include
130+ if ($ tag === 'include ' ) {
131+ if (file_exists ((string )$ value )) {
132+ $ included = Yaml::parseFile ((string )$ value );
133+ return $ this ->normalizeYamlData ($ included );
134+ }
135+ return null ;
136+ }
137+
138+ // Default — recursively normalize nested tagged structures
139+ $ normalized = $ this ->normalizeYamlData ($ value );
140+ return is_array ($ normalized ) ? $ normalized : [$ normalized ];
120141 }
121142
143+ // Recursively normalize arrays
122144 if (is_array ($ data )) {
123145 foreach ($ data as $ key => $ value ) {
124146 $ data [$ key ] = $ this ->normalizeYamlData ($ value );
125147 }
126- return $ data ;
127148 }
128149
129150 return $ data ;
0 commit comments