1 | <?php |
||||
2 | namespace SpareParts\Pillar\Mapper\Dibi; |
||||
3 | |||||
4 | use Doctrine\Common\Annotations\Reader; |
||||
5 | use SpareParts\Pillar\Entity\IEntity; |
||||
6 | use SpareParts\Pillar\Mapper\Annotation\Column; |
||||
7 | use SpareParts\Pillar\Mapper\Annotation\IPillarAnnotation; |
||||
8 | use SpareParts\Pillar\Mapper\Annotation\Table; |
||||
9 | use SpareParts\Pillar\Mapper\Annotation\VirtualEntity; |
||||
10 | use SpareParts\Pillar\Mapper\EntityMappingException; |
||||
11 | use SpareParts\Pillar\Mapper\IMapper; |
||||
12 | |||||
13 | class AnnotationMapper implements IMapper |
||||
14 | { |
||||
15 | /** |
||||
16 | * @var Reader |
||||
17 | */ |
||||
18 | private $annotationReader; |
||||
19 | |||||
20 | /** |
||||
21 | * @var IEntityMapping[] |
||||
22 | */ |
||||
23 | private $dibiMappingCache = []; |
||||
24 | |||||
25 | /** |
||||
26 | * Mapper constructor. |
||||
27 | * |
||||
28 | * @param Reader $annotationReader |
||||
29 | */ |
||||
30 | 6 | public function __construct(Reader $annotationReader) |
|||
31 | { |
||||
32 | 6 | $this->annotationReader = $annotationReader; |
|||
33 | 6 | } |
|||
34 | |||||
35 | /** |
||||
36 | * @param string|IEntity $classnameOrInstance |
||||
37 | * @return IEntityMapping |
||||
38 | * @throws EntityMappingException |
||||
39 | */ |
||||
40 | 6 | public function getEntityMapping($classnameOrInstance) |
|||
41 | { |
||||
42 | 6 | $className = $classnameOrInstance; |
|||
43 | 6 | if (is_object($classnameOrInstance)) { |
|||
44 | 2 | if (!($classnameOrInstance instanceof IEntity)) { |
|||
0 ignored issues
–
show
introduced
by
![]() |
|||||
45 | throw new EntityMappingException(sprintf('Expected class implementing IEntity interface, got %s instead', get_class($classnameOrInstance))); |
||||
46 | } |
||||
47 | 2 | $className = get_class($classnameOrInstance); |
|||
48 | } |
||||
49 | |||||
50 | 6 | if (!isset($this->dibiMappingCache[$className])) { |
|||
51 | 6 | $class = new \ReflectionClass($className); |
|||
52 | 6 | $tableInfoList = []; |
|||
53 | 6 | $isVirtualEntity = false; |
|||
54 | |||||
55 | 6 | foreach ($this->annotationReader->getClassAnnotations($class) as $classAnnotation) { |
|||
56 | 6 | if (!($classAnnotation instanceof IPillarAnnotation)) { |
|||
57 | continue; |
||||
58 | } |
||||
59 | |||||
60 | 6 | if ($classAnnotation instanceof Table) { |
|||
61 | 6 | $identifier = $classAnnotation->getIdentifier() ?: $classAnnotation->getName(); |
|||
62 | 6 | $tableInfoList[$identifier] = new TableInfo( |
|||
63 | 6 | $classAnnotation->getName(), |
|||
64 | 6 | $identifier, |
|||
65 | 6 | $classAnnotation->getCode() |
|||
66 | ); |
||||
67 | } |
||||
68 | |||||
69 | 6 | if ($classAnnotation instanceof VirtualEntity) { |
|||
70 | 6 | $isVirtualEntity = true; |
|||
71 | } |
||||
72 | } |
||||
73 | |||||
74 | 6 | $columnInfoList = []; |
|||
75 | 6 | foreach ($class->getProperties() as $property) { |
|||
76 | 6 | $enabledForSelect = true; |
|||
77 | // null means this property is not mapped to ANY table = probably not mapped column - ignore it. |
||||
78 | // true means this property is mapped to a table, and that table was not used - exception |
||||
79 | // false means this property is mapped to a table and at least one of those tables is used - ok |
||||
80 | 6 | $danglingProperty = null; |
|||
81 | 6 | foreach ($this->annotationReader->getPropertyAnnotations($property) as $propertyAnnotation) { |
|||
82 | 6 | if (!($propertyAnnotation instanceof Column)) { |
|||
83 | continue; |
||||
84 | } |
||||
85 | 6 | if (is_null($danglingProperty)) { |
|||
86 | 6 | $danglingProperty = true; |
|||
87 | } |
||||
88 | |||||
89 | 6 | if (!isset($tableInfoList[$propertyAnnotation->getTable()])) { |
|||
90 | // this is possibly not a mistake - property may have multiple Column annotations, and not be using all at once in the current entity |
||||
91 | continue; |
||||
92 | // throw new EntityMappingException(sprintf('Entity :`%s` property: `%s` is mapped to table identified as: `%s`, but no such table identifier is present.', $className, $property->getName(), $propertyAnnotation->getTable())); |
||||
93 | } |
||||
94 | 6 | $danglingProperty = false; |
|||
95 | |||||
96 | 6 | $columnInfoList[] = new ColumnInfo( |
|||
97 | 6 | $propertyAnnotation->getName() ?: $property->getName(), |
|||
98 | 6 | $property->getName(), |
|||
99 | 6 | $tableInfoList[$propertyAnnotation->getTable()], |
|||
100 | 6 | $propertyAnnotation->isPrimary(), |
|||
101 | 6 | $propertyAnnotation->isDeprecated(), |
|||
102 | 6 | $enabledForSelect, |
|||
103 | 6 | $propertyAnnotation->getCustomSelect() |
|||
0 ignored issues
–
show
It seems like
$propertyAnnotation->getCustomSelect() can also be of type string ; however, parameter $customSelectSql of SpareParts\Pillar\Mapper...lumnInfo::__construct() does only seem to accept null , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
104 | ); |
||||
105 | // only first @column annotation should be used for selecting |
||||
106 | // all following @column are there for saving/updating |
||||
107 | 6 | $enabledForSelect = false; |
|||
108 | } |
||||
109 | |||||
110 | // dangling property = property which will never be selected, throw an exception |
||||
111 | // ignore dangling properties for abstract and virtual entities |
||||
112 | 6 | if ($danglingProperty === true && !$class->isAbstract() && !$isVirtualEntity) { |
|||
113 | 6 | throw new EntityMappingException(sprintf('Entity: `%s` has property `%s` mapped to tables, but none of those tables are used in the entity. Maybe you forgot to use the table in the select?', $className, $property->getName())); |
|||
0 ignored issues
–
show
It seems like
$className can also be of type SpareParts\Pillar\Entity\IEntity ; however, parameter $args of sprintf() does only seem to accept string , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
114 | } |
||||
115 | } |
||||
116 | |||||
117 | 6 | $this->dibiMappingCache[$className] = new EntityMapping( |
|||
118 | 6 | $className, $tableInfoList, $columnInfoList, $isVirtualEntity |
|||
0 ignored issues
–
show
It seems like
$className can also be of type SpareParts\Pillar\Entity\IEntity ; however, parameter $entityClassName of SpareParts\Pillar\Mapper...yMapping::__construct() does only seem to accept string , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
119 | ); |
||||
120 | } |
||||
121 | 6 | return $this->dibiMappingCache[$className]; |
|||
122 | } |
||||
123 | } |
||||
124 |