Skip to content

Commit 39d92d4

Browse files
authored
Move image config from YAML to attributes (#4421)
2 parents 6dac05f + 48c260c commit 39d92d4

39 files changed

Lines changed: 555 additions & 316 deletions
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Shopsys\FrameworkBundle\Component\Image\Config\Attributes;
6+
7+
use Attribute;
8+
9+
#[Attribute(Attribute::TARGET_CLASS | Attribute::IS_REPEATABLE)]
10+
class EntityImage
11+
{
12+
public const string DEFAULT_NAME = 'default';
13+
14+
public function __construct(
15+
public readonly string $name = self::DEFAULT_NAME,
16+
public readonly bool $multiple = false,
17+
) {
18+
}
19+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Shopsys\FrameworkBundle\Component\Image\Config\Attributes;
6+
7+
use Attribute;
8+
9+
#[Attribute(Attribute::TARGET_CLASS)]
10+
class EntityImageFolder
11+
{
12+
public function __construct(
13+
public readonly string $name,
14+
) {
15+
}
16+
}

src/Component/Image/Config/Exception/EntityParseException.php

Lines changed: 0 additions & 23 deletions
This file was deleted.

src/Component/Image/Config/ImageConfig.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,12 @@
1111
class ImageConfig
1212
{
1313
/**
14-
* @var array<class-string, \Shopsys\FrameworkBundle\Component\Image\Config\ImageEntityConfig>
14+
* @var array<string,\Shopsys\FrameworkBundle\Component\Image\Config\ImageEntityConfig>
1515
*/
1616
protected array $imageEntityConfigsByClass;
1717

1818
/**
19-
* @param \Shopsys\FrameworkBundle\Component\Image\Config\ImageEntityConfig[] $imageEntityConfigsByClass
19+
* @param array<string,\Shopsys\FrameworkBundle\Component\Image\Config\ImageEntityConfig> $imageEntityConfigsByClass
2020
*/
2121
public function __construct(
2222
array $imageEntityConfigsByClass,
@@ -26,7 +26,7 @@ public function __construct(
2626
}
2727

2828
/**
29-
* @param \Shopsys\FrameworkBundle\Component\Image\Config\ImageEntityConfig[] $imageEntityConfigsByClass
29+
* @param array<string,\Shopsys\FrameworkBundle\Component\Image\Config\ImageEntityConfig> $imageEntityConfigsByClass
3030
*/
3131
protected function setUpImageEntityConfigsByClass(array $imageEntityConfigsByClass): void
3232
{

src/Component/Image/Config/ImageConfigDefinition.php

Lines changed: 0 additions & 53 deletions
This file was deleted.

src/Component/Image/Config/ImageConfigLoader.php

Lines changed: 83 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -4,128 +4,149 @@
44

55
namespace Shopsys\FrameworkBundle\Component\Image\Config;
66

7+
use ReflectionAttribute;
8+
use ReflectionClass;
79
use Shopsys\FrameworkBundle\Component\EntityExtension\EntityNameResolver;
10+
use Shopsys\FrameworkBundle\Component\Image\Config\Attributes\EntityImage;
11+
use Shopsys\FrameworkBundle\Component\Image\Config\Attributes\EntityImageFolder;
812
use Shopsys\FrameworkBundle\Component\Image\Config\Exception\DuplicateEntityNameExceptionInvalid;
913
use Shopsys\FrameworkBundle\Component\Image\Config\Exception\DuplicateTypeNameExceptionInvalid;
10-
use Shopsys\FrameworkBundle\Component\Image\Config\Exception\EntityParseException;
11-
use Shopsys\FrameworkBundle\Component\Image\Config\Exception\InvalidImageConfigException;
12-
use Symfony\Component\Config\Definition\Processor;
13-
use Symfony\Component\Filesystem\Exception\FileNotFoundException;
14-
use Symfony\Component\Filesystem\Filesystem;
15-
use Symfony\Component\Yaml\Parser;
1614

1715
class ImageConfigLoader
1816
{
1917
/**
20-
* @var array<class-string, \Shopsys\FrameworkBundle\Component\Image\Config\ImageEntityConfig>
18+
* @var array<class-string,\Shopsys\FrameworkBundle\Component\Image\Config\ImageEntityConfig>
2119
*/
2220
protected array $foundEntityConfigs;
2321

2422
/**
2523
* @var string[]
2624
*/
27-
protected array $foundEntityNames;
25+
protected array $foundFolderNames;
2826

2927
public function __construct(
30-
protected readonly Filesystem $filesystem,
3128
protected readonly EntityNameResolver $entityNameResolver,
3229
) {
3330
}
3431

35-
public function loadFromYaml(string $filename): ImageConfig
32+
/**
33+
* @param class-string[] $entityClasses
34+
*/
35+
public function loadFromEntityClasses(array $entityClasses): ImageConfig
3636
{
37-
$yamlParser = new Parser();
37+
$this->foundEntityConfigs = [];
38+
$this->foundFolderNames = [];
3839

39-
if (!$this->filesystem->exists($filename)) {
40-
throw new FileNotFoundException(
41-
'File ' . $filename . ' does not exist',
42-
);
43-
}
40+
foreach ($entityClasses as $entityClass) {
41+
$imageAttributes = $this->getImageAttributesFromClass($entityClass);
4442

45-
$imageConfigDefinition = new ImageConfigDefinition();
46-
$processor = new Processor();
43+
if ($imageAttributes === []) {
44+
continue;
45+
}
4746

48-
$inputConfig = $yamlParser->parse(file_get_contents($filename));
49-
$outputConfig = $processor->processConfiguration($imageConfigDefinition, [$inputConfig]);
47+
$folderName = $this->getFolderName($entityClass);
5048

51-
$preparedConfig = $this->loadFromArray($outputConfig);
49+
$this->processEntity($entityClass, $folderName, $imageAttributes);
50+
}
5251

53-
return new ImageConfig($preparedConfig, $this->entityNameResolver);
52+
return new ImageConfig($this->foundEntityConfigs, $this->entityNameResolver);
5453
}
5554

5655
/**
57-
* @return \Shopsys\FrameworkBundle\Component\Image\Config\ImageEntityConfig[]
56+
* @param class-string $entityClass
57+
* @return array<\Shopsys\FrameworkBundle\Component\Image\Config\Attributes\EntityImage>
5858
*/
59-
public function loadFromArray(array $outputConfig): array
59+
protected function getImageAttributesFromClass(string $entityClass): array
6060
{
61-
$this->foundEntityConfigs = [];
62-
$this->foundEntityNames = [];
63-
64-
foreach ($outputConfig as $entityConfig) {
65-
try {
66-
$this->processEntityConfig($entityConfig);
67-
} catch (InvalidImageConfigException $e) {
68-
throw new EntityParseException(
69-
$entityConfig[ImageConfigDefinition::CONFIG_CLASS],
70-
$e,
71-
);
61+
$reflectionClass = new ReflectionClass($entityClass);
62+
63+
do {
64+
$attributes = $reflectionClass->getAttributes(EntityImage::class, ReflectionAttribute::IS_INSTANCEOF);
65+
66+
if ($attributes !== []) {
67+
return array_map(static fn (ReflectionAttribute $attribute) => $attribute->newInstance(), $attributes);
7268
}
73-
}
69+
} while ($reflectionClass = $reflectionClass->getParentClass());
7470

75-
return $this->foundEntityConfigs;
71+
return [];
7672
}
7773

78-
protected function processEntityConfig(array $entityConfig): void
74+
protected function getFolderName(string $entityClass): string
7975
{
80-
$entityClass = $entityConfig[ImageConfigDefinition::CONFIG_CLASS];
81-
$entityName = $entityConfig[ImageConfigDefinition::CONFIG_ENTITY_NAME];
76+
$originalReflectionClass = new ReflectionClass($entityClass);
77+
$reflectionClass = $originalReflectionClass;
78+
79+
do {
80+
$attributes = $reflectionClass->getAttributes(EntityImageFolder::class, ReflectionAttribute::IS_INSTANCEOF);
81+
82+
if ($attributes !== []) {
83+
return $attributes[0]->newInstance()->name;
84+
}
85+
} while ($reflectionClass = $reflectionClass->getParentClass());
8286

83-
if (array_key_exists($entityClass, $this->foundEntityConfigs)
84-
|| array_key_exists($entityName, $this->foundEntityNames)
85-
) {
86-
throw new DuplicateEntityNameExceptionInvalid($entityName);
87+
return lcfirst($originalReflectionClass->getShortName());
88+
}
89+
90+
protected function processEntity(string $entityClass, string $folderName, array $imageAttributes): void
91+
{
92+
if (array_key_exists($entityClass, $this->foundEntityConfigs)) {
93+
throw new DuplicateEntityNameExceptionInvalid($folderName);
8794
}
8895

89-
$types = $this->prepareTypes($entityConfig[ImageConfigDefinition::CONFIG_TYPES]);
90-
$multipleByType = $this->getMultipleByType($entityConfig);
96+
$types = $this->prepareTypes($imageAttributes);
97+
$multipleByType = $this->getMultipleByType($imageAttributes);
98+
99+
$imageEntityConfig = new ImageEntityConfig($folderName, $entityClass, $types, $multipleByType);
100+
101+
if (isset($this->foundFolderNames[$folderName])) {
102+
$existingClass = $this->foundFolderNames[$folderName];
103+
104+
if (!is_subclass_of($entityClass, $existingClass) && !is_subclass_of($existingClass, $entityClass)) {
105+
throw new DuplicateEntityNameExceptionInvalid($folderName);
106+
}
107+
108+
if (is_subclass_of($existingClass, $entityClass)) {
109+
return;
110+
}
111+
112+
unset($this->foundEntityConfigs[$this->foundFolderNames[$folderName]]);
113+
}
91114

92-
$imageEntityConfig = new ImageEntityConfig($entityName, $entityClass, $types, $multipleByType);
93-
$this->foundEntityNames[$entityName] = $entityName;
94115
$this->foundEntityConfigs[$entityClass] = $imageEntityConfig;
116+
$this->foundFolderNames[$folderName] = $entityClass;
95117
}
96118

97119
/**
120+
* @param array<\Shopsys\FrameworkBundle\Component\Image\Config\Attributes\EntityImage> $imageAttributes
98121
* @return string[]
99122
*/
100-
protected function prepareTypes(array $typesConfig): array
123+
protected function prepareTypes(array $imageAttributes): array
101124
{
102125
$result = [];
103126

104-
foreach ($typesConfig as $typeConfig) {
105-
$typeName = $typeConfig[ImageConfigDefinition::CONFIG_TYPE_NAME];
106-
107-
if (array_key_exists($typeName, $result)) {
108-
throw new DuplicateTypeNameExceptionInvalid($typeName);
127+
foreach ($imageAttributes as $imageAttribute) {
128+
if (in_array($imageAttribute->name, $result, true)) {
129+
throw new DuplicateTypeNameExceptionInvalid($imageAttribute->name);
109130
}
110131

111-
$result[$typeName] = $typeName;
132+
$result[] = $imageAttribute->name;
112133
}
113134

114135
return $result;
115136
}
116137

117138
/**
118-
* @return array<string, bool>
139+
* @param array<\Shopsys\FrameworkBundle\Component\Image\Config\Attributes\EntityImage> $imageAttributes
140+
* @return array<string,bool>
119141
*/
120-
protected function getMultipleByType(array $entityConfig): array
142+
protected function getMultipleByType(array $imageAttributes): array
121143
{
122144
$multipleByType = [];
123-
$multipleByType[ImageEntityConfig::WITHOUT_NAME_KEY] = $entityConfig[ImageConfigDefinition::CONFIG_MULTIPLE];
124145

125-
foreach ($entityConfig[ImageConfigDefinition::CONFIG_TYPES] as $typeConfig) {
126-
$type = $typeConfig[ImageConfigDefinition::CONFIG_TYPE_NAME];
127-
$multiple = $typeConfig[ImageConfigDefinition::CONFIG_MULTIPLE];
128-
$multipleByType[$type] = $multiple;
146+
foreach ($imageAttributes as $imageAttribute) {
147+
$key = $imageAttribute->name === EntityImage::DEFAULT_NAME ? ImageEntityConfig::WITHOUT_NAME_KEY : $imageAttribute->name;
148+
149+
$multipleByType[$key] = $imageAttribute->multiple;
129150
}
130151

131152
return $multipleByType;

0 commit comments

Comments
 (0)