Completed
Push — master ( f2e43e...df01cf )
by Maciej
14:18
created

ClassMetadata   A

Complexity

Total Complexity 19

Size/Duplication

Total Lines 164
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 2

Test Coverage

Coverage 89.47%

Importance

Changes 0
Metric Value
wmc 19
lcom 2
cbo 2
dl 0
loc 164
c 0
b 0
f 0
ccs 51
cts 57
cp 0.8947
rs 10

5 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 8 1
A mapField() 0 8 1
F __sleep() 0 74 12
A __wakeup() 0 16 4
A newInstance() 0 4 1
1
<?php
2
3
namespace Doctrine\ODM\MongoDB\Mapping;
4
5
use Doctrine\Instantiator\Instantiator;
6
7
/**
8
 * A <tt>ClassMetadata</tt> instance holds all the object-document mapping metadata
9
 * of a document and it's references.
10
 *
11
 * Once populated, ClassMetadata instances are usually cached in a serialized form.
12
 *
13
 * <b>IMPORTANT NOTE:</b>
14
 *
15
 * The fields of this class are only public for 2 reasons:
16
 * 1) To allow fast READ access.
17
 * 2) To drastically reduce the size of a serialized instance (private/protected members
18
 *    get the whole class name, namespace inclusive, prepended to every property in
19
 *    the serialized representation).
20
 *
21
 * @since       1.0
22
 */
23
class ClassMetadata extends ClassMetadataInfo
24
{
25
    /**
26
     * The ReflectionProperty instances of the mapped class.
27
     *
28
     * @var \ReflectionProperty[]
29
     */
30
    public $reflFields = array();
31
32
    /**
33
     * @var \Doctrine\Instantiator\InstantiatorInterface|null
34
     */
35
    private $instantiator;
36
37
    /**
38
     * Initializes a new ClassMetadata instance that will hold the object-document mapping
39
     * metadata of the class with the given name.
40
     *
41
     * @param string $documentName The name of the document class the new instance is used for.
42
     */
43 1464
    public function __construct($documentName)
44
    {
45 1464
        parent::__construct($documentName);
46 1464
        $this->reflClass = new \ReflectionClass($documentName);
47 1464
        $this->namespace = $this->reflClass->getNamespaceName();
48 1464
        $this->setCollection($this->reflClass->getShortName());
49 1464
        $this->instantiator = new Instantiator();
50 1464
    }
51
52
    /**
53
     * Map a field.
54
     *
55
     * @param array $mapping The mapping information.
56
     * @return void
57
     */
58 1392
    public function mapField(array $mapping)
59
    {
60 1392
        $mapping = parent::mapField($mapping);
61
62 1391
        $reflProp = $this->reflClass->getProperty($mapping['fieldName']);
63 1390
        $reflProp->setAccessible(true);
64 1390
        $this->reflFields[$mapping['fieldName']] = $reflProp;
65 1390
    }
66
67
    /**
68
     * Determines which fields get serialized.
69
     *
70
     * It is only serialized what is necessary for best unserialization performance.
71
     * That means any metadata properties that are not set or empty or simply have
72
     * their default value are NOT serialized.
73
     *
74
     * Parts that are also NOT serialized because they can not be properly unserialized:
75
     *      - reflClass (ReflectionClass)
76
     *      - reflFields (ReflectionProperty array)
77
     *
78
     * @return array The names of all the fields that should be serialized.
79
     */
80 6
    public function __sleep()
81
    {
82
        // This metadata is always serialized/cached.
83
        $serialized = array(
84 6
            'fieldMappings',
85
            'associationMappings',
86
            'identifier',
87
            'name',
88
            'namespace', // TODO: REMOVE
89
            'db',
90
            'collection',
91
            'readPreference',
92
            'readPreferenceTags',
93
            'writeConcern',
94
            'rootDocumentName',
95
            'generatorType',
96
            'generatorOptions',
97
            'idGenerator',
98
            'indexes',
99
            'shardKey',
100
        );
101
102
        // The rest of the metadata is only serialized if necessary.
103 6
        if ($this->changeTrackingPolicy != self::CHANGETRACKING_DEFERRED_IMPLICIT) {
104
            $serialized[] = 'changeTrackingPolicy';
105
        }
106
107 6
        if ($this->customRepositoryClassName) {
108 1
            $serialized[] = 'customRepositoryClassName';
109
        }
110
111 6
        if ($this->inheritanceType != self::INHERITANCE_TYPE_NONE || $this->discriminatorField !== null) {
112 4
            $serialized[] = 'inheritanceType';
113 4
            $serialized[] = 'discriminatorField';
114 4
            $serialized[] = 'discriminatorValue';
115 4
            $serialized[] = 'discriminatorMap';
116 4
            $serialized[] = 'defaultDiscriminatorValue';
117 4
            $serialized[] = 'parentClasses';
118 4
            $serialized[] = 'subClasses';
119
        }
120
121 6
        if ($this->isMappedSuperclass) {
122 1
            $serialized[] = 'isMappedSuperclass';
123
        }
124
125 6
        if ($this->isEmbeddedDocument) {
126 1
            $serialized[] = 'isEmbeddedDocument';
127
        }
128
129 6
        if ($this->isQueryResultDocument) {
130
            $serialized[] = 'isQueryResultDocument';
131
        }
132
133 6
        if ($this->isVersioned) {
134
            $serialized[] = 'isVersioned';
135
            $serialized[] = 'versionField';
136
        }
137
138 6
        if ($this->lifecycleCallbacks) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->lifecycleCallbacks of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
139
            $serialized[] = 'lifecycleCallbacks';
140
        }
141
142 6
        if ($this->collectionCapped) {
143 1
            $serialized[] = 'collectionCapped';
144 1
            $serialized[] = 'collectionSize';
145 1
            $serialized[] = 'collectionMax';
146
        }
147
148 6
        if ($this->isReadOnly) {
149
            $serialized[] = 'isReadOnly';
150
        }
151
152 6
        return $serialized;
153
    }
154
155
    /**
156
     * Restores some state that can not be serialized/unserialized.
157
     *
158
     * @return void
159
     */
160 6
    public function __wakeup()
161
    {
162
        // Restore ReflectionClass and properties
163 6
        $this->reflClass = new \ReflectionClass($this->name);
164 6
        $this->instantiator = $this->instantiator ?: new Instantiator();
165
166 6
        foreach ($this->fieldMappings as $field => $mapping) {
167 3
            if (isset($mapping['declared'])) {
168 1
                $reflField = new \ReflectionProperty($mapping['declared'], $field);
169
            } else {
170 3
                $reflField = $this->reflClass->getProperty($field);
171
            }
172 3
            $reflField->setAccessible(true);
173 3
            $this->reflFields[$field] = $reflField;
174
        }
175 6
    }
176
177
    /**
178
     * Creates a new instance of the mapped class, without invoking the constructor.
179
     *
180
     * @return object
181
     */
182 354
    public function newInstance()
183
    {
184 354
        return $this->instantiator->instantiate($this->name);
185
    }
186
}
187