Skip to content

Commit 0bc7d90

Browse files
Merge pull request #156 from magento-commerce/MCLOUD-14020
MCLOUD-14020: Symphony package constants & tags fixes
2 parents 0c41186 + 7df8fe4 commit 0bc7d90

File tree

1 file changed

+84
-2
lines changed

1 file changed

+84
-2
lines changed

src/Environment/ConfigReader.php

Lines changed: 84 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
use Magento\CloudPatches\Filesystem\Filesystem;
1212
use Magento\CloudPatches\Filesystem\FileSystemException;
1313
use Symfony\Component\Yaml\Yaml;
14+
use Symfony\Component\Yaml\Tag\TaggedValue;
1415
use Symfony\Component\Yaml\Exception\ParseException;
1516

1617
/**
@@ -60,11 +61,92 @@ public function read(): array
6061
if (!$this->filesystem->exists($path)) {
6162
$this->config = [];
6263
} else {
63-
$parseFlag = defined(Yaml::class . '::PARSE_CONSTANT') ? Yaml::PARSE_CONSTANT : 0;
64-
$this->config = (array)Yaml::parse($this->filesystem->get($path), $parseFlag);
64+
$flags = 0;
65+
if (defined(Yaml::class . '::PARSE_CONSTANT')) {
66+
$flags |= Yaml::PARSE_CONSTANT;
67+
}
68+
if (defined(Yaml::class . '::PARSE_CUSTOM_TAGS')) {
69+
$flags |= Yaml::PARSE_CUSTOM_TAGS;
70+
}
71+
$this->config = (array) Yaml::parse(
72+
$this->filesystem->get($path),
73+
$flags
74+
);
75+
76+
$this->config = $this->normalizeYamlData($this->config);
6577
}
6678
}
6779

6880
return $this->config;
6981
}
82+
83+
/**
84+
* Recursively normalizes Symfony YAML TaggedValue objects into PHP-native values.
85+
*
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.
91+
*
92+
* Ensures all YAML data is converted to scalars or arrays suitable for safe merging.
93+
*
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.
99+
*/
100+
private function normalizeYamlData(mixed $data): mixed
101+
{
102+
if ($data instanceof TaggedValue) {
103+
$tag = $data->getTag(); // e.g. "php/const:\PDO::MYSQL_ATTR_LOCAL_INFILE"
104+
$value = $data->getValue();
105+
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;
127+
}
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];
141+
}
142+
143+
// Recursively normalize arrays
144+
if (is_array($data)) {
145+
foreach ($data as $key => $value) {
146+
$data[$key] = $this->normalizeYamlData($value);
147+
}
148+
}
149+
150+
return $data;
151+
}
70152
}

0 commit comments

Comments
 (0)