Completed
Pull Request — master (#14)
by Pavel
05:32 queued 02:29
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 18
    public function loadMetadataForClass($className, ClassMetadata $metadata)
27
    {
28 18
        $element = $this->getElement($className);
29
30 18
        switch ($element['type']) {
31 18
            case 'entity':
32 18
                if (array_key_exists('repositoryClass', $element)) {
33 2
                    $metadata->setCustomRepositoryClass($element['repositoryClass']);
34 2
                }
35 18
                break;
36
            case 'mappedSuperclass':
37
                $metadata->isMappedSuperclass = true;
38
                $metadata->setCustomRepositoryClass(
39
                    array_key_exists('repositoryClass', $element) ? $element['repositoryClass'] : null
40
                );
41
                break;
42 18
        }
43
44
        // Configure API
45 18
        if (array_key_exists('api', $element)) {
46 18
            if (array_key_exists('factory', $element['api'])) {
47 18
                $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 18
            }
49 18
        }
50
51
        // Configure Client
52 18
        if (array_key_exists('client', $element)) {
53 18
            if (array_key_exists('name', $element['client'])) {
54 18
                $metadata->clientName = $element['client']['name'];
55 18
            }
56
57 18
            $methodProvider = null;
58 18
            if (array_key_exists('methods', $element['client'])) {
59
                $methodProvider = new MethodProvider($element['client']['methods']);
60
            }
61 18
            if (array_key_exists('entityPath', $element['client'])) {
62
                $pathSeparator  =
63 18
                    array_key_exists('entityPathSeparator', $element['client']) ?
64 18
                        $element['client']['entityPathSeparator'] :
65 18
                        EntityMethodProvider::DEFAULT_PATH_SEPARATOR;
66
                $methodProvider =
67 18
                    new EntityMethodProvider($element['client']['entityPath'], $pathSeparator, $methodProvider);
68 18
            }
69
70 18
            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 18
            if (null !== $methodProvider) {
75 18
                $metadata->methodProvider = $methodProvider;
76 18
            }
77 18
        }
78
79
        // Configure fields
80 18
        if (array_key_exists('fields', $element)) {
81 18
            foreach ($element['fields'] as $field => $mapping) {
82 18
                $mapping = $this->fieldToArray($field, $mapping);
83 18
                $metadata->mapField($mapping);
84 18
            }
85 18
        }
86
87
        // Configure identifiers
88 18
        $associationIds = [];
89 18
        if (array_key_exists('id', $element)) {
90
            // Evaluate identifier settings
91 18
            $defaults = ['generator' => ['strategy' => 'NATURAL']];
92 18
            foreach ($element['id'] as $name => $idElement) {
93 18
                if (isset($idElement['associationKey']) && (bool)$idElement['associationKey'] === true) {
94
                    $associationIds[$name] = true;
95
                    continue;
96
                }
97
98 18
                $mapping = $this->fieldToArray($name, $idElement);
99
100 18
                $mapping['id'] = true;
101 18
                $idElement     = array_replace_recursive($defaults, $idElement);
102
103 18
                $mapping['generator']['strategy'] =
104 18
                    constant(ApiMetadata::class . '::GENERATOR_TYPE_' . $idElement['generator']['strategy']);
105
106 18
                $metadata->mapIdentifier($mapping);
107 18
            }
108 18
        }
109
110 18
        foreach (['oneToOne', 'manyToOne', 'oneToMany'] as $type) {
111 18
            if (array_key_exists($type, $element)) {
112 14
                $associations = $element[$type];
113 14
                foreach ($associations as $name => $association) {
114 14
                    $this->mapAssociation($metadata, $type, $name, $association, $associationIds);
115 14
                }
116 14
            }
117 18
        }
118 18
    }
119
120
    /**
121
     * @param EntityMetadata $metadata
122
     * @param string         $type
123
     * @param string         $name
124
     * @param array          $association
125
     * @param int[]          $associationIds
126
     */
127 14
    protected function mapAssociation(EntityMetadata $metadata, $type, $name, $association, $associationIds)
128
    {
129 14
        $mapping           = $this->fieldToArray($name, $association);
130 14
        $mapping['target'] = $association['target'];
131 14
        if (isset($association['fetch'])) {
132
            $mapping['fetch'] = constant(ApiMetadata::class . '::FETCH_' . $association['fetch']);
133
        }
134
        switch ($type) {
135 14 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 14
            case 'manyToOne':
149 14
                $mapping['type'] = EntityMetadata::MANY_TO_ONE;
150 14
                if (array_key_exists('inversedBy', $association)) {
151 14
                    $mapping['inversedBy'] = $association['inversedBy'];
152 14
                }
153 14
                $metadata->mapManyToOne($mapping);
154 14
                break;
155 14 View Code Duplication
            case 'oneToMany':
156 14
                $mapping['type'] = EntityMetadata::ONE_TO_MANY;
157 14
                if (array_key_exists('mappedBy', $association)) {
158 14
                    $mapping['mappedBy'] = $association['mappedBy'];
159 14
                }
160 14
                if (array_key_exists('orderBy', $association)) {
161
                    $mapping['orderBy'] = $association['orderBy'];
162
                }
163 14
                if (array_key_exists('indexBy', $association)) {
164
                    $mapping['indexBy'] = $association['indexBy'];
165
                }
166 14
                $metadata->mapOneToMany($mapping);
167 14
                break;
168
        }
169 14
    }
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 18
    protected function loadMappingFile($file)
181
    {
182 18
        return Yaml::parse(file_get_contents($file));
183
    }
184
185 18
    private function fieldToArray($field, $source)
186
    {
187
        $mapping = [
188 18
            'field'    => $field,
189 18
            'type'     => 'string',
190 18
            'nullable' => true,
191 18
        ];
192
193 18
        if (array_key_exists('type', $source)) {
194 18
            $mapping['type'] = $source['type'];
195 18
        }
196
197 18
        if (array_key_exists('nullable', $source)) {
198 5
            $mapping['nullable'] = $source['nullable'];
199 5
        }
200
201 18
        if (array_key_exists('api_field', $source)) {
202 16
            $mapping['api_field'] = $source['api_field'];
203 16
        }
204
205 18
        return $mapping;
206
    }
207
}
208
209