Passed
Push — master ( 57b2d8...55b64c )
by Raffael
22:23 queued 13s
created

Factory::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 5
ccs 0
cts 5
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
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 MongoDB\Database;
18
use Tubee\DataObject\DataObjectInterface;
19
use Tubee\DataObjectRelation;
20
use Tubee\Resource\Factory as ResourceFactory;
21
use Tubee\ResourceNamespace\ResourceNamespaceInterface;
22
23
class Factory
24
{
25
    /**
26
     * Collection name.
27
     */
28
    public const COLLECTION_NAME = 'relations';
29
30
    /**
31
     * Database.
32
     *
33
     * @var Database
34
     */
35
    protected $db;
36
37
    /**
38
     * Resource factory.
39
     *
40
     * @var ResourceFactory
41
     */
42
    protected $resource_factory;
43
44
    /**
45
     * Initialize.
46
     */
47
    public function __construct(Database $db, ResourceFactory $resource_factory)
48
    {
49
        $this->db = $db;
50
        $this->resource_factory = $resource_factory;
51
    }
52
53
    /**
54
     * Has resource.
55
     */
56
    public function has(ResourceNamespaceInterface $namespace, string $name): bool
57
    {
58
        return $this->db->{self::COLLECTION_NAME}->count([
59
            'namespace' => $namespace->getName(),
60
            'name' => $name,
61
        ]) > 0;
62
    }
63
64
    /**
65
     * Get one.
66
     */
67
    public function getOne(ResourceNamespaceInterface $namespace, string $name): DataObjectRelationInterface
68
    {
69
        $resource = $this->db->{self::COLLECTION_NAME}->findOne([
70
            'namespace' => $namespace->getName(),
71
            'name' => $name,
72
        ], [
73
            'projection' => ['history' => 0],
74
        ]);
75
76
        if ($resource === null) {
77
            throw new Exception\NotFound('relation '.$name.' was not found');
78
        }
79
80
        return $this->build($resource);
81
    }
82
83
    /**
84
     * Get one from object.
85
     */
86
    public function getOneFromObject(DataObjectInterface $object, string $name): DataObjectRelationInterface
87
    {
88
        $relation = [
89
            'namespace' => $object->getCollection()->getResourceNamespace()->getName(),
90
            'collection' => $object->getCollection()->getName(),
91
            'object' => $object->getName(),
92
        ];
93
94
        $filter = [
95
            'name' => $name,
96
            'data.relation.namespace' => $relation['namespace'],
97
            'data.relation.collection' => $relation['collection'],
98
            'data.relation.object' => $relation['object'],
99
        ];
100
101
        $resource = $this->db->{self::COLLECTION_NAME}->findOne($filter);
102
103
        if ($resource === null) {
104
            throw new Exception\NotFound('relation '.$name.' was not found');
105
        }
106
107
        $object_1 = array_shift($resource['data']['relation']);
108
        $object_2 = array_shift($resource['data']['relation']);
109
        $related = $object_1;
110
111
        if ($object_1 == $relation) {
112
            $related = $object_2;
113
        }
114
115
        $related = $object->getCollection()->getResourceNamespace()->switch($related['namespace'])->getCollection($related['collection'])->getObject(['name' => $related['object']]);
116
117
        return $this->build($resource, $related);
118
    }
119
120
    /**
121
     * Get all from object.
122
     */
123
    public function getAllFromObject(DataObjectInterface $object, ?array $query = null, ?int $offset = null, ?int $limit = null, ?array $sort = null): Generator
124
    {
125
        $relation = [
126
            'namespace' => $object->getCollection()->getResourceNamespace()->getName(),
127
            'collection' => $object->getCollection()->getName(),
128
            'object' => $object->getName(),
129
        ];
130
131
        $filter = [
132
            'data.relation.namespace' => $relation['namespace'],
133
            'data.relation.collection' => $relation['collection'],
134
            'data.relation.object' => $relation['object'],
135
        ];
136
137
        if (!empty($query)) {
138
            $filter = [
139
                '$and' => [$filter, $query],
140
            ];
141
        }
142
143
        $that = $this;
144
145
        return $this->resource_factory->getAllFrom($this->db->{self::COLLECTION_NAME}, $filter, $offset, $limit, $sort, function (array $resource) use ($object, $relation, $that) {
146
            $object_1 = $resource['data']['relation'][0];
147
            $object_2 = $resource['data']['relation'][1];
148
            $related = $object_1;
149
150
            if ($object_1 == $relation) {
151
                $related = $object_2;
152
            }
153
154
            $related = $object->getCollection()->getResourceNamespace()->switch($related['namespace'])->getCollection($related['collection'])->getObject(['name' => $related['object']]);
155
156
            return $that->build($resource, $related);
157
        });
158
    }
159
160
    public function getAll(ResourceNamespaceInterface $namespace, ?array $query = null, ?int $offset = null, ?int $limit = null, ?array $sort = null): Generator
161
    {
162
        $filter = [
163
            'namespace' => $namespace->getName(),
164
        ];
165
166
        if (!empty($query)) {
167
            $filter = [
168
                '$and' => [$filter, $query],
169
            ];
170
        }
171
172
        $that = $this;
173
174
        return $this->resource_factory->getAllFrom($this->db->{self::COLLECTION_NAME}, $filter, $offset, $limit, $sort, function (array $resource) use ($that) {
175
            return $that->build($resource);
176
        });
177
    }
178
179
    public function deleteFromObject(DataObjectInterface $object_1, DataObjectInterface $object_2, 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...
180
    {
181
        $relations = [
182
            [
183
                'data.relation.namespace' => $object_1->getCollection()->getResourceNamespace()->getName(),
184
                'data.relation.collection' => $object_1->getCollection()->getName(),
185
                'data.relation.object' => $object_1->getName(),
186
            ], [
187
                'data.relation.namespace' => $object_2->getCollection()->getResourceNamespace()->getName(),
188
                'data.relation.collection' => $object_2->getCollection()->getName(),
189
                'data.relation.object' => $object_2->getName(),
190
            ],
191
        ];
192
193
        $this->db->{self::COLLECTION_NAME}->remove([
194
            '$and' => $relations,
195
        ]);
196
197
        return true;
198
    }
199
200
    public function createOrUpdate(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 $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...
201
    {
202
        $relations = [
203
            [
204
                'data.relation.namespace' => $object_1->getCollection()->getResourceNamespace()->getName(),
205
                'data.relation.collection' => $object_1->getCollection()->getName(),
206
                'data.relation.object' => $object_1->getName(),
207
            ], [
208
                'data.relation.namespace' => $object_2->getCollection()->getResourceNamespace()->getName(),
209
                'data.relation.collection' => $object_2->getCollection()->getName(),
210
                'data.relation.object' => $object_2->getName(),
211
            ],
212
        ];
213
214
        $name = new ObjectId();
215
        $resource = [
216
            '_id' => $name,
217
            'name' => (string) $name,
218
            'data' => [
219
                'relation' => [
220
                    [
221
                        'namespace' => $relations[0]['data.relation.namespace'],
222
                        'collection' => $relations[0]['data.relation.collection'],
223
                        'object' => $relations[0]['data.relation.object'],
224
                    ],
225
                    [
226
                        'namespace' => $relations[1]['data.relation.namespace'],
227
                        'collection' => $relations[1]['data.relation.collection'],
228
                        'object' => $relations[1]['data.relation.object'],
229
                    ],
230
                ],
231
                'context' => $context,
232
            ],
233
            'namespace' => $object_1->getCollection()->getResourceNamespace()->getName(),
234
        ];
235
236
        $exists = $this->db->{self::COLLECTION_NAME}->findOne([
237
            '$and' => $relations,
238
        ]);
239
240
        if ($endpoints !== null) {
241
            $resource['endpoints'] = $endpoints;
242
        }
243
244
        if ($exists !== null) {
245
            $data = [
246
                'data' => $exists['data'],
247
                'endpoints' => array_replace_recursive($exists['endpoints'], $endpoints),
248
            ];
249
250
            $exists = $this->build($exists);
251
            $this->resource_factory->updateIn($this->db->{self::COLLECTION_NAME}, $exists, $data);
252
253
            return $exists->getId();
254
        }
255
256
        return $this->resource_factory->addTo($this->db->{self::COLLECTION_NAME}, $resource);
257
    }
258
259
    /**
260
     * Add.
261
     */
262
    public function add(ResourceNamespaceInterface $namespace, array $resource): ObjectIdInterface
263
    {
264
        $resource['kind'] = 'DataObjectRelation';
265
        $resource = $this->resource_factory->validate($resource);
266
267
        $resource['_id'] = new ObjectId();
268
        if (!isset($resource['name'])) {
269
            $resource['name'] = (string) $resource['_id'];
270
        }
271
272
        if ($this->has($namespace, $resource['name'])) {
273
            throw new Exception\NotUnique('relation '.$resource['name'].' does already exists');
274
        }
275
276
        $resource['namespace'] = $namespace->getName();
277
278
        return $this->resource_factory->addTo($this->db->{self::COLLECTION_NAME}, $resource);
279
    }
280
281
    public function update(DataObjectRelationInterface $resource, array $data): bool
282
    {
283
        $data['name'] = $resource->getName();
284
        $data['kind'] = $resource->getKind();
285
        $data = $this->resource_factory->validate($data);
286
287
        return $this->resource_factory->updateIn($this->db->{self::COLLECTION_NAME}, $resource, $data);
288
    }
289
290
    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...
291
    {
292
        $this->resource_factory->deleteFrom($this->db->{self::COLLECTION_NAME}, $relation->getId());
293
294
        return true;
295
    }
296
297
    /**
298
     * Change stream.
299
     */
300
    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...
301
    {
302
        $that = $this;
303
304
        return $this->resource_factory->watchFrom($this->db->{self::COLLECTION_NAME}, $after, $existing, $query, function (array $resource) use ($that) {
305
            return $that->build($resource);
306
        }, $offset, $limit, $sort);
307
    }
308
309
    /**
310
     * Build.
311
     */
312
    public function build(array $resource, ?DataObjectInterface $object = null): DataObjectRelationInterface
313
    {
314
        return $this->resource_factory->initResource(new DataObjectRelation($resource, $object));
315
    }
316
}
317