Skip to content

Commit 3675325

Browse files
MCLOUD-14020: Normalized method improvements
1 parent 0f214bd commit 3675325

File tree

2 files changed

+94
-52
lines changed

2 files changed

+94
-52
lines changed

src/Config/Source/CloudSource.php

Lines changed: 46 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ public function __construct(
7777
*/
7878
public function read(): Repository
7979
{
80-
$appConfigFile = $this->fileList->getAppConfig();
80+
$appConfigFile = $this->fileList->getAppConfig();
8181
$servicesConfigFile = $this->fileList->getServicesConfig();
8282

8383
if (!$this->filesystem->exists($appConfigFile) || !$this->filesystem->exists($servicesConfigFile)) {
@@ -162,49 +162,70 @@ public function read(): Repository
162162
}
163163

164164
/**
165-
* Recursively unwrap Symfony YAML TaggedValue objects and handle common tags.
165+
* Recursively normalizes Symfony YAML TaggedValue objects into PHP-native values.
166166
*
167-
* This method handles !env, !include, !php/const, and unknown tags,
168-
* ensuring all YAML values are normalized to arrays or scalars for safe merging.
167+
* Handles the following YAML tags:
168+
* - !env: resolves environment variables.
169+
* - !include: parses and normalizes included YAML files.
170+
* - !php/const: resolves PHP constants (e.g. !php/const:\PDO::ATTR_ERRMODE).
171+
* - Other or unknown tags: recursively normalize their values.
169172
*
170-
* @param mixed $data
171-
* @return mixed
173+
* Ensures all YAML data is converted to scalars or arrays suitable for safe merging.
172174
*
173-
* @SuppressWarnings("PHPMD.CyclomaticComplexity") Method is intentionally complex due to tag handling.
175+
* @param mixed $data The parsed YAML data (array, scalar, or TaggedValue).
176+
* @return mixed The normalized data structure.
177+
*
178+
* @SuppressWarnings("PHPMD.NPathComplexity")
179+
* @SuppressWarnings("PHPMD.CyclomaticComplexity") Method is intentionally complex due to tag resolution logic.
174180
*/
175181
private function normalizeYamlData(mixed $data): mixed
176182
{
177183
if ($data instanceof TaggedValue) {
178-
$tag = $data->getTag();
184+
$tag = $data->getTag(); // e.g. "php/const:\PDO::MYSQL_ATTR_LOCAL_INFILE"
179185
$value = $data->getValue();
180186

181-
switch ($tag) {
182-
case '!env':
183-
$envValue = getenv((string)$value);
184-
return $envValue !== false ? $envValue : null;
187+
// Handle php/const tags (Symfony strips leading '!')
188+
if (str_starts_with($tag, 'php/const:')) {
189+
// Extract the constant name
190+
$constName = substr($tag, strlen('php/const:'));
191+
$constName = ltrim($constName, '\\');
185192

186-
case '!include':
187-
if (file_exists((string)$value)) {
188-
$included = Yaml::parseFile((string)$value);
189-
return $this->normalizeYamlData($included);
190-
}
191-
return null;
193+
// Resolve the constant name to its value if defined
194+
$constKey = defined($constName) ? constant($constName) : $constName;
195+
196+
// Handle YAML quirk where ": 1" is parsed literally
197+
$raw = is_string($value) ? $value : (string)$value;
198+
$cleanVal = str_replace([':', ' '], '', $raw);
199+
$constVal = is_numeric($cleanVal) ? (int)$cleanVal : $cleanVal;
200+
201+
return [$constKey => $constVal];
202+
}
192203

193-
case '!php/const':
194-
// Evaluate the PHP constant
195-
return defined($value) ? constant($value) : null;
204+
// Handle !env
205+
if ($tag === 'env') {
206+
$envValue = getenv((string)$value);
207+
return $envValue !== false ? $envValue : null;
208+
}
196209

197-
default:
198-
$val = $this->normalizeYamlData($value);
199-
return is_array($val) ? $val : [$val];
210+
// Handle !include
211+
if ($tag === 'include') {
212+
if (file_exists((string)$value)) {
213+
$included = Yaml::parseFile((string)$value);
214+
return $this->normalizeYamlData($included);
215+
}
216+
return null;
200217
}
218+
219+
// Default — recursively normalize nested tagged structures
220+
$normalized = $this->normalizeYamlData($value);
221+
return is_array($normalized) ? $normalized : [$normalized];
201222
}
202223

224+
// Recursively normalize arrays
203225
if (is_array($data)) {
204226
foreach ($data as $key => $value) {
205227
$data[$key] = $this->normalizeYamlData($value);
206228
}
207-
return $data;
208229
}
209230

210231
return $data;

tests/functional/Codeception/TestInfrastructure.php

Lines changed: 48 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -712,49 +712,70 @@ private function readYamlConfiguration(string $path): array
712712
}
713713

714714
/**
715-
* Recursively unwrap Symfony YAML TaggedValue objects and handle common tags.
715+
* Recursively normalizes Symfony YAML TaggedValue objects into PHP-native values.
716716
*
717-
* This method handles !env, !include, !php/const, and unknown tags,
718-
* ensuring all YAML values are normalized to arrays or scalars for safe merging.
717+
* Handles the following YAML tags:
718+
* - !env: resolves environment variables.
719+
* - !include: parses and normalizes included YAML files.
720+
* - !php/const: resolves PHP constants (e.g. !php/const:\PDO::ATTR_ERRMODE).
721+
* - Other or unknown tags: recursively normalize their values.
719722
*
720-
* @param mixed $data
721-
* @return mixed
723+
* Ensures all YAML data is converted to scalars or arrays suitable for safe merging.
722724
*
723-
* @SuppressWarnings("PHPMD.CyclomaticComplexity") Method is intentionally complex due to tag handling.
725+
* @param mixed $data The parsed YAML data (array, scalar, or TaggedValue).
726+
* @return mixed The normalized data structure.
727+
*
728+
* @SuppressWarnings("PHPMD.NPathComplexity")
729+
* @SuppressWarnings("PHPMD.CyclomaticComplexity") Method is intentionally complex due to tag resolution logic.
724730
*/
725731
private function normalizeYamlData(mixed $data): mixed
726732
{
727733
if ($data instanceof TaggedValue) {
728-
$tag = $data->getTag();
734+
$tag = $data->getTag(); // e.g. "php/const:\PDO::MYSQL_ATTR_LOCAL_INFILE"
729735
$value = $data->getValue();
730736

731-
switch ($tag) {
732-
case '!env':
733-
$envValue = getenv((string)$value);
734-
return $envValue !== false ? $envValue : null;
735-
736-
case '!include':
737-
if (file_exists((string)$value)) {
738-
$included = Yaml::parseFile((string)$value);
739-
return $this->normalizeYamlData($included);
740-
}
741-
return null;
742-
743-
case '!php/const':
744-
// Evaluate the PHP constant
745-
return defined($value) ? constant($value) : null;
746-
747-
default:
748-
$val = $this->normalizeYamlData($value);
749-
return is_array($val) ? $val : [$val];
737+
// Handle php/const tags (Symfony strips leading '!')
738+
if (str_starts_with($tag, 'php/const:')) {
739+
// Extract the constant name
740+
$constName = substr($tag, strlen('php/const:'));
741+
$constName = ltrim($constName, '\\');
742+
743+
// Resolve the constant name to its value if defined
744+
$constKey = defined($constName) ? constant($constName) : $constName;
745+
746+
// Handle YAML quirk where ": 1" is parsed literally
747+
$raw = is_string($value) ? $value : (string)$value;
748+
$cleanVal = str_replace([':', ' '], '', $raw);
749+
$constVal = is_numeric($cleanVal) ? (int)$cleanVal : $cleanVal;
750+
751+
return [$constKey => $constVal];
750752
}
753+
754+
// Handle !env
755+
if ($tag === 'env') {
756+
$envValue = getenv((string)$value);
757+
return $envValue !== false ? $envValue : null;
758+
}
759+
760+
// Handle !include
761+
if ($tag === 'include') {
762+
if (file_exists((string)$value)) {
763+
$included = Yaml::parseFile((string)$value);
764+
return $this->normalizeYamlData($included);
765+
}
766+
return null;
767+
}
768+
769+
// Default — recursively normalize nested tagged structures
770+
$normalized = $this->normalizeYamlData($value);
771+
return is_array($normalized) ? $normalized : [$normalized];
751772
}
752773

774+
// Recursively normalize arrays
753775
if (is_array($data)) {
754776
foreach ($data as $key => $value) {
755777
$data[$key] = $this->normalizeYamlData($value);
756778
}
757-
return $data;
758779
}
759780

760781
return $data;

0 commit comments

Comments
 (0)