OrmAnnotation::getAnnotatedPrimaryKeyProperty()   A
last analyzed

Complexity

Conditions 4
Paths 7

Size

Total Lines 17
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 4.1755

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 17
ccs 7
cts 9
cp 0.7778
rs 9.2
cc 4
eloc 10
nc 7
nop 1
crap 4.1755
1
<?php
2
namespace Nkey\Caribu\Orm;
3
4
/**
5
 * Annotation provider for Caribu Orm
6
 *
7
 * This class is part of Caribu package
8
 *
9
 * @author Maik Greubel <[email protected]>
10
 */
11
trait OrmAnnotation
12
{
13
    use OrmDataTypeConverter;
14
15
    /**
16
     * Retrieve the annotated table name
17
     *
18
     * @param string $class
19
     *            The name of class
20
     * @param string $fallback
21
     *            As fallback if nothing was found
22
     *            
23
     * @return string The name of table
24
     *        
25
     * @throws OrmException
26
     */
27 32
    private static function getAnnotatedTableName(string $class, string $fallback): string
28
    {
29
        try {
30 32
            $rfClass = new \ReflectionClass($class);
31
            
32 32
            $docComments = $rfClass->getDocComment();
33
            
34 32
            $matches = array();
35 32
            if (preg_match('/@table (\w+)/', $docComments, $matches)) {
36 26
                $fallback = $matches[1];
37
            }
38
            
39 32
            return $fallback;
40
        } catch (\ReflectionException $exception) {
41
            throw OrmException::fromPrevious($exception);
42
        }
43
    }
44
45
    /**
46
     * Get the annotated primary key property name
47
     *
48
     * The property is annotated with the @id annotation
49
     *
50
     * @param string $class
51
     *            The name of class to retrieve the primary key property
52
     *            
53
     * @return string The name of property which represents the primary key
54
     *        
55
     * @throws OrmException
56
     */
57 10
    private static function getAnnotatedPrimaryKeyProperty(string $class): string
58
    {
59
        try {
60 10
            $propertyName = "";
61
            
62 10
            foreach (self::getClassProperties($class) as $property) {
63 10
                if (self::isIdAnnotated($property->getDocComment())) {
64 7
                    $propertyName = $property->getName();
65 10
                    break;
66
                }
67
            }
68
            
69 10
            return $propertyName;
70
        } catch (\ReflectionException $exception) {
71
            throw OrmException::fromPrevious($exception);
72
        }
73
    }
74
75
    /**
76
     * Get the annotated primary key
77
     *
78
     * The property is annotated with the @id annotation
79
     * The propery may have a @column annotation to modify the database column name
80
     *
81
     * @param string $class
82
     *            The name of class to retrieve the primary key column of
83
     *            
84
     * @return string|null The name of primary key column
85
     *        
86
     * @throws OrmException
87
     */
88 20
    private static function getAnnotatedPrimaryKeyColumn(string $class): string
89
    {
90
        try {
91 20
            $columnName = "";
92
            
93 20
            foreach (self::getClassProperties($class) as $property) {
94 20
                $docComment = $property->getDocComment();
95 20
                if (self::isIdAnnotated($docComment) && "" === ($columnName = self::getAnnotatedColumn($docComment))) {
96
                    $columnName = $property->getName();
97 20
                    break;
98
                }
99
            }
100
            
101 20
            return $columnName;
102
        } catch (\ReflectionException $exception) {
103
            throw OrmException::fromPrevious($exception);
104
        }
105
    }
106
107
    /**
108
     * Get the property type via annotation
109
     *
110
     * @param string $class
111
     *            The name of class to retrieve a particular property type
112
     * @param string $propertyName
113
     *            The name of property to retrieve the type of
114
     * @param string $namespace
115
     *            The namespace
116
     *            
117
     * @return string|null The property type either as primitive type or full qualified class
118
     */
119 26
    private static function getAnnotatedPropertyType(string $class, string $propertyName, string $namespace): string
120
    {
121 26
        $type = "";
122
        
123 26
        $rfClass = new \ReflectionClass(self::fullQualifiedName($namespace, $class));
124
        
125 26
        if ($rfClass->hasProperty($propertyName)) {
126 26
            $property = $rfClass->getProperty($propertyName);
127 26
            $type = self::getAnnotatedType($property->getDocComment(), $rfClass->getNamespaceName());
128
        }
129
        
130 26
        return $type;
131
    }
132
133
    /**
134
     * Get the value from property
135
     *
136
     * @param object $from
137
     *            The source object
138
     * @param string $toClass
139
     *            The type of destination class
140
     * @param \ReflectionProperty $property
141
     *            The property to get value of
142
     * @param string $namespace
143
     *            The namespace of destination class
144
     *            
145
     * @return array The type and value from property
146
     */
147 26
    private static function getAnnotatedPropertyValue(\stdClass $from, string $toClass, \ReflectionProperty $property, string $namespace): array
148
    
149
    {
150 26
        $value = $property->getValue($from);
151
        
152 26
        $type = self::getAnnotatedPropertyType($toClass, $property->getName(), $namespace);
153
        
154 26
        if ("" === $type || self::isPrimitive($type) || ! class_exists($type)) {
155
            return array(
156 26
                $type,
157 26
                $value
158
            );
159
        }
160
        
161 14
        $rfPropertyType = new \ReflectionClass($type);
162
        
163 14
        if ($rfPropertyType->getParentClass() && strcmp($rfPropertyType->getParentClass()->name, 'Nkey\Caribu\Model\AbstractModel') == 0) {
164 5
            $getById = new \ReflectionMethod($type, "get");
165 5
            $value = $getById->invoke(null, $value);
166
            
167
            return array(
168 5
                $type,
169 5
                $value
170
            );
171
        }
172
        
173 14
        $value = $rfPropertyType->isInternal() ? self::convertType($type, $value) : $rfPropertyType->newInstance($value);
174
        
175
        return array(
176 14
            $type,
177 14
            $value
178
        );
179
    }
180
181
    /**
182
     * Retrieve list of columns and its corresponding pairs
183
     *
184
     * @param string $class
185
     *            The name of class to retrieve all column-value pairs of
186
     * @param \Nkey\Caribu\Model\AbstractModel $object
187
     *            The entity to get the column-value pairs of
188
     *            
189
     * @return array List of column => value pairs
190
     *        
191
     * @throws OrmException
192
     */
193 12
    private static function getAnnotatedColumnValuePairs(string $class, \Nkey\Caribu\Model\AbstractModel $object): array
194
    {
195 12
        $pairs = array();
196
        try {
197 12
            $rfClass = new \ReflectionClass($class);
198
            
199 12
            foreach ($rfClass->getProperties() as $property) {
200 12
                $docComments = $property->getDocComment();
201
                
202
                // mapped by entries have no corresponding table column, so we skip it here
203 12
                if (preg_match('/@mappedBy/i', $docComments)) {
204 2
                    continue;
205
                }
206 12
                if ("" === ($column = self::getAnnotatedColumn($docComments))) {
207 10
                    $column = $property->getName();
208
                }
209
                
210 12
                $rfMethod = new \ReflectionMethod($class, sprintf("get%s", ucfirst($property->getName())));
211
                
212 12
                $value = $rfMethod->invoke($object);
213 12
                if (null != $value) {
214 12
                    $pairs[$column] = $value;
215
                }
216
            }
217
        } catch (\ReflectionException $exception) {
218
            throw OrmException::fromPrevious($exception);
219
        }
220
        
221 12
        return $pairs;
222
    }
223
224
    /**
225
     * Retrieve the primary key name and value using annotation
226
     *
227
     * @param string $class
228
     *            The name of class to retrieve the primary key name and value
229
     * @param \Nkey\Caribu\Model\AbstractModel $object
230
     *            The entity to retrieve the pimary key value
231
     * @param bool $onlyValue
232
     *            Whether to retrieve only the value instead of name and value
233
     *            
234
     * @return array The "name" => "value" of primary key or only the value (depending on $onlyValue)
235
     *        
236
     * @throws OrmException
237
     */
238 16
    private static function getAnnotatedPrimaryKey(string $class, \Nkey\Caribu\Model\AbstractModel $object, bool $onlyValue)
239
    {
240
        try {
241 16
            $rfClass = new \ReflectionClass($class);
242
            
243 16
            foreach ($rfClass->getProperties() as $property) {
244 16
                $docComment = $property->getDocComment();
245
                
246 16
                if (! self::isIdAnnotated($docComment)) {
247 4
                    continue;
248
                }
249
                
250 12
                $rfMethod = new \ReflectionMethod($class, sprintf("get%s", ucfirst($property->getName())));
251
                
252 12
                if ("" === ($columnName = self::getAnnotatedColumn($docComment))) {
253 1
                    $columnName = $property->getName();
254
                }
255
                
256 12
                $primaryKey = $rfMethod->invoke($object);
257
                
258 12
                if (! $onlyValue) {
259
                    $primaryKey = array(
260 12
                        $columnName => $primaryKey
261
                    );
262
                }
263 12
                return $primaryKey;
264
            }
265 4
            return null;
266
        } catch (\ReflectionException $exception) {
267
            throw OrmException::fromPrevious($exception);
268
        }
269
    }
270
271
    /**
272
     * Get the annotated type
273
     *
274
     * @param string $comment
275
     *            The document comment string which may contain the @var annotation
276
     * @param string $namespace
277
     *            Optional namespace where class is part of
278
     *            
279
     * @return string The parsed type
280
     *        
281
     * @throws OrmException
282
     */
283 31
    private static function getAnnotatedType(string $comment, string $namespace = null): string
284
    {
285 31
        $matches = array();
286 31
        if (! preg_match('/@var ([\w\\\\]+)/', $comment, $matches)) {
287 5
            return "";
288
        }
289
        
290 27
        $type = $matches[1];
291
        
292 27
        if (self::isPrimitive($type)) {
293 27
            return $type;
294
        }
295
        
296 20
        $type = self::fullQualifiedName($namespace, $type);
297
        
298 20
        if (! class_exists($type)) {
299 1
            throw new OrmException("Annotated type {type} could not be found nor loaded", array(
300 1
                'type' => $matches[1]
301
            ));
302
        }
303
        
304 19
        return $type;
305
    }
306
307
    /**
308
     * Get the annotated column name
309
     *
310
     * @param string $class
311
     *            The name of class to retrieve te annotated column name
312
     * @param string $property
313
     *            The property which is annotated by column name
314
     *            
315
     * @return string The column name
316
     */
317 1
    private static function getAnnotatedColumnFromProperty(string $class, string $property): string
318
    {
319 1
        $rfProperty = new \ReflectionProperty($class, $property);
320 1
        return self::getAnnotatedColumn($rfProperty->getDocComment());
321
    }
322
323
    /**
324
     * Get the annotated column name from document comment string
325
     *
326
     * @param string $comment
327
     *            The document comment which may contain the @column annotation
328
     *            
329
     * @return string|null The parsed column name
330
     */
331 30
    private static function getAnnotatedColumn(string $comment): string
332
    {
333 30
        $columnName = "";
334
        
335 30
        $matches = array();
336 30
        if (preg_match("/@column (\w+)/", $comment, $matches)) {
337 21
            $columnName = $matches[1];
338
        }
339 30
        return $columnName;
340
    }
341
342
    /**
343
     * Check whether property is annotated using @id
344
     *
345
     * @param string $comment
346
     *            The document comment which may contain the @id annotation
347
     *            
348
     * @return bool true in case of it is annotated, false otherwise
349
     */
350 22
    private static function isIdAnnotated(string $comment): bool
351
    {
352 22
        return preg_match('/@id/', $comment) > 0 ? true : false;
353
    }
354
355
    /**
356
     * Check whether property is annotated using @cascade
357
     *
358
     * @param string $comment
359
     *            The document comment which may contain the @cascade annotation
360
     *            
361
     * @return bool true in case of it is annotated, false otherwise
362
     */
363 13
    private static function isCascadeAnnotated(string $comment): bool
364
    {
365 13
        return preg_match('/@cascade/', $comment) > 0 ? true : false;
366
    }
367
368
    /**
369
     * Get the mappedBy parameters from documentation comment
370
     *
371
     * @param string $comment
372
     *            The documentation comment to parse
373
     *            
374
     * @return string The parsed parameters or null
375
     */
376 22
    private static function getAnnotatedMappedByParameters(string $comment): string
377
    {
378 22
        $parameters = "";
379
        
380 22
        $matches = array();
381 22
        if (preg_match('/@mappedBy\(([^\)].+)\)/', $comment, $matches)) {
382 5
            $parameters = $matches[1];
383
        }
384 22
        return $parameters;
385
    }
386
387
    /**
388
     * Checks whether an entity has eager fetch type
389
     *
390
     * @param string $class
391
     *            Name of class of entity
392
     *            
393
     * @return bool true if fetch type is eager, false otherwise
394
     */
395 26
    private static function isEager(string $class): bool
396
    {
397 26
        $rf = new \ReflectionClass($class);
398 26
        return preg_match('/@eager/', $rf->getDocComment()) > 0 ? true : false;
399
    }
400
}
401