Completed
Push — master ( 8c953e...7fbcf6 )
by Thomas
37s
created

Relation::getForeignKey()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 16
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 3

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 16
ccs 8
cts 8
cp 1
rs 9.4285
cc 3
eloc 8
nc 3
nop 2
crap 3
1
<?php
2
3
namespace ORM;
4
5
use ORM\Exceptions\IncompletePrimaryKey;
6
use ORM\Exceptions\InvalidConfiguration;
7
use ORM\Exceptions\InvalidRelation;
8
use ORM\Relation\ManyToMany;
9
use ORM\Relation\OneToMany;
10
use ORM\Relation\OneToOne;
11
use ORM\Relation\Owner;
12
13
abstract class Relation
14
{
15
    const CARDINALITY_ONE          = 'one';
16
    const CARDINALITY_MANY         = 'many';
17
18
    /** The name of the relation for error messages
19
     * @var string */
20
    protected $name;
21
22
    /** The class that is related
23
     * @var string */
24
    protected $class;
25
26
    /** The name of the relation in the related class
27
     * @var string */
28
    protected $opponent;
29
30
    /** Reference definition as key value pairs
31
     * @var array */
32
    protected $reference;
33
34
    /**
35
     * Factory for relation definition object
36
     *
37
     * @param string $name
38
     * @param array $relDef
39
     * @return Relation
40
     */
41 15
    public static function createRelation($name, $relDef)
42
    {
43 15
        if (isset($relDef[0])) {
44 12
            $relDef = self::convertShort($name, $relDef);
45
        }
46
47 14
        if (isset($relDef[Entity::OPT_RELATION_REFERENCE]) && !isset($relDef[Entity::OPT_RELATION_TABLE])) {
48 5
            return new Owner(
49
                $name,
50 5
                $relDef[Entity::OPT_RELATION_CLASS],
51 5
                $relDef[Entity::OPT_RELATION_REFERENCE]
52
            );
53 9
        } elseif (isset($relDef[Entity::OPT_RELATION_TABLE])) {
54 2
            return new ManyToMany(
55
                $name,
56 2
                $relDef[Entity::OPT_RELATION_CLASS],
57 2
                $relDef[Entity::OPT_RELATION_REFERENCE],
58 2
                $relDef[Entity::OPT_RELATION_OPPONENT],
59 2
                $relDef[Entity::OPT_RELATION_TABLE]
60
            );
61 7
        } elseif (!isset($relDef[Entity::OPT_RELATION_CARDINALITY]) ||
62 7
                  $relDef[Entity::OPT_RELATION_CARDINALITY] === self::CARDINALITY_MANY
63
        ) {
64 4
            return new OneToMany(
65
                $name,
66 4
                $relDef[Entity::OPT_RELATION_CLASS],
67 4
                $relDef[Entity::OPT_RELATION_OPPONENT]
68
            );
69
        } else {
70 4
            return new OneToOne(
71
                $name,
72 4
                $relDef[Entity::OPT_RELATION_CLASS],
73 4
                $relDef[Entity::OPT_RELATION_OPPONENT]
74
            );
75
        }
76
    }
77
78
    /**
79
     * Converts short form to assoc form
80
     *
81
     * @param string $name
82
     * @param array $relDef
83
     * @return array
84
     * @throws InvalidConfiguration
85
     */
86 12
    protected static function convertShort($name, $relDef)
87
    {
88
        // convert the short form
89 12
        $length = count($relDef);
90
91 12
        if ($length === 2 && gettype($relDef[1]) === 'array') {
92
            // owner of one-to-many or one-to-one
93
            return [
94 3
                Entity::OPT_RELATION_CARDINALITY => self::CARDINALITY_ONE,
95 3
                Entity::OPT_RELATION_CLASS       => $relDef[0],
96 3
                Entity::OPT_RELATION_REFERENCE   => $relDef[1],
97
            ];
98 9
        } elseif ($length === 3 && $relDef[0] === self::CARDINALITY_ONE) {
99
            // non-owner of one-to-one
100
            return [
101 4
                Entity::OPT_RELATION_CARDINALITY => self::CARDINALITY_ONE,
102 4
                Entity::OPT_RELATION_CLASS       => $relDef[1],
103 4
                Entity::OPT_RELATION_OPPONENT    => $relDef[2],
104
            ];
105 6
        } elseif ($length === 2) {
106
            // non-owner of one-to-many
107
            return [
108 3
                Entity::OPT_RELATION_CARDINALITY => self::CARDINALITY_MANY,
109 3
                Entity::OPT_RELATION_CLASS       => $relDef[0],
110 3
                Entity::OPT_RELATION_OPPONENT    => $relDef[1],
111
            ];
112 3
        } elseif ($length === 4 && gettype($relDef[1]) === 'array') {
113
            // many-to-many
114
            return [
115 2
                Entity::OPT_RELATION_CARDINALITY => self::CARDINALITY_MANY,
116 2
                Entity::OPT_RELATION_CLASS       => $relDef[0],
117 2
                Entity::OPT_RELATION_REFERENCE   => $relDef[1],
118 2
                Entity::OPT_RELATION_OPPONENT    => $relDef[2],
119 2
                Entity::OPT_RELATION_TABLE       => $relDef[3],
120
            ];
121
        } else {
122 1
            throw new InvalidConfiguration('Invalid short form for relation ' . $name);
123
        }
124
    }
125
126
    /**
127
     * @return string
128
     */
129 8
    public function getClass()
130
    {
131 8
        return $this->class;
132
    }
133
134
    /**
135
     * @return array
136
     */
137 34
    public function getReference()
138
    {
139 34
        return $this->reference;
140
    }
141
142
    /**
143
     * @return Relation
144
     */
145 36
    public function getOpponent()
146
    {
147
        // @todo seems we need a test for it
148
//        if (!$this->opponent) {
149
//            return null;
150
//        }
151
152 36
        return call_user_func([$this->class, 'getRelation'], $this->opponent);
153
    }
154
155
    /**
156
     * Fetch the relation
157
     *
158
     * Runs fetch on the EntityManager and returns its result.
159
     *
160
     * @param Entity        $me
161
     * @param EntityManager $entityManager
162
     * @return mixed
163
     */
164
    abstract public function fetch(Entity $me, EntityManager $entityManager);
165
166
    /**
167
     * Fetch all from the relation
168
     *
169
     * Runs fetch and returns EntityFetcher::all() if a Fetcher is returned.
170
     *
171
     * @param Entity        $me
172
     * @param EntityManager $entityManager
173
     * @return Entity[]|Entity
174
     */
175 3
    public function fetchAll(Entity $me, EntityManager $entityManager)
176
    {
177 3
        $fetcher = $this->fetch($me, $entityManager);
178
179 3
        if ($fetcher instanceof EntityFetcher) {
180 1
            return $fetcher->all();
181
        }
182
183 2
        return $fetcher;
184
    }
185
186
    /**
187
     * Get the foreign key for the given reference
188
     *
189
     * @param Entity $me
190
     * @param array  $reference
191
     * @return array
192
     * @throws IncompletePrimaryKey
193
     */
194 10
    protected function getForeignKey(Entity $me, $reference)
195
    {
196 10
        $foreignKey = [];
197
198 10
        foreach ($reference as $var => $fkCol) {
199 10
            $value = $me->__get($var);
200
201 10
            if ($value === null) {
202 2
                throw new IncompletePrimaryKey('Key incomplete for join');
203
            }
204
205 8
            $foreignKey[$fkCol] = $value;
206
        }
207
208 8
        return $foreignKey;
209
    }
210
211
    /**
212
     * Set the relation to $entity
213
     *
214
     * @param Entity      $me
215
     * @param Entity|null $entity
216
     * @throws InvalidRelation
217
     */
218 1
    public function setRelated(Entity $me, Entity $entity = null)
219
    {
220 1
        throw new InvalidRelation('This is not the owner of the relation');
221
    }
222
223
    /**
224
     * Add $entities to association table
225
     *
226
     * @param Entity        $me
227
     * @param Entity[]      $entities
228
     * @param EntityManager $entityManager
229
     * @throws InvalidRelation
230
     */
231 1
    public function addRelated(Entity $me, array $entities, EntityManager $entityManager)
232
    {
233 1
        throw new InvalidRelation('This is not a many-to-many relation');
234
    }
235
236
    /**
237
     * Delete $entities from association table
238
     *
239
     * @param Entity        $me
240
     * @param Entity[]      $entities
241
     * @param EntityManager $entityManager
242
     * @throws InvalidRelation
243
     */
244 1
    public function deleteRelated(Entity $me, array $entities, EntityManager $entityManager)
245
    {
246 1
        throw new InvalidRelation('This is not a many-to-many relation');
247
    }
248
249
    /**
250
     * Join this relation in $fetcher
251
     *
252
     * @param EntityFetcher $fetcher
253
     * @param string        $join
254
     * @param string        $alias
255
     * @return mixed
256
     */
257
    abstract public function addJoin(EntityFetcher $fetcher, $join, $alias);
258
}
259