Completed
Push — master ( abe227...316baf )
by Raffael
13:55 queued 08:01
created

Factory::build()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 0
cts 4
cp 0
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 2
crap 2
1
<?php
2
3
declare(strict_types=1);
4
5
/**
6
 * tubee.io
7
 *
8
 * @copyright   Copryright (c) 2017-2019 gyselroth GmbH (https://gyselroth.com)
9
 * @license     GPL-3.0 https://opensource.org/licenses/GPL-3.0
10
 */
11
12
namespace Tubee\DataObjectRelation;
13
14
use Generator;
15
use MongoDB\BSON\ObjectId;
16
use MongoDB\BSON\ObjectIdInterface;
17
use Tubee\DataObject\DataObjectInterface;
18
use Tubee\DataObjectRelation;
19
use Tubee\Resource\Factory as ResourceFactory;
20
use Tubee\ResourceNamespace\ResourceNamespaceInterface;
21
22
class Factory extends ResourceFactory
23
{
24
    /**
25
     * Collection name.
26
     */
27
    public const COLLECTION_NAME = 'relations';
28
29
    /**
30
     * Has resource.
31
     */
32
    public function has(ResourceNamespaceInterface $namespace, string $name): bool
33
    {
34
        return $this->db->{self::COLLECTION_NAME}->count([
35
            'namespace' => $namespace->getName(),
36
            'name' => $name,
37
        ]) > 0;
38
    }
39
40
    /**
41
     * Get one.
42
     */
43
    public function getOne(ResourceNamespaceInterface $namespace, string $name): DataObjectRelationInterface
44
    {
45
        $resource = $this->db->{self::COLLECTION_NAME}->findOne([
46
            'namespace' => $namespace->getName(),
47
            'name' => $name,
48
        ]);
49
50
        if ($resource === null) {
51
            throw new Exception\NotFound('relation '.$name.' was not found');
52
        }
53
54
        return $this->build($resource);
55
    }
56
57
    /**
58
     * Get one from object.
59
     */
60
    public function getOneFromObject(DataObjectInterface $object, string $name): DataObjectRelationInterface
61
    {
62
        $relation = [
63
            'namespace' => $object->getCollection()->getResourceNamespace()->getName(),
64
            'collection' => $object->getCollection()->getName(),
65
            'object' => $object->getName(),
66
        ];
67
68
        $filter = [
69
            'name' => $name,
70
            'data.relation.namespace' => $relation['namespace'],
71
            'data.relation.collection' => $relation['collection'],
72
            'data.relation.object' => $relation['object'],
73
        ];
74
75
        $resource = $this->db->{self::COLLECTION_NAME}->findOne($filter);
76
77
        if ($resource === null) {
78
            throw new Exception\NotFound('relation '.$name.' was not found');
79
        }
80
81
        $object_1 = array_shift($resource['data']['relation']);
82
        $object_2 = array_shift($resource['data']['relation']);
83
        $related = $object_1;
84
85
        if ($object_1 == $relation) {
86
            $related = $object_2;
87
        }
88
89
        $related = $object->getCollection()->getResourceNamespace()->switch($related['namespace'])->getCollection($related['collection'])->getObject(['name' => $related['object']]);
90
91
        return $this->build($resource, $related);
92
    }
93
94
    /**
95
     * Get all from object.
96
     */
97
    public function getAllFromObject(DataObjectInterface $object, ?array $query = null, ?int $offset = null, ?int $limit = null, ?array $sort = null): Generator
98
    {
99
        $relation = [
100
            'namespace' => $object->getCollection()->getResourceNamespace()->getName(),
101
            'collection' => $object->getCollection()->getName(),
102
            'object' => $object->getName(),
103
        ];
104
105
        $filter = [
106
            'data.relation.namespace' => $relation['namespace'],
107
            'data.relation.collection' => $relation['collection'],
108
            'data.relation.object' => $relation['object'],
109
        ];
110
111
        if (!empty($query)) {
112
            $filter = [
113
                '$and' => [$filter, $query],
114
            ];
115
        }
116
117
        return $this->getAllFrom($this->db->{self::COLLECTION_NAME}, $filter, $offset, $limit, $sort, function (array $resource) use ($object, $relation) {
118
            $object_1 = $resource['data']['relation'][0];
119
            $object_2 = $resource['data']['relation'][1];
120
            $related = $object_1;
121
122
            if ($object_1 == $relation) {
123
                $related = $object_2;
124
            }
125
126
            $related = $object->getCollection()->getResourceNamespace()->switch($related['namespace'])->getCollection($related['collection'])->getObject(['name' => $related['object']]);
127
128
            return $this->build($resource, $related);
129
        });
130
    }
131
132
    /**
133
     * {@inheritdoc}
134
     */
135
    public function getAll(ResourceNamespaceInterface $namespace, ?array $query = null, ?int $offset = null, ?int $limit = null, ?array $sort = null): Generator
136
    {
137
        $filter = [
138
            'namespace' => $namespace->getName(),
139
        ];
140
141
        if (!empty($query)) {
142
            $filter = [
143
                '$and' => [$filter, $query],
144
            ];
145
        }
146
147
        return $this->getAllFrom($this->db->{self::COLLECTION_NAME}, $filter, $offset, $limit, $sort, function (array $resource) {
148
            return $this->build($resource);
149
        });
150
    }
151
152
    /**
153
     * {@inheritdoc}
154
     */
155
    public function createOrUpdate(ResourceNamespaceInterface $namespace, DataObjectInterface $object_1, DataObjectInterface $object_2, array $context = [], bool $simulate = false, ?array $endpoints = null): ObjectIdInterface
0 ignored issues
show
Unused Code introduced by
The parameter $namespace is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $simulate is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
156
    {
157
        $relations = [
158
            [
159
                'data.relation.namespace' => $object_1->getCollection()->getResourceNamespace()->getName(),
160
                'data.relation.collection' => $object_1->getCollection()->getName(),
161
                'data.relation.object' => $object_1->getName(),
162
            ], [
163
                'data.relation.namespace' => $object_2->getCollection()->getResourceNamespace()->getName(),
164
                'data.relation.collection' => $object_2->getCollection()->getName(),
165
                'data.relation.object' => $object_2->getName(),
166
            ],
167
        ];
168
169
        $resource = $relations;
170
        $resource['data.context'] = $context;
171
172
        $exists = $this->db->{self::COLLECTION_NAME}->findOne([
173
            '$and' => $relations,
174
        ]);
175
176
        if ($endpoints !== null) {
177
            $resource['endpoints'] = $endpoints;
178
        }
179
180
        if ($exists !== null) {
181
            $exists = $this->build($exists);
182
            $this->update($exists, ['context' => $context]);
183
184
            return $exists->getId();
185
        }
186
187
        return $this->addTo($this->db->{self::COLLECTION_NAME}, $resource);
188
    }
189
190
    /**
191
     * Add.
192
     */
193
    public function add(ResourceNamespaceInterface $namespace, array $resource): ObjectIdInterface
194
    {
195
        $resource = Validator::validate($resource);
196
197
        $object['_id'] = new ObjectId();
0 ignored issues
show
Coding Style Comprehensibility introduced by
$object was never initialized. Although not strictly required by PHP, it is generally a good practice to add $object = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
198
        if (!isset($object['name'])) {
199
            $object['name'] = (string) $object['_id'];
200
        }
201
202
        if ($this->has($namespace, $resource['name'])) {
203
            throw new Exception\NotUnique('relation '.$resource['name'].' does already exists');
204
        }
205
206
        $resource['namespace'] = $namespace->getName();
207
208
        return $this->addTo($this->db->{self::COLLECTION_NAME}, $resource);
209
    }
210
211
    /**
212
     * {@inheritdoc}
213
     */
214
    public function update(DataObjectRelationInterface $resource, array $data): bool
215
    {
216
        $data['name'] = $resource->getName();
217
        $data = Validator::validate($data);
218
219
        return $this->updateIn($this->db->{self::COLLECTION_NAME}, $resource, $data);
220
    }
221
222
    /**
223
     * {@inheritdoc}
224
     */
225
    public function deleteOne(DataObjectRelationInterface $relation, bool $simulate = false): bool
0 ignored issues
show
Unused Code introduced by
The parameter $simulate is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
226
    {
227
        $this->logger->info('delete object relation ['.$relation->getId()().'] from ['.self::COLLECTION_NAME.']', [
228
            'category' => get_class($this),
229
        ]);
230
231
        $this->db->{self::COLLECTION_NAME}->deleteOne(['_id' => $relation->getId()]);
232
233
        return true;
234
    }
235
236
    /**
237
     * Change stream.
238
     */
239
    public function watch(ResourceNamespaceInterface $namespace, ?ObjectIdInterface $after = null, bool $existing = true, ?array $query = null, ?int $offset = null, ?int $limit = null, ?array $sort = null): Generator
0 ignored issues
show
Unused Code introduced by
The parameter $namespace is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
240
    {
241
        return $this->watchFrom($this->db->{self::COLLECTION_NAME}, $after, $existing, $query, function (array $resource) {
242
            return $this->build($resource);
243
        }, $offset, $limit, $sort);
244
    }
245
246
    /**
247
     * Build.
248
     */
249
    public function build(array $resource, ?DataObjectInterface $object = null): DataObjectRelationInterface
250
    {
251
        return $this->initResource(new DataObjectRelation($resource, $object));
252
    }
253
}
254