Skip to content

Commit d8abe5d

Browse files
committed
Merge remote-tracking branch 'commerce/main' into story-351-product-reviews
2 parents d1c38c1 + e74ea72 commit d8abe5d

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+467
-6596
lines changed

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ As a result, after the component installation,
88
a merchant will notice new indexers in the corresponding admin menu,
99
where each indexer represents a data feed.
1010

11+
### Code generation
12+
Magento_CatalogExportApi module contains DTOs that are automatically generated on every run of setup:upgrade and setup:di:compile.
13+
1114
## Requirements and Dependencies
1215
The export component is a set Magento modules and requires Magento 2.3 and higher.
1316

Lines changed: 0 additions & 371 deletions
Original file line numberDiff line numberDiff line change
@@ -1,371 +0,0 @@
1-
<?php
2-
/**
3-
* Copyright © Magento, Inc. All rights reserved.
4-
* See COPYING.txt for license details.
5-
*/
6-
7-
declare(strict_types=1);
8-
9-
namespace Magento\CatalogExport\Console\Command;
10-
11-
use Magento\Framework\Console\Cli;
12-
use Magento\Framework\Exception\FileSystemException;
13-
use Magento\Framework\Exception\LocalizedException;
14-
use Magento\Framework\Exception\RuntimeException;
15-
use Magento\Framework\Filesystem\Driver\File;
16-
use Magento\Framework\Phrase;
17-
use Magento\Framework\Xml\Parser;
18-
use Nette\PhpGenerator\PhpFile;
19-
use Nette\PhpGenerator\PsrPrinter;
20-
use Symfony\Component\Console\Command\Command;
21-
use Symfony\Component\Console\Input\InputInterface;
22-
use Symfony\Component\Console\Input\InputOption;
23-
use Symfony\Component\Console\Output\OutputInterface;
24-
use Magento\DataExporter\Config\ConfigInterface;
25-
26-
/**
27-
* Class Generate
28-
*
29-
* Nette is required for this module - 'composer require nette/php-generator'
30-
*
31-
* A destination folder is required to define where the files will be generated.
32-
*
33-
* php bin/magento dto:generate --destination-folder
34-
* /var/www/commerce-data-export/app/code/Magento/CatalogExportApi/Api/Data
35-
*
36-
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
37-
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
38-
* @SuppressWarnings(PHPMD.NPathComplexity)
39-
*
40-
*/
41-
class GenerateDTOFiles extends Command
42-
{
43-
/**
44-
* Command Option
45-
* @var string
46-
*/
47-
private const DESTINATION_FOLDER = 'destination-folder';
48-
49-
/**
50-
* @var Parser
51-
*/
52-
private $parser;
53-
54-
/**
55-
* @var File
56-
*/
57-
private $fileDriver;
58-
59-
/**
60-
* @var ConfigInterface
61-
*/
62-
private $config;
63-
64-
/**
65-
* @var string[]
66-
*/
67-
private $baseConfigEntities = [
68-
'Product',
69-
'Category',
70-
'ProductVariant',
71-
'Review',
72-
'RatingMetadata',
73-
];
74-
75-
/**
76-
* @param Parser $parser
77-
* @param File $fileDriver
78-
* @param ConfigInterface $config
79-
* @param $string|null $name
80-
*/
81-
public function __construct(
82-
Parser $parser,
83-
File $fileDriver,
84-
ConfigInterface $config,
85-
$name = null
86-
) {
87-
parent::__construct($name);
88-
$this->parser = $parser;
89-
$this->fileDriver = $fileDriver;
90-
$this->config = $config;
91-
}
92-
93-
/**
94-
* @inheritdoc
95-
*/
96-
protected function configure()
97-
{
98-
$this->setName('dto:generate');
99-
$this->setDescription(
100-
'This will generate the provider class for a module or file. A output path must be defined.'
101-
);
102-
$this->addOption(
103-
self::DESTINATION_FOLDER,
104-
null,
105-
InputOption::VALUE_REQUIRED,
106-
__('Destination Folder')
107-
);
108-
parent::configure();
109-
}
110-
111-
/**
112-
* Generate classes
113-
*
114-
* @param InputInterface $input
115-
* @param OutputInterface $output
116-
* @throws LocalizedException
117-
* @throws RuntimeException
118-
* @throws FileSystemException
119-
* @return int|void
120-
*/
121-
protected function execute(InputInterface $input, OutputInterface $output): ?int
122-
{
123-
if (!$outPutLocation = $input->getOption(self::DESTINATION_FOLDER)) {
124-
throw new RuntimeException(new Phrase('Destination not defined'));
125-
}
126-
127-
$baseNamespace = $this->resolveNameSpace($outPutLocation);
128-
$parsedEntities = [];
129-
foreach ($this->baseConfigEntities as $node) {
130-
$parsedEntities[] = $this->getConfig($node);
131-
}
132-
$parsedArray = \array_merge(...$parsedEntities);
133-
134-
$classesData = $this->prepareDtoClassData($parsedArray, $baseNamespace);
135-
136-
$this->createDirectory($outPutLocation);
137-
try {
138-
$this->generateFiles($classesData, $baseNamespace, $outPutLocation);
139-
} catch (\Throwable $e) {
140-
$output->writeln('Error: ' . $e->getMessage());
141-
return Cli::RETURN_FAILURE;
142-
}
143-
$output->writeln('Files has been generated');
144-
145-
return Cli::RETURN_SUCCESS;
146-
}
147-
148-
/**
149-
* Return entities config.
150-
*
151-
* @param string $entity
152-
* @param array $parsedArray
153-
* @return array
154-
*/
155-
private function getConfig(string $entity, $parsedArray = [])
156-
{
157-
$parsedEntity = $this->config->get($entity);
158-
if ($parsedEntity) {
159-
$parsedArray[$entity] = $parsedEntity;
160-
161-
foreach ($parsedEntity['field'] as $field) {
162-
if (!$this->config->isScalar($field['type'])) {
163-
$parsedArray = $this->getConfig($field['type'], $parsedArray);
164-
}
165-
}
166-
}
167-
return $parsedArray;
168-
}
169-
170-
/**
171-
* Build structure required to build DTO
172-
*
173-
* @param array $parsedArray
174-
* @param string $baseNamespace
175-
* @return array
176-
*/
177-
private function prepareDtoClassData(array $parsedArray, string $baseNamespace)
178-
{
179-
$result = [];
180-
if (empty($parsedArray)) {
181-
return $result;
182-
}
183-
184-
foreach ($parsedArray as $schemaConfig) {
185-
foreach ($schemaConfig['field'] as &$field) {
186-
$field['type'] = $this->mapType($field['type'], $baseNamespace);
187-
$field['name'] = lcfirst(str_replace('_', '', ucwords($field['name'], '_')));
188-
}
189-
190-
$result[$schemaConfig['name']] = $schemaConfig['field'];
191-
}
192-
193-
return $result;
194-
}
195-
196-
/**
197-
* Resolve namespace
198-
*
199-
* @param string $filePath
200-
* @return string
201-
*/
202-
private function resolveNameSpace(string $filePath): string
203-
{
204-
$filePath = trim($filePath, DIRECTORY_SEPARATOR);
205-
return str_replace('/', '\\', strstr($filePath, 'Magento'));
206-
}
207-
208-
/**
209-
* Map type
210-
*
211-
* @param string $type
212-
* @param string $baseNameSpace
213-
* @return string
214-
*/
215-
private function mapType(string $type, string $baseNameSpace): string
216-
{
217-
switch ($type) {
218-
case 'Int':
219-
$type = 'int';
220-
break;
221-
case 'ID':
222-
case 'String':
223-
$type = 'string';
224-
break;
225-
case 'Boolean':
226-
$type = 'bool';
227-
break;
228-
case 'Float':
229-
$type = 'float';
230-
break;
231-
default:
232-
$type = '\\' . $baseNameSpace . '\\' . $type . '[]|null';
233-
}
234-
235-
return $type;
236-
}
237-
238-
/**
239-
* Generate files
240-
*
241-
* @param array $generateArray
242-
* @param string $baseNameSpace
243-
* @param string $baseFileLocation
244-
* @throws FileSystemException
245-
* @return void
246-
*/
247-
private function generateFiles(array $generateArray, string $baseNameSpace, string $baseFileLocation): void
248-
{
249-
$nonRequiredMethods = ['id'];
250-
foreach ($generateArray as $className => $phpClassFields) {
251-
// phpstan:ignore "Class Nette\PhpGenerator\PhpFile not found."
252-
$file = new PhpFile();
253-
$file->addComment('Copyright © Magento, Inc. All rights reserved.');
254-
$file->addComment('See COPYING.txt for license details.');
255-
$file->addComment('');
256-
$file->addComment('Generated from et_schema.xml. DO NOT EDIT!');
257-
$file->setStrictTypes();
258-
$namespace = $file->addNamespace($baseNameSpace);
259-
$class = $namespace->addClass($className);
260-
$class->addComment($className . ' entity');
261-
$class->addComment('');
262-
$class->addComment('phpcs:disable Magento2.PHP.FinalImplementation');
263-
$class->addComment('@SuppressWarnings(PHPMD.BooleanGetMethodName)');
264-
$class->addComment('@SuppressWarnings(PHPMD.TooManyFields)');
265-
$class->addComment('@SuppressWarnings(PHPMD.ExcessivePublicCount)');
266-
$class->addComment('@SuppressWarnings(PHPMD.ExcessiveClassComplexity)');
267-
$class->addComment('@SuppressWarnings(PHPMD.CouplingBetweenObjects)');
268-
foreach ($phpClassFields as $field) {
269-
$repeated = $field['repeated'];
270-
$name = $field['name'];
271-
$type = $field['type'];
272-
273-
$commentName = preg_replace('/(?<!\ )[A-Z]/', ' $0', $field['name']);
274-
$property = $class->addProperty($field['name'])->setPrivate();
275-
276-
if (true === $repeated) {
277-
if (substr($type, -4) !== 'null') {
278-
$property->addComment('@var ' . 'array');
279-
} else {
280-
$property->addComment('@var ' . $type);
281-
}
282-
} else {
283-
$property->addComment('@var ' . str_replace('[]|null', '', $type));
284-
}
285-
$method = $class->addMethod('get' . ucfirst($name));
286-
$method->addComment('Get ' . strtolower($commentName));
287-
$method->addComment('');
288-
if (true === $repeated) {
289-
if (substr($type, -4) !== 'null') {
290-
$method->addComment('@return ' . $type . '[]');
291-
} else {
292-
$method->addComment('@return ' . $type);
293-
}
294-
} else {
295-
$method->addComment('@return ' . str_replace('[]|null', '', $type));
296-
}
297-
if (true === $repeated) {
298-
$method->setReturnType('array');
299-
} else {
300-
$method->setReturnType(str_replace('[]|null', '', $type));
301-
}
302-
if (!in_array($name, $nonRequiredMethods)) {
303-
$method->setReturnNullable();
304-
}
305-
$method->addBody('return $this->' . $name . ';');
306-
$method = $class->addMethod('set' . ucfirst($name));
307-
$method->addComment('Set ' . strtolower($commentName));
308-
$method->addComment('');
309-
if (true === $repeated) {
310-
$method->addComment(
311-
'@param ' . str_replace('[]|null', '', $type) . '[] $' . $name
312-
);
313-
} else {
314-
$method->addComment(
315-
'@param ' . str_replace('[]|null', '', $type) . ' $' . $name
316-
);
317-
}
318-
$method->addComment('@return void');
319-
if (true === $repeated) {
320-
if (!in_array($name, $nonRequiredMethods)) {
321-
$method->addParameter($name, null)->setType('array')->setNullable();
322-
} else {
323-
$method->addParameter($name, null)->setType('array');
324-
}
325-
} else {
326-
if (!in_array($name, $nonRequiredMethods)) {
327-
$method->addParameter($name)
328-
->setType(str_replace('[]|null', '', $type))
329-
->setNullable();
330-
} else {
331-
$method->addParameter($name)->setType(str_replace('[]|null', '', $type));
332-
}
333-
}
334-
$method->setReturnType('void');
335-
$method->addBody('$this->' . $name . ' = $' . $name . ';');
336-
}
337-
// phpstan:ignore "Class Nette\PhpGenerator\PsrPrinter not found."
338-
$print = new PsrPrinter();
339-
$this->writeToFile($baseFileLocation . '/' . $className . '.php', $print->printFile($file));
340-
}
341-
}
342-
343-
/**
344-
* Create directory
345-
*
346-
* @param string $outPutLocation
347-
* @throws FileSystemException
348-
* @return void
349-
*/
350-
private function createDirectory(string $outPutLocation): void
351-
{
352-
if (!$this->fileDriver->isExists($outPutLocation)) {
353-
$this->fileDriver->createDirectory($outPutLocation, 0755);
354-
}
355-
}
356-
357-
/**
358-
* Write to file
359-
*
360-
* @param string $fileLocation
361-
* @param string $output
362-
* @throws FileSystemException
363-
* @return void
364-
*/
365-
private function writeToFile(string $fileLocation, string $output): void
366-
{
367-
$resource = $this->fileDriver->fileOpen($fileLocation, 'w');
368-
$this->fileDriver->fileWrite($resource, $output);
369-
$this->fileDriver->fileClose($resource);
370-
}
371-
}

0 commit comments

Comments
 (0)