Completed
Push — master ( fd62a8...5cbc9e )
by Filipe
04:02
created

EntityDescriptor::determineTableName()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 9
ccs 7
cts 7
cp 1
rs 9.6666
cc 2
eloc 6
nc 2
nop 0
crap 2
1
<?php
2
3
/**
4
 * This file is part of slick/orm package
5
 *
6
 * For the full copyright and license information, please view the LICENSE
7
 * file that was distributed with this source code.
8
 */
9
10
namespace Slick\Orm\Descriptor;
11
12
use Slick\Common\Inspector;
13
use Slick\Common\Utils\Text;
14
use Slick\Orm\Annotations\Column;
15
use Slick\Orm\Descriptor\Field\FieldDescriptor;
16
use Slick\Orm\Descriptor\Field\FieldsCollection;
17
use Slick\Orm\Mapper\Relation\BelongsTo;
18
19
/**
20
 * Entity Descriptor
21
 *
22
 * @package Slick\Orm\Descriptor
23
 * @author  Filipe Silva <[email protected]>
24
 */
25
class EntityDescriptor implements EntityDescriptorInterface
26
{
27
28
    /**
29
     * @var string Entity class name
30
     */
31
    protected $entity;
32
33
    /**
34
     * @var string
35
     */
36
    protected $tableName;
37
38
    /**
39
     * @var Inspector
40
     */
41
    protected $inspector;
42
43
    /**
44
     * @var FieldsCollection
45
     */
46
    protected $fields;
47
48
    /**
49
     * @var FieldDescriptor
50
     */
51
    protected $primaryKey;
52
53
    /**
54
     * @var string
55
     */
56
    protected $adapterAlias = '__undefined__';
57
58
    /**
59
     * @var RelationsMap
60
     */
61
    protected $relationsMap;
62
63
    protected static $knownRelations = [
64
        'belongsTo' => BelongsTo::class
65
    ];
66
67
    /**
68
     * EntityDescriptor need an entity FQ class name.
69
     *
70
     * @param string $entity
71
     */
72 16
    public function __construct($entity)
73 16
    {
74 12
        $this->entity = is_object($entity)
75 12
            ? get_class($entity)
76 2
            : $entity;
77 12
        $this->inspector = Inspector::forClass($entity);
78 12
        $this->createEntityRelationsMap();
79 12
    }
80
81
    /**
82
     * Gets entity table name
83
     *
84
     * @return string
85
     */
86 10
    public function getTableName()
87
    {
88 10
        if (null == $this->tableName) {
89 4
            $this->tableName = $this->determineTableName();
90 4
        }
91 10
        return $this->tableName;
92
    }
93
94
    /**
95
     * Returns entity fields
96
     *
97
     * @return FieldsCollection|FieldDescriptor[]
98
     */
99 12
    public function getFields()
100
    {
101 12
        if (null == $this->fields) {
102 6
            $properties = $this->inspector->getClassProperties();
103 6
            $this->fields = new FieldsCollection();
104 6
            foreach ($properties as $property) {
105 6
                $this->addDescriptor($property);
106 6
            }
107 6
        }
108 12
        return $this->fields;
109
    }
110
111
    /**
112
     * Returns the primary key field
113
     *
114
     * @return FieldDescriptor|null
115
     */
116 8
    public function getPrimaryKey()
117
    {
118 8
        if (null == $this->primaryKey) {
119 4
            foreach ($this->getFields() as $field) {
120 4
                if ($field->isPrimaryKey()) {
121 4
                    $this->primaryKey = $field;
122 4
                    break;
123
                }
124 4
            }
125 4
        }
126 8
        return $this->primaryKey;
127
    }
128
129
    /**
130
     * Determines the table name for current entity
131
     *
132
     * If there is an annotation @table present it will be used
133
     * otherwise the name will be parsed by convention using the
134
     * EntityDescriptor::parseTableName() method.
135
     *
136
     * @return string
137
     */
138 4
    private function determineTableName()
139
    {
140 4
        $annotations = $this->inspector->getClassAnnotations();
141 4
        $name = self::parseTableName($this->entity);
142 4
        if ($annotations->hasAnnotation('@table')) {
143 4
            $name = $annotations->getAnnotation('@table')->getValue();
144 4
        }
145 4
        return $name;
146
    }
147
148
    /**
149
     * Creates the descriptor if provided property has annotation @column
150
     *
151
     * @param $property
152
     *
153
     * @return self|$this|EntityDescriptor
154
     */
155 6
    private function addDescriptor($property)
156
    {
157 6
        $annotations = $this->inspector
158 6
            ->getPropertyAnnotations($property);
159 6
        if ($annotations->hasAnnotation('column')) {
160
            /** @var Column $annotation */
161 6
            $annotation = $annotations->getAnnotation('column');
162 6
            $descriptor = new FieldDescriptor($annotation->getParameters());
163 6
            $this->fields[] = $descriptor->setName($property);
164 6
        }
165 6
        return $this;
166
    }
167
168
    /**
169
     * Parses the table name from the class name
170
     *
171
     * @param string $className
172
     *
173
     * @return string
174
     */
175 10
    public static function parseTableName($className)
176
    {
177 10
        $parts = explode('\\', $className);
178 10
        $name = end($parts);
179 10
        $tableName = null;
180
181 10
        $words = explode('#', Text::camelCaseToSeparator($name, "#"));
182 10
        $last = array_pop($words);
183 10
        $last = Text::plural(strtolower($last));
184 10
        array_push($words, $last);
185 10
        foreach ($words as $word) {
186 10
            $tableName .= ucfirst($word);
187 10
        }
188 10
        return lcfirst($tableName);
189
    }
190
191
    /**
192
     * Returns the adapter alias name to use with this entity
193
     *
194
     * @return string
195
     */
196 6
    public function getAdapterAlias()
197
    {
198 6
        if ('__undefined__' == $this->adapterAlias) {
199 4
            $this->adapterAlias = null;
200 4
            $annotations = $this->inspector->getClassAnnotations();
201 4
            if ($annotations->hasAnnotation('@adapter')) {
202 4
                $this->adapterAlias = $annotations
203 4
                    ->getAnnotation('@adapter')
204 4
                    ->getValue();
205 4
            }
206 4
        }
207 6
        return $this->adapterAlias;
208
    }
209
210
    /**
211
     * Gets entity class name
212
     *
213
     * @return string
214
     */
215 6
    public function className()
216
    {
217 6
        return $this->entity;
218
    }
219
220 12
    private function createEntityRelationsMap()
221
    {
222 12
        $properties = $this->inspector->getClassProperties();
223 12
        $this->relationsMap = new RelationsMap();
224 12
        foreach ($properties as $property) {
225 12
            $this->checkRelation($property);
226 12
        }
227 12
    }
228
229 12
    private function checkRelation($property)
230
    {
231 12
        $annotations = $this->inspector->getPropertyAnnotations($property);
232 12
        foreach (static::$knownRelations as $knownRelation => $class) {
233 12
            if ($annotations->hasAnnotation($knownRelation)) {
234
                $relation = new $class(
235
                    [
236
                        'property' => $property,
237
                        'entityDescriptor' => $this,
238
                        'annotation' => $annotations->getAnnotation($knownRelation)
239
                    ]
240
                );
241
                $this->relationsMap->set($property, $relation);
242
                break;
243
            }
244 12
        }
245
    }
246
}