Completed
Pull Request — master (#14)
by Pavel
04:14
created

Mapping/Driver/YmlMetadataDriver.php (2 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
namespace Bankiru\Api\Doctrine\Mapping\Driver;
4
5
use Bankiru\Api\Doctrine\Exception\MappingException;
6
use Bankiru\Api\Doctrine\Mapping\ApiMetadata;
7
use Bankiru\Api\Doctrine\Mapping\EntityMetadata;
8
use Bankiru\Api\Doctrine\Rpc\Method\EntityMethodProvider;
9
use Bankiru\Api\Doctrine\Rpc\Method\MethodProvider;
10
use Doctrine\Common\Persistence\Mapping\ClassMetadata;
11
use Doctrine\Common\Persistence\Mapping\Driver\FileDriver;
12
use Symfony\Component\Yaml\Exception\ParseException;
13
use Symfony\Component\Yaml\Yaml;
14
15
class YmlMetadataDriver extends FileDriver
16
{
17
    /**
18
     * Loads the metadata for the specified class into the provided container.
19
     *
20
     * @param string                       $className
21
     * @param EntityMetadata|ClassMetadata $metadata
22
     *
23
     * @return void
24
     * @throws MappingException
25
     */
26 20
    public function loadMetadataForClass($className, ClassMetadata $metadata)
27
    {
28 20
        $element = $this->getElement($className);
29
30 20
        switch ($element['type']) {
31 20
            case 'entity':
32 20
                if (array_key_exists('repositoryClass', $element)) {
33 2
                    $metadata->setCustomRepositoryClass($element['repositoryClass']);
34 2
                }
35 20
                break;
36
            case 'mappedSuperclass':
37
                $metadata->isMappedSuperclass = true;
38
                $metadata->setCustomRepositoryClass(
39
                    array_key_exists('repositoryClass', $element) ? $element['repositoryClass'] : null
40
                );
41
                break;
42 20
        }
43
44
        // Configure API
45 20
        if (array_key_exists('api', $element)) {
46 20
            if (array_key_exists('factory', $element['api'])) {
47 20
                $metadata->apiFactory = $element['api']['factory'];
0 ignored issues
show
Accessing apiFactory 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...
48 20
            }
49 20
        }
50
51
        // Configure Client
52 20
        if (array_key_exists('client', $element)) {
53 20
            if (array_key_exists('name', $element['client'])) {
54 20
                $metadata->clientName = $element['client']['name'];
55 20
            }
56
57 20
            $methodProvider = null;
58 20
            if (array_key_exists('methods', $element['client'])) {
59
                $methodProvider = new MethodProvider($element['client']['methods']);
60
            }
61 20
            if (array_key_exists('entityPath', $element['client'])) {
62
                $pathSeparator  =
63 20
                    array_key_exists('entityPathSeparator', $element['client']) ?
64 20
                        $element['client']['entityPathSeparator'] :
65 20
                        EntityMethodProvider::DEFAULT_PATH_SEPARATOR;
66
                $methodProvider =
67 20
                    new EntityMethodProvider($element['client']['entityPath'], $pathSeparator, $methodProvider);
68 20
            }
69
70 20
            if (null === $methodProvider && null === $metadata->methodProvider) {
0 ignored issues
show
Accessing methodProvider 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...
71
                throw MappingException::noMethods();
72
            }
73
74 20
            if (null !== $methodProvider) {
75 20
                $metadata->methodProvider = $methodProvider;
76 20
            }
77 20
        }
78
79
        // Configure fields
80 20
        if (array_key_exists('fields', $element)) {
81 20
            foreach ($element['fields'] as $field => $mapping) {
82 20
                $mapping = $this->fieldToArray($field, $mapping);
83 20
                $metadata->mapField($mapping);
84 20
            }
85 20
        }
86
87
        // Configure identifiers
88 20
        $associationIds = [];
89 20
        if (array_key_exists('id', $element)) {
90
            // Evaluate identifier settings
91 20
            $defaults = ['generator' => ['strategy' => 'NATURAL']];
92 20
            foreach ($element['id'] as $name => $idElement) {
93 20
                if (isset($idElement['associationKey']) && (bool)$idElement['associationKey'] === true) {
94
                    $associationIds[$name] = true;
95
                    continue;
96
                }
97
98 20
                $mapping = $this->fieldToArray($name, $idElement);
99
100 20
                $mapping['id'] = true;
101 20
                $idElement     = array_replace_recursive($defaults, $idElement);
102
103 20
                $mapping['generator']['strategy'] =
104 20
                    constant(ApiMetadata::class . '::GENERATOR_TYPE_' . $idElement['generator']['strategy']);
105
106 20
                $metadata->mapIdentifier($mapping);
107 20
            }
108 20
        }
109
110 20
        foreach (['oneToOne', 'manyToOne', 'oneToMany'] as $type) {
111 20
            if (array_key_exists($type, $element)) {
112 16
                $associations = $element[$type];
113 16
                foreach ($associations as $name => $association) {
114 16
                    $this->mapAssociation($metadata, $type, $name, $association, $associationIds);
115 16
                }
116 16
            }
117 20
        }
118 20
    }
119
120
    /**
121
     * @param EntityMetadata $metadata
122
     * @param string         $type
123
     * @param string         $name
124
     * @param array          $association
125
     * @param int[]          $associationIds
126
     */
127 16
    protected function mapAssociation(EntityMetadata $metadata, $type, $name, $association, $associationIds)
128
    {
129 16
        $mapping           = $this->fieldToArray($name, $association);
130 16
        $mapping['target'] = $association['target'];
131 16
        if (isset($association['fetch'])) {
132
            $mapping['fetch'] = constant(ApiMetadata::class . '::FETCH_' . $association['fetch']);
133
        }
134
        switch ($type) {
135 16 View Code Duplication
            case 'oneToOne':
136
                $mapping['type'] = EntityMetadata::ONE_TO_ONE;
137
                if (isset($associationIds[$mapping['field']])) {
138
                    $mapping['id'] = true;
139
                }
140
                if (array_key_exists('mappedBy', $association)) {
141
                    $mapping['mappedBy'] = $association['mappedBy'];
142
                }
143
                if (array_key_exists('inversedBy', $association)) {
144
                    $mapping['inversedBy'] = $association['inversedBy'];
145
                }
146
                $metadata->mapOneToOne($mapping);
147
                break;
148 16
            case 'manyToOne':
149 16
                $mapping['type'] = EntityMetadata::MANY_TO_ONE;
150 16
                if (array_key_exists('inversedBy', $association)) {
151 16
                    $mapping['inversedBy'] = $association['inversedBy'];
152 16
                }
153 16
                $metadata->mapManyToOne($mapping);
154 16
                break;
155 16 View Code Duplication
            case 'oneToMany':
156 16
                $mapping['type'] = EntityMetadata::ONE_TO_MANY;
157 16
                if (array_key_exists('mappedBy', $association)) {
158 16
                    $mapping['mappedBy'] = $association['mappedBy'];
159 16
                }
160 16
                if (array_key_exists('orderBy', $association)) {
161
                    $mapping['orderBy'] = $association['orderBy'];
162
                }
163 16
                if (array_key_exists('indexBy', $association)) {
164
                    $mapping['indexBy'] = $association['indexBy'];
165
                }
166 16
                $metadata->mapOneToMany($mapping);
167 16
                break;
168
        }
169 16
    }
170
171
    /**
172
     * Loads a mapping file with the given name and returns a map
173
     * from class/entity names to their corresponding file driver elements.
174
     *
175
     * @param string $file The mapping file to load.
176
     *
177
     * @return array
178
     * @throws ParseException
179
     */
180 20
    protected function loadMappingFile($file)
181
    {
182 20
        return Yaml::parse(file_get_contents($file));
183
    }
184
185 20
    private function fieldToArray($field, $source)
186
    {
187
        $mapping = [
188 20
            'field'    => $field,
189 20
            'type'     => 'string',
190 20
            'nullable' => true,
191 20
        ];
192
193 20
        if (array_key_exists('type', $source)) {
194 20
            $mapping['type'] = $source['type'];
195 20
        }
196
197 20
        if (array_key_exists('nullable', $source)) {
198 5
            $mapping['nullable'] = $source['nullable'];
199 5
        }
200
201 20
        if (array_key_exists('api_field', $source)) {
202 18
            $mapping['api_field'] = $source['api_field'];
203 18
        }
204
205 20
        return $mapping;
206
    }
207
}
208
209