Passed
Push — master ( 8d6a0a...560462 )
by Stefano
02:58 queued 12s
created

CloneComponent   A

Complexity

Total Complexity 9

Size/Duplication

Total Lines 101
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 9
eloc 28
c 1
b 0
f 0
dl 0
loc 101
rs 10

5 Methods

Rating   Name   Duplication   Size   Complexity  
A initialize() 0 4 1
A relation() 0 16 3
A relations() 0 14 3
A filterRelations() 0 7 1
A queryCloneRelations() 0 5 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
     * BEdita Api client
28
     *
29
     * @var \BEdita\SDK\BEditaClient
30
     */
31
    protected $apiClient = null;
32
33
    /**
34
     * {@inheritDoc}
35
     * {@codeCoverageIgnore}
36
     */
37
    public function initialize(array $config): void
38
    {
39
        $this->apiClient = ApiClientProvider::getApiClient();
40
        parent::initialize($config);
41
    }
42
43
    /**
44
     * Get the value of query 'cloneRelations'.
45
     * Return true when cloneRelations is not false.
46
     *
47
     * @return bool
48
     */
49
    public function queryCloneRelations(): bool
50
    {
51
        $cloneRelations = $this->getController()->getRequest()->getQuery('cloneRelations');
52
53
        return filter_var($cloneRelations, FILTER_VALIDATE_BOOLEAN) !== false;
54
    }
55
56
    /**
57
     * Clone relation from source object $source to destination object ID $destination.
58
     * Exclude 'children', if present.
59
     *
60
     * @param array $source The source object
61
     * @param string $destinationId The destination ID
62
     * @return bool
63
     */
64
    public function relations(array $source, string $destinationId): bool
65
    {
66
        if (!$this->queryCloneRelations()) {
67
            return false;
68
        }
69
        $sourceId = (string)Hash::get($source, 'data.id');
70
        $type = (string)Hash::get($source, 'data.type');
71
        $relationships = array_keys((array)Hash::extract($source, 'data.relationships'));
72
        $relationships = $this->filterRelations($relationships);
73
        foreach ($relationships as $relation) {
74
            $this->relation($sourceId, $type, $relation, $destinationId);
75
        }
76
77
        return true;
78
    }
79
80
    /**
81
     * Filter relationships, remove not allowed 'children', 'parents', 'translations'
82
     *
83
     * @param array $relationships The relationships
84
     * @return array
85
     */
86
    public function filterRelations(array $relationships): array
87
    {
88
        return array_values(
89
            array_filter(
90
                $relationships,
91
                function ($relationship) {
92
                    return !in_array($relationship, ModulesComponent::FIXED_RELATIONSHIPS);
93
                }
94
            )
95
        );
96
    }
97
98
    /**
99
     * Clone single relation data.
100
     * This calls multiple times `BEditaClient::addRelated`, instead of calling it once,
101
     * to avoid time and resources consuming api operations locking tables.
102
     *
103
     * @param string $sourceId The source ID
104
     * @param string $type The object type
105
     * @param string $relation The relation name
106
     * @param string $destinationId The destination ID
107
     * @return bool
108
     */
109
    public function relation(string $sourceId, string $type, string $relation, string $destinationId): bool
110
    {
111
        $related = $this->apiClient->getRelated($sourceId, $type, $relation);
112
        if (empty($related['data'])) {
113
            return false;
114
        }
115
        foreach ($related['data'] as $obj) {
116
            $this->apiClient->addRelated($destinationId, $type, $relation, [
117
                [
118
                    'id' => (string)Hash::get($obj, 'id'),
119
                    'type' => (string)Hash::get($obj, 'type'),
120
                ],
121
            ]);
122
        }
123
124
        return true;
125
    }
126
}
127