Completed
Push — master ( 707688...6da863 )
by Mike
04:47 queued 02:08
created

ODM/CouchDB/Mapping/ClassMetadataFactory.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
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
6
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
7
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
8
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
9
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
10
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
11
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
12
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
13
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14
 *
15
 * This software consists of voluntary contributions made by many individuals
16
 * and is licensed under the MIT license. For more information, see
17
 * <http://www.doctrine-project.org>.
18
 */
19
20
namespace Doctrine\ODM\CouchDB\Mapping;
21
22
use Doctrine\ODM\CouchDB\DocumentManager,
23
    Doctrine\ODM\CouchDB\CouchDBException,
24
    Doctrine\ODM\CouchDB\Mapping\ClassMetadata,
25
    Doctrine\Common\Persistence\Mapping\Driver\MappingDriver,
26
    Doctrine\Common\Persistence\Mapping\ClassMetadata as ClassMetadataInterface,
27
    Doctrine\Common\Persistence\Mapping\ReflectionService,
28
    Doctrine\Common\Persistence\Mapping\RuntimeReflectionService,
29
    Doctrine\Common\Persistence\Mapping\AbstractClassMetadataFactory;
30
31
/**
32
 * The ClassMetadataFactory is used to create ClassMetadata objects that contain all the
33
 * metadata mapping information of a class which describes how a class should be mapped
34
 * to a document database.
35
36
 * @license     http://www.opensource.org/licenses/lgpl-license.php LGPL
37
 * @link        www.doctrine-project.com
38
 * @since       1.0
39
 * @author      Benjamin Eberlei <[email protected]>
40
 * @author      Lukas Kahwe Smith <[email protected]>
41
 */
42
class ClassMetadataFactory extends AbstractClassMetadataFactory
43
{
44
    /**
45
     * @var DocumentManager
46
     */
47
    private $dm;
48
49
    /**
50
     *  The used metadata driver.
51
     *
52
     * @var MappingDriver
53
     */
54
    private $driver;
55
56
    /**
57
     * Creates a new factory instance that uses the given DocumentManager instance.
58
     *
59
     * @param DocumentManager $dm The DocumentManager instance
60
     * @throws \RuntimeException
61
     */
62
    public function __construct(DocumentManager $dm)
63
    {
64
        $this->dm = $dm;
65
        $config = $this->dm->getConfiguration();
66
        $this->setCacheDriver($config->getMetadataCacheImpl());
67
        $this->driver = $config->getMetadataDriverImpl();
68
        if (!$this->driver) {
69
            throw new \RuntimeException('No metadata driver was configured.');
70
        }
71
    }
72
73
    /**
74
     * {@inheritdoc}
75
     */
76
    protected function doLoadMetadata($class, $parent, $rootEntityFound, array $nonSuperclassParents)
77
    {
78
        /** @var $parent ClassMetaData */
79
        if ($parent) {
80
            $this->addAssociationsMapping($class, $parent);
81
            $this->addFieldMapping($class, $parent);
82
            $this->addIndexes($class, $parent);
83
            $parent->deriveChildMetadata($class);
84
            $class->setParentClasses($nonSuperclassParents);
85
        }
86
87
        if ($this->getDriver()) {
88
            $this->getDriver()->loadMetadataForClass($class->getName(), $class);
89
        }
90
91
        $this->validateMapping($class);
92
    }
93
94
    /**
95
     * Check for any possible shortcomings in the class:
96
     *
97
     * The class must have an identifier field unless it's an embedded document or mapped superclass.
98
     */
99
    private function validateMapping(ClassMetadataInterface $class)
100
    {
101
        if (!$class->identifier && !$class->isEmbeddedDocument && !$class->isMappedSuperclass) {
102
            throw new MappingException("An identifier (@Id) field is required in {$class->getName()}.");
103
        }
104
    }
105
106
    private function addFieldMapping(ClassMetadataInterface $class, ClassMetadataInterface $parent)
107
    {
108
        foreach ($parent->reflFields as $name => $field) {
109
            $class->reflFields[$name] = $field;
110
        }
111
112
        foreach ($parent->fieldMappings as $name => $field) {
113
            $class->fieldMappings[$name] = $field;
114
        }
115
116
        foreach ($parent->jsonNames as $name => $field) {
117
            $class->jsonNames[$name] = $field;
118
        }
119
120
        if ($parent->identifier) {
121
            $class->setIdentifier($parent->identifier);
122
        }
123
    }
124
125
    private function addIndexes(ClassMetadata $class, ClassMetadata $parent)
126
    {
127
        $class->indexes = $parent->indexes;
128
    }
129
130
    /**
131
     *
132
     * @param ClassMetadataInterface $class
133
     * @param ClassMetadataInterface $parent
134
     */
135
    private function addAssociationsMapping(ClassMetadataInterface $class, ClassMetadataInterface $parent)
136
    {
137
        foreach ($parent->associationsMappings as $name => $field) {
138
            $class->associationsMappings[$name] = $field;
139
        }
140
    }
141
142
    /**
143
     * {@inheritdoc}
144
     */
145
    protected function getFqcnFromAlias($namespaceAlias, $simpleClassName)
146
    {
147
        return $this->dm->getConfiguration()->getDocumentNamespace($namespaceAlias) . '\\' . $simpleClassName;
148
    }
149
150
    /**
151
     * Forces the factory to load the metadata of all classes known to the underlying
152
     * mapping driver.
153
     *
154
     * @return array The ClassMetadata instances of all mapped classes.
155
     */
156
    public function getAllMetadata()
157
    {
158
        $metadata = array();
159
        foreach ($this->driver->getAllClassNames() as $className) {
160
            $metadata[] = $this->getMetadataFor($className);
161
        }
162
163
        return $metadata;
164
    }
165
166
    /**
167
     * Gets the class metadata descriptor for a class.
168
     *
169
     * @param string $className The name of the class.
170
     * @return ClassMetadata
171
     * @throws MappingException
172
     */
173
    public function getMetadataFor($className)
174
    {
175
        $metadata = parent::getMetadataFor($className);
176
177
        if ($metadata) {
178
            return $metadata;
179
        }
180
181
        throw MappingException::classNotMapped($className);
0 ignored issues
show
The call to MappingException::classNotMapped() has too many arguments starting with $className.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
182
    }
183
184
    /**
185
     * Loads the metadata of the class in question and all it's ancestors whose metadata
186
     * is still not loaded.
187
     *
188
     * @param string $className The name of the class for which the metadata should get loaded.
189
     * @return array
190
     * @throws MappingException
191
     */
192
    protected function loadMetadata($className)
193
    {
194
        if (class_exists($className)) {
195
            return parent::loadMetadata($className);
196
        }
197
        throw MappingException::classNotFound($className);
198
    }
199
200
    /**
201
     * Creates a new ClassMetadata instance for the given class name.
202
     *
203
     * @param string $className
204
     * @return ClassMetadata
205
     */
206
    protected function newClassMetadataInstance($className)
207
    {
208
        return new ClassMetadata($className);
209
    }
210
211
    /**
212
     * {@inheritdoc}
213
     */
214
    protected function getDriver()
215
    {
216
        return $this->driver;
217
    }
218
219
    /**
220
     * {@inheritdoc}
221
     */
222
    protected function initialize()
223
    {
224
        $this->initialized = true;
225
    }
226
227
    /**
228
     * {@inheritdoc}
229
     */
230
    protected function initializeReflection(ClassMetadataInterface $class, ReflectionService $reflService)
231
    {
232
        $class->initializeReflection($reflService);
233
    }
234
235
    /**
236
     * {@inheritdoc}
237
     */
238
    protected function wakeupReflection(ClassMetadataInterface $class, ReflectionService $reflService)
239
    {
240
        $class->wakeupReflection($reflService);
241
    }
242
243
    /**
244
     * {@inheritDoc}
245
     */
246
    protected function isEntity(ClassMetadataInterface $class)
247
    {
248
        return isset($class->isMappedSuperclass) && $class->isMappedSuperclass === false;
0 ignored issues
show
Accessing isMappedSuperclass 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...
249
    }
250
}
251