Skip to content

Commit a94d8fc

Browse files
Merge pull request #232 from magento-commerce/develop
MCLOUD-14199 - Merge develop branch into 2002.2
2 parents e765c76 + aba61ef commit a94d8fc

10 files changed

Lines changed: 555 additions & 20 deletions

File tree

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "magento/ece-tools",
33
"description": "Provides tools to build and deploy Magento 2 Enterprise Edition",
44
"type": "magento2-component",
5-
"version": "2002.2.8",
5+
"version": "2002.2.9",
66
"license": "OSL-3.0",
77
"repositories": {
88
"repo.magento.com": {

src/App/ErrorInfo.php

Lines changed: 83 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
use Magento\MagentoCloud\Filesystem\Driver\File;
1111
use Magento\MagentoCloud\Filesystem\FileList;
1212
use Magento\MagentoCloud\Filesystem\FileSystemException;
13+
use Symfony\Component\Yaml\Tag\TaggedValue;
1314
use Symfony\Component\Yaml\Yaml;
1415

1516
/**
@@ -64,10 +65,90 @@ public function get(int $errorCode): array
6465
private function loadErrors(): void
6566
{
6667
if (empty($this->errors)) {
67-
$this->errors = Yaml::parse(
68+
$parseFlags = 0;
69+
if (defined(Yaml::class . '::PARSE_CONSTANT')) {
70+
$parseFlags |= Yaml::PARSE_CONSTANT;
71+
}
72+
if (defined(Yaml::class . '::PARSE_CUSTOM_TAGS')) {
73+
$parseFlags |= Yaml::PARSE_CUSTOM_TAGS;
74+
}
75+
76+
$this->errors = (array) Yaml::parse(
6877
$this->file->fileGetContents($this->fileList->getErrorSchema()),
69-
Yaml::PARSE_CONSTANT
78+
$parseFlags
7079
);
80+
81+
$this->errors = $this->normalizeYamlData($this->errors) ?? [];
82+
}
83+
}
84+
85+
/**
86+
* Recursively normalizes Symfony YAML TaggedValue objects into PHP-native values.
87+
*
88+
* Handles the following YAML tags:
89+
* - !env: resolves environment variables.
90+
* - !include: parses and normalizes included YAML files.
91+
* - !php/const: resolves PHP constants (e.g. !php/const:\PDO::ATTR_ERRMODE).
92+
* - Other or unknown tags: recursively normalize their values.
93+
*
94+
* Ensures all YAML data is converted to scalars or arrays suitable for safe merging.
95+
*
96+
* @param mixed $data The parsed YAML data (array, scalar, or TaggedValue).
97+
* @return mixed The normalized data structure.
98+
*
99+
* @SuppressWarnings("PHPMD.NPathComplexity")
100+
* @SuppressWarnings("PHPMD.CyclomaticComplexity") Method is intentionally complex due to tag resolution logic.
101+
*/
102+
private function normalizeYamlData(mixed $data): mixed
103+
{
104+
if ($data instanceof TaggedValue) {
105+
$tag = $data->getTag(); // e.g. "php/const:\PDO::MYSQL_ATTR_LOCAL_INFILE"
106+
$value = $data->getValue();
107+
108+
// Handle php/const tags (Symfony strips leading '!')
109+
if (str_starts_with($tag, 'php/const:')) {
110+
// Extract the constant name
111+
$constName = substr($tag, strlen('php/const:'));
112+
$constName = ltrim($constName, '\\');
113+
114+
// Resolve the constant name to its value if defined
115+
$constKey = defined($constName) ? constant($constName) : $constName;
116+
117+
// Handle YAML quirk where ": 1" is parsed literally
118+
$raw = is_string($value) ? $value : (string)$value;
119+
$cleanVal = str_replace([':', ' '], '', $raw);
120+
$constVal = is_numeric($cleanVal) ? (int)$cleanVal : $cleanVal;
121+
122+
return [$constKey => $constVal];
123+
}
124+
125+
// Handle !env
126+
if ($tag === 'env') {
127+
$envValue = getenv((string)$value);
128+
return $envValue !== false ? $envValue : null;
129+
}
130+
131+
// Handle !include
132+
if ($tag === 'include') {
133+
if (file_exists((string)$value)) {
134+
$included = Yaml::parseFile((string)$value);
135+
return $this->normalizeYamlData($included);
136+
}
137+
return null;
138+
}
139+
140+
// Default — recursively normalize nested tagged structures
141+
$normalized = $this->normalizeYamlData($value);
142+
return is_array($normalized) ? $normalized : [$normalized];
71143
}
144+
145+
// Recursively normalize arrays
146+
if (is_array($data)) {
147+
foreach ($data as $key => $value) {
148+
$data[$key] = $this->normalizeYamlData($value);
149+
}
150+
}
151+
152+
return $data;
72153
}
73154
}

src/Command/Dev/GenerateSchemaError.php

Lines changed: 82 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
use Symfony\Component\Console\Command\Command;
1414
use Symfony\Component\Console\Input\InputInterface;
1515
use Symfony\Component\Console\Output\OutputInterface;
16+
use Symfony\Component\Yaml\Tag\TaggedValue;
1617
use Symfony\Component\Yaml\Yaml;
1718

1819
/**
@@ -64,22 +65,98 @@ protected function configure(): void
6465
*/
6566
protected function execute(InputInterface $input, OutputInterface $output): int
6667
{
67-
$errors = Yaml::parse(
68+
$parseFlags = 0;
69+
if (defined(Yaml::class . '::PARSE_CONSTANT')) {
70+
$parseFlags |= Yaml::PARSE_CONSTANT;
71+
}
72+
if (defined(Yaml::class . '::PARSE_CUSTOM_TAGS')) {
73+
$parseFlags |= Yaml::PARSE_CUSTOM_TAGS;
74+
}
75+
$errors = (array) Yaml::parse(
6876
$this->file->fileGetContents($this->fileList->getErrorSchema()),
69-
Yaml::PARSE_CONSTANT
77+
$parseFlags
7078
);
7179

80+
$errors = $this->normalizeYamlData($errors);
7281
$errors = $this->groupErrors($errors);
73-
74-
$docs = $this->generateDocs($errors);
82+
$docs = $this->generateDocs($errors);
7583

7684
$this->file->filePutContents($this->fileList->getErrorDistConfig(), $docs);
77-
7885
$output->writeln(sprintf('File %s was generated', $this->fileList->getErrorDistConfig()));
7986

8087
return Cli::SUCCESS;
8188
}
8289

90+
/**
91+
* Recursively normalizes Symfony YAML TaggedValue objects into PHP-native values.
92+
*
93+
* Handles the following YAML tags:
94+
* - !env: resolves environment variables.
95+
* - !include: parses and normalizes included YAML files.
96+
* - !php/const: resolves PHP constants (e.g. !php/const:\PDO::ATTR_ERRMODE).
97+
* - Other or unknown tags: recursively normalize their values.
98+
*
99+
* Ensures all YAML data is converted to scalars or arrays suitable for safe merging.
100+
*
101+
* @param mixed $data The parsed YAML data (array, scalar, or TaggedValue).
102+
* @return mixed The normalized data structure.
103+
*
104+
* @SuppressWarnings("PHPMD.NPathComplexity")
105+
* @SuppressWarnings("PHPMD.CyclomaticComplexity") Method is intentionally complex due to tag resolution logic.
106+
*/
107+
private function normalizeYamlData(mixed $data): mixed
108+
{
109+
if ($data instanceof TaggedValue) {
110+
$tag = $data->getTag(); // e.g. "php/const:\PDO::MYSQL_ATTR_LOCAL_INFILE"
111+
$value = $data->getValue();
112+
113+
// Handle php/const tags (Symfony strips leading '!')
114+
if (str_starts_with($tag, 'php/const:')) {
115+
// Extract the constant name
116+
$constName = substr($tag, strlen('php/const:'));
117+
$constName = ltrim($constName, '\\');
118+
119+
// Resolve the constant name to its value if defined
120+
$constKey = defined($constName) ? constant($constName) : $constName;
121+
122+
// Handle YAML quirk where ": 1" is parsed literally
123+
$raw = is_string($value) ? $value : (string)$value;
124+
$cleanVal = str_replace([':', ' '], '', $raw);
125+
$constVal = is_numeric($cleanVal) ? (int)$cleanVal : $cleanVal;
126+
127+
return [$constKey => $constVal];
128+
}
129+
130+
// Handle !env
131+
if ($tag === 'env') {
132+
$envValue = getenv((string)$value);
133+
return $envValue !== false ? $envValue : null;
134+
}
135+
136+
// Handle !include
137+
if ($tag === 'include') {
138+
if (file_exists((string)$value)) {
139+
$included = Yaml::parseFile((string)$value);
140+
return $this->normalizeYamlData($included);
141+
}
142+
return null;
143+
}
144+
145+
// Default — recursively normalize nested tagged structures
146+
$normalized = $this->normalizeYamlData($value);
147+
return is_array($normalized) ? $normalized : [$normalized];
148+
}
149+
150+
// Recursively normalize arrays
151+
if (is_array($data)) {
152+
foreach ($data as $key => $value) {
153+
$data[$key] = $this->normalizeYamlData($value);
154+
}
155+
}
156+
157+
return $data;
158+
}
159+
83160
/**
84161
* Groups errors by type and stage
85162
*

src/Config/Environment/Reader.php

Lines changed: 73 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
use Magento\MagentoCloud\Filesystem\ConfigFileList;
1111
use Magento\MagentoCloud\Filesystem\FileSystemException;
1212
use Magento\MagentoCloud\Filesystem\Driver\File;
13+
use Symfony\Component\Yaml\Tag\TaggedValue;
1314
use Symfony\Component\Yaml\Yaml;
1415
use Symfony\Component\Yaml\Exception\ParseException;
1516

@@ -65,10 +66,81 @@ public function read(): array
6566
if (defined(Yaml::class . '::PARSE_CUSTOM_TAGS')) {
6667
$parseFlag |= Yaml::PARSE_CUSTOM_TAGS;
6768
}
68-
$this->config = (array)Yaml::parse($this->file->fileGetContents($path), $parseFlag);
69+
$this->config = (array) Yaml::parse($this->file->fileGetContents($path), $parseFlag);
70+
$this->config = $this->normalizeYamlData($this->config);
6971
}
7072
}
7173

7274
return $this->config;
7375
}
76+
77+
/**
78+
* Recursively normalizes Symfony YAML TaggedValue objects into PHP-native values.
79+
*
80+
* Handles the following YAML tags:
81+
* - !env: resolves environment variables.
82+
* - !include: parses and normalizes included YAML files.
83+
* - !php/const: resolves PHP constants (e.g. !php/const:\PDO::ATTR_ERRMODE).
84+
* - Other or unknown tags: recursively normalize their values.
85+
*
86+
* Ensures all YAML data is converted to scalars or arrays suitable for safe merging.
87+
*
88+
* @param mixed $data The parsed YAML data (array, scalar, or TaggedValue).
89+
* @return mixed The normalized data structure.
90+
*
91+
* @SuppressWarnings("PHPMD.NPathComplexity")
92+
* @SuppressWarnings("PHPMD.CyclomaticComplexity") Method is intentionally complex due to tag resolution logic.
93+
*/
94+
private function normalizeYamlData(mixed $data): mixed
95+
{
96+
if ($data instanceof TaggedValue) {
97+
$tag = $data->getTag(); // e.g. "php/const:\PDO::MYSQL_ATTR_LOCAL_INFILE"
98+
$value = $data->getValue();
99+
100+
// Handle php/const tags (Symfony strips leading '!')
101+
if (str_starts_with($tag, 'php/const:')) {
102+
// Extract the constant name
103+
$constName = substr($tag, strlen('php/const:'));
104+
$constName = ltrim($constName, '\\');
105+
106+
// Resolve the constant name to its value if defined
107+
$constKey = defined($constName) ? constant($constName) : $constName;
108+
109+
// Handle YAML quirk where ": 1" is parsed literally
110+
$raw = is_string($value) ? $value : (string)$value;
111+
$cleanVal = str_replace([':', ' '], '', $raw);
112+
$constVal = is_numeric($cleanVal) ? (int)$cleanVal : $cleanVal;
113+
114+
return [$constKey => $constVal];
115+
}
116+
117+
// Handle !env
118+
if ($tag === 'env') {
119+
$envValue = getenv((string)$value);
120+
return $envValue !== false ? $envValue : null;
121+
}
122+
123+
// Handle !include
124+
if ($tag === 'include') {
125+
if (file_exists((string)$value)) {
126+
$included = Yaml::parseFile((string)$value);
127+
return $this->normalizeYamlData($included);
128+
}
129+
return null;
130+
}
131+
132+
// Default — recursively normalize nested tagged structures
133+
$normalized = $this->normalizeYamlData($value);
134+
return is_array($normalized) ? $normalized : [$normalized];
135+
}
136+
137+
// Recursively normalize arrays
138+
if (is_array($data)) {
139+
foreach ($data as $key => $value) {
140+
$data[$key] = $this->normalizeYamlData($value);
141+
}
142+
}
143+
144+
return $data;
145+
}
74146
}

0 commit comments

Comments
 (0)