Completed
Push — master ( 3ff7e6...cf5edc )
by Kamil
96:30 queued 63:14
created

LoadMetadataSubscriber::loadClassMetadata()   B

Complexity

Conditions 4
Paths 5

Size

Total Lines 25
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 25
rs 8.5806
c 0
b 0
f 0
cc 4
eloc 15
nc 5
nop 1
1
<?php
2
3
/*
4
 * This file is part of the Sylius package.
5
 *
6
 * (c) Paweł Jędrzejewski
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Sylius\Bundle\AssociationBundle\Doctrine\ORM\Subscriber;
13
14
use Doctrine\Common\EventSubscriber;
15
use Doctrine\Common\Persistence\Mapping\ClassMetadata;
16
use Doctrine\ORM\Event\LoadClassMetadataEventArgs;
17
18
/**
19
 * @author Łukasz Chruściel <[email protected]>
20
 */
21
final class LoadMetadataSubscriber implements EventSubscriber
22
{
23
    /**
24
     * @var array
25
     */
26
    protected $subjects;
27
28
    /**
29
     * @param array $subjects
30
     */
31
    public function __construct(array $subjects)
32
    {
33
        $this->subjects = $subjects;
34
    }
35
36
    /**
37
     * @return array
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use string[].

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
38
     */
39
    public function getSubscribedEvents()
40
    {
41
        return [
42
            'loadClassMetadata',
43
        ];
44
    }
45
46
    /**
47
     * @param LoadClassMetadataEventArgs $eventArgs
48
     */
49
    public function loadClassMetadata(LoadClassMetadataEventArgs $eventArgs)
50
    {
51
        $metadata = $eventArgs->getClassMetadata();
52
        $metadataFactory = $eventArgs->getEntityManager()->getMetadataFactory();
53
54
        foreach ($this->subjects as $subject => $class) {
55
            if ($class['association']['classes']['model'] === $metadata->getName()) {
56
                $associationEntity = $class['subject'];
57
                $associationEntityMetadata = $metadataFactory->getMetadataFor($associationEntity);
0 ignored issues
show
Comprehensibility Naming introduced by
The variable name $associationEntityMetadata exceeds the maximum configured length of 20.

Very long variable names usually make code harder to read. It is therefore recommended not to make variable names too verbose.

Loading history...
58
59
                $associationTypeModel = $class['association_type']['classes']['model'];
60
                $associationTypeMetadata = $metadataFactory->getMetadataFor($associationTypeModel);
0 ignored issues
show
Comprehensibility Naming introduced by
The variable name $associationTypeMetadata exceeds the maximum configured length of 20.

Very long variable names usually make code harder to read. It is therefore recommended not to make variable names too verbose.

Loading history...
61
62
                $metadata->mapManyToOne($this->createSubjectMapping($associationEntity, $subject, $associationEntityMetadata));
63
                $metadata->mapManyToMany($this->createAssociationMapping($associationEntity, $subject, $associationEntityMetadata));
64
                $metadata->mapManyToOne($this->createAssociationTypeMapping($associationTypeModel, $associationTypeMetadata));
65
            }
66
67
            if ($class['subject'] === $metadata->getName()) {
68
                $associationEntity = $class['association']['classes']['model'];
69
70
                $metadata->mapOneToMany($this->createAssociationsMapping($associationEntity));
71
            }
72
        }
73
    }
74
75
    /**
76
     * @param string $associationEntity
77
     * @param string $subject
78
     * @param ClassMetadata $associationEntityMetadata
79
     *
80
     * @return array
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use array<string,string|array[]>.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
81
     */
82
    private function createSubjectMapping($associationEntity, $subject, ClassMetadata $associationEntityMetadata)
0 ignored issues
show
Comprehensibility Naming introduced by
The variable name $associationEntityMetadata exceeds the maximum configured length of 20.

Very long variable names usually make code harder to read. It is therefore recommended not to make variable names too verbose.

Loading history...
83
    {
84
        return [
85
            'fieldName' => 'owner',
86
            'targetEntity' => $associationEntity,
87
            'inversedBy' => 'associations',
88
            'joinColumns' => [[
89
                'name' => $subject.'_id',
90
                'referencedColumnName' => $associationEntityMetadata->fieldMappings['id']['columnName'],
0 ignored issues
show
Bug introduced by
Accessing fieldMappings on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
91
                'nullable' => false,
92
                'onDelete' => 'CASCADE',
93
            ]],
94
        ];
95
    }
96
97
    /**
98
     * @param string $associationEntity
99
     * @param string $subject
100
     * @param ClassMetadata $associationEntityMetadata
101
     *
102
     * @return array
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use array<string,string|arra...tring,string|false>[]>>.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
103
     */
104
    private function createAssociationMapping($associationEntity, $subject, ClassMetadata $associationEntityMetadata)
0 ignored issues
show
Comprehensibility Naming introduced by
The variable name $associationEntityMetadata exceeds the maximum configured length of 20.

Very long variable names usually make code harder to read. It is therefore recommended not to make variable names too verbose.

Loading history...
105
    {
106
        return [
107
            'fieldName' => 'associatedObjects',
108
            'targetEntity' => $associationEntity,
109
            'joinTable' => [
110
                'name' => sprintf('sylius_%s_association_%s', $subject, $subject),
111
                'joinColumns' => [[
112
                    'name' => 'association_id',
113
                    'referencedColumnName' => 'id',
114
                    'nullable' => false,
115
                    'unique' => false,
116
                    'onDelete' => 'CASCADE',
117
                ]],
118
                'inverseJoinColumns' => [[
119
                    'name' => $subject.'_id',
120
                    'referencedColumnName' => $associationEntityMetadata->fieldMappings['id']['columnName'],
0 ignored issues
show
Bug introduced by
Accessing fieldMappings on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
121
                    'nullable' => false,
122
                    'unique' => false,
123
                    'onDelete' => 'CASCADE',
124
                ]],
125
            ],
126
        ];
127
    }
128
129
    /**
130
     * @param string $associationModel
131
     * @param ClassMetadata $associationMetadata
132
     *
133
     * @return array
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use array<string,string|array[]>.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
134
     */
135
    private function createAssociationTypeMapping($associationModel, ClassMetadata $associationMetadata)
136
    {
137
        return [
138
            'fieldName' => 'type',
139
            'targetEntity' => $associationModel,
140
            'joinColumns' => [[
141
                'name' => 'association_type_id',
142
                'referencedColumnName' => $associationMetadata->fieldMappings['id']['columnName'],
0 ignored issues
show
Bug introduced by
Accessing fieldMappings on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
143
                'nullable' => false,
144
                'onDelete' => 'CASCADE',
145
            ]],
146
        ];
147
    }
148
149
    /**
150
     * @param string $associationEntity
151
     *
152
     * @return array
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use array<string,string|string[]>.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
153
     */
154
    private function createAssociationsMapping($associationEntity)
155
    {
156
        return [
157
            'fieldName' => 'associations',
158
            'targetEntity' => $associationEntity,
159
            'mappedBy' => 'owner',
160
            'cascade' => ['all'],
161
        ];
162
    }
163
}
164