Passed
Pull Request — master (#800)
by Stefano
03:06
created

RelationsController::view()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 5
c 0
b 0
f 0
dl 0
loc 8
rs 10
cc 1
nc 1
nop 1
1
<?php
2
/**
3
 * BEdita, API-first content management framework
4
 * Copyright 2021 ChannelWeb Srl, Chialab Srl
5
 *
6
 * This file is part of BEdita: you can redistribute it and/or modify
7
 * it under the terms of the GNU Lesser General Public License as published
8
 * by the Free Software Foundation, either version 3 of the License, or
9
 * (at your option) any later version.
10
 *
11
 * See LICENSE.LGPL or <http://gnu.org/licenses/lgpl-3.0.html> for more details.
12
 */
13
namespace App\Controller\Model;
14
15
use Cake\Http\Response;
16
use Cake\Utility\Hash;
17
18
/**
19
 * Relations Model Controller: list, add, edit, remove relations
20
 *
21
 * @property \App\Controller\Component\PropertiesComponent $Properties
22
 */
23
class RelationsController extends ModelBaseController
24
{
25
    /**
26
     * Resource type currently used
27
     *
28
     * @var string
29
     */
30
    protected $resourceType = 'relations';
31
32
    /**
33
     * @inheritDoc
34
     */
35
    public function index(): ?Response
36
    {
37
        parent::index();
38
        $resources = (array)$this->viewBuilder()->getVar('resources');
39
        foreach ($resources as &$resource) {
40
            $resource['left_object_types'] = $this->relatedTypes($resource, 'left');
41
            $resource['right_object_types'] = $this->relatedTypes($resource, 'right');
42
        }
43
        $this->set(compact('resources'));
44
45
        return null;
46
    }
47
48
    /**
49
     * @inheritDoc
50
     */
51
    protected function indexQuery(): array
52
    {
53
        return  parent::indexQuery() + ['include' => 'left_object_types,right_object_types'];
54
    }
55
56
    /**
57
     * @inheritDoc
58
     */
59
    protected function viewQuery(): array
60
    {
61
        return  parent::viewQuery() + ['include' => 'left_object_types,right_object_types'];
62
    }
63
64
    /**
65
     * @inheritDoc
66
     */
67
    public function view($id): ?Response
68
    {
69
        parent::view($id);
70
        $resource = (array)$this->viewBuilder()->getVar('resource');
71
        $this->set('left_object_types', $this->relatedTypes($resource, 'left'));
72
        $this->set('right_object_types', $this->relatedTypes($resource, 'right'));
73
74
        return null;
75
    }
76
77
    /**
78
     * Save relation.
79
     *
80
     * @return \Cake\Http\Response|null
81
     */
82
    public function save(): ?Response
83
    {
84
        $data = (array)$this->request->getData();
85
        $this->updateRelatedTypes($data, 'left');
86
        $this->updateRelatedTypes($data, 'right');
87
        $this->request = $this->request->withoutData('change_left')
88
            ->withoutData('change_right')
89
            ->withoutData('current_left')
90
            ->withoutData('current_right');
91
92
        return parent::save();
93
    }
94
95
    /**
96
     * Update relation types on the `left` or `right` side of a relation
97
     *
98
     * @param array $data Request data
99
     * @param string $side Relation side, `left` or `right`
100
     * @return void
101
     */
102
    protected function updateRelatedTypes(array $data, string $side): void
103
    {
104
        $current = array_filter(explode(',', (string)Hash::get($data, sprintf('current_%s', $side))));
105
        $change = array_filter(explode(',', (string)Hash::get($data, sprintf('change_%s', $side))));
106
        sort($current);
107
        sort($change);
108
        if ($current == $change) {
109
            return;
110
        }
111
        $id = Hash::get($data, 'id');
112
        $endpoint = sprintf('/model/relations/%s/relationships/%s_object_types', $id, $side);
113
        $data = $this->relatedItems($change);
114
        $this->apiClient->patch($endpoint, json_encode(compact('data')));
115
    }
116
117
    /**
118
     * Retrieve body item for API call
119
     *
120
     * @param array $types Object type names array
121
     * @return array
122
     */
123
    protected function relatedItems(array $types): array
124
    {
125
        return array_map(
126
            function ($item) {
127
                $response = $this->apiClient->get(sprintf('/model/object_types/%s', trim($item)));
128
                $id = Hash::get((array)$response, 'data.id');
129
130
                return compact('id') + ['type' => 'object_types'];
131
            },
132
            $types
133
        );
134
    }
135
136
    /**
137
     * Get related types by relation resource and side
138
     *
139
     * @param array $resource The resource data
140
     * @param string $side The side, can be 'left' or 'right'
141
     * @return array
142
     */
143
    protected function relatedTypes(array $resource, string $side): array
144
    {
145
        $path = sprintf('relationships.%s_object_types.data.{n}.attributes.name', $side);
146
147
        return (array)Hash::extract($resource, $path);
148
    }
149
}
150