Passed
Pull Request — master (#794)
by Stefano
02:37
created

CloneComponent::initialize()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 2
c 1
b 0
f 0
dl 0
loc 4
rs 10
cc 1
nc 1
nop 1
1
<?php
2
declare(strict_types=1);
3
/**
4
 * BEdita, API-first content management framework
5
 * Copyright 2022 Atlas Srl, Chialab Srl
6
 *
7
 * This file is part of BEdita: you can redistribute it and/or modify
8
 * it under the terms of the GNU Lesser General Public License as published
9
 * by the Free Software Foundation, either version 3 of the License, or
10
 * (at your option) any later version.
11
 *
12
 * See LICENSE.LGPL or <http://gnu.org/licenses/lgpl-3.0.html> for more details.
13
 */
14
15
namespace App\Controller\Component;
16
17
use BEdita\WebTools\ApiClientProvider;
18
use Cake\Controller\Component;
19
use Cake\Utility\Hash;
20
21
/**
22
 * Clone component
23
 */
24
class CloneComponent extends Component
25
{
26
    /**
27
     * Get the value of query 'cloneRelations'.
28
     * Return true when cloneRelations is not false.
29
     *
30
     * @return bool
31
     */
32
    public function queryCloneRelations(): bool
33
    {
34
        $cloneRelations = $this->getController()->getRequest()->getQuery('cloneRelations');
35
36
        return filter_var($cloneRelations, FILTER_VALIDATE_BOOLEAN) !== false;
37
    }
38
39
    /**
40
     * Clone relation from source object $source to destination object ID $destination.
41
     * Exclude 'children', if present.
42
     *
43
     * @param array $source The source object
44
     * @param string $destinationId The destination ID
45
     * @return bool
46
     */
47
    public function relations(array $source, string $destinationId): bool
48
    {
49
        if (!$this->queryCloneRelations()) {
50
            return false;
51
        }
52
        $sourceId = (string)Hash::get($source, 'data.id');
53
        $type = (string)Hash::get($source, 'data.type');
54
        $relationships = array_keys((array)Hash::extract($source, 'data.relationships'));
55
        $relationships = $this->filterRelations($relationships);
56
        foreach ($relationships as $relation) {
57
            $this->relation($sourceId, $type, $relation, $destinationId);
58
        }
59
60
        return true;
61
    }
62
63
    /**
64
     * Filter relationships, remove not allowed 'children', 'parents', 'translations'
65
     *
66
     * @param array $relationships The relationships
67
     * @return array
68
     */
69
    public function filterRelations(array $relationships): array
70
    {
71
        return array_values(
72
            array_filter(
73
                $relationships,
74
                function ($relationship) {
75
                    return !in_array($relationship, ModulesComponent::FIXED_RELATIONSHIPS);
76
                }
77
            )
78
        );
79
    }
80
81
    /**
82
     * Clone single relation data.
83
     * This calls multiple times `BEditaClient::addRelated`, instead of calling it once,
84
     * to avoid time and resources consuming api operations locking tables.
85
     *
86
     * @param string $sourceId The source ID
87
     * @param string $type The object type
88
     * @param string $relation The relation name
89
     * @param string $destinationId The destination ID
90
     * @return bool
91
     */
92
    public function relation(string $sourceId, string $type, string $relation, string $destinationId): bool
93
    {
94
        $apiClient = ApiClientProvider::getApiClient();
95
        $related = $apiClient->getRelated($sourceId, $type, $relation);
96
        if (empty($related['data'])) {
97
            return false;
98
        }
99
        foreach ($related['data'] as $obj) {
100
            $apiClient->addRelated($destinationId, $type, $relation, [
101
                [
102
                    'id' => (string)Hash::get($obj, 'id'),
103
                    'type' => (string)Hash::get($obj, 'type'),
104
                ],
105
            ]);
106
        }
107
108
        return true;
109
    }
110
}
111