Completed
Branch feature-relations (b11bfd)
by Thomas
02:28
created

Relation::setRelated()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

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