Passed
Pull Request — master (#865)
by Stefano
03:26
created

TranslationsController::setupJsonKeys()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 5
nc 1
nop 0
dl 0
loc 9
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * BEdita, API-first content management framework
4
 * Copyright 2018 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;
14
15
use BEdita\SDK\BEditaClientException;
16
use Cake\Http\Exception\BadRequestException;
17
use Cake\Http\Exception\NotFoundException;
18
use Cake\Http\Response;
19
use Cake\Utility\Hash;
20
use Psr\Log\LogLevel;
21
22
/**
23
 * Translations controller: create, edit, remove translations
24
 *
25
 * @property \App\Controller\Component\HistoryComponent $History
26
 * @property \App\Controller\Component\ObjectsEditorsComponent $ObjectsEditors
27
 * @property \App\Controller\Component\PropertiesComponent $Properties
28
 * @property \App\Controller\Component\ProjectConfigurationComponent $ProjectConfiguration
29
 * @property \App\Controller\Component\QueryComponent $Query
30
 * @property \App\Controller\Component\ThumbsComponent $Thumbs
31
 * @property \BEdita\WebTools\Controller\Component\ApiFormatterComponent $ApiFormatter
32
 */
33
class TranslationsController extends ModulesController
34
{
35
    /**
36
     * @inheritDoc
37
     */
38
    public function initialize(): void
39
    {
40
        $this->setRequest($this->getRequest()->withParam('object_type', 'translations'));
41
        parent::initialize();
42
        $this->Query->setConfig('include', 'object');
43
    }
44
45
    /**
46
     * Display data to add a translation.
47
     *
48
     * @param string|int $id Object ID.
49
     * @return \Cake\Http\Response|null
50
     */
51
    public function add($id): ?Response
52
    {
53
        $this->getRequest()->allowMethod(['get']);
54
        $this->objectType = $this->typeFromUrl();
55
56
        try {
57
            $response = $this->apiClient->getObject($id, $this->objectType);
58
        } catch (BEditaClientException $e) {
59
            // Error! Back to index.
60
            $this->log($e->getMessage(), LogLevel::ERROR);
61
            $this->Flash->error($e->getMessage(), ['params' => $e]);
62
63
            return $this->redirect(['_name' => 'modules:view', 'object_type' => $this->objectType, 'id' => $id]);
64
        }
65
        $this->ProjectConfiguration->read();
66
67
        $this->set('schema', $this->Schema->getSchema($this->objectType));
68
69
        $object = Hash::extract($response, 'data');
70
        $this->set('translation', []);
71
        $this->set('object', $object);
72
73
        return null;
74
    }
75
76
    /**
77
     * View single translation.
78
     *
79
     * @param string|int $id Object ID.
80
     * @param string $lang The lang code.
81
     * @return \Cake\Http\Response|null
82
     */
83
    public function edit($id, $lang): ?Response
84
    {
85
        $this->getRequest()->allowMethod(['get']);
86
        $this->objectType = $this->typeFromUrl();
87
88
        $translation = [];
89
        try {
90
            $response = $this->apiClient->getObject($id, $this->objectType, compact('lang'));
91
92
            // verify that exists a translation in lang $lang inside include
93
            if (!empty($response['included'])) {
94
                foreach ($response['included'] as $included) {
95
                    if ($included['type'] === 'translations' && $included['attributes']['lang'] == $lang) {
96
                        $translation = $included;
97
                    }
98
                }
99
            }
100
            if (empty($translation)) {
101
                throw new NotFoundException(sprintf('Translation not found per %s %s and lang %s', $this->objectType, $id, $lang));
102
            }
103
        } catch (\Exception $e) {
104
            // Error! Back to index.
105
            $this->log($e->getMessage(), LogLevel::ERROR);
106
            $this->Flash->error($e->getMessage(), ['params' => $e]);
107
108
            return $this->redirect(['_name' => 'modules:view', 'object_type' => $this->objectType, 'id' => $id]);
109
        }
110
        $this->ProjectConfiguration->read();
111
112
        $this->set('schema', $this->Schema->getSchema($this->objectType));
113
114
        $object = Hash::extract($response, 'data');
115
        $this->set('translation', $translation);
116
        $this->set('object', $object);
117
118
        return null;
119
    }
120
121
    /**
122
     * Create or edit single translation.
123
     *
124
     * @return void
125
     */
126
    public function save(): void
127
    {
128
        $this->request->allowMethod(['post']);
129
        $this->objectType = $this->typeFromUrl();
130
        $this->setupJsonKeys();
131
        $requestData = $this->prepareRequest($this->objectType);
132
        $objectId = $requestData['object_id'];
133
        if (!empty($requestData['id'])) {
134
            unset($requestData['object_id']);
135
        }
136
        $lang = $requestData['lang'];
137
        try {
138
            $this->apiClient->save('translations', $requestData);
139
        } catch (BEditaClientException $e) {
140
            // Error! Back to object view or index.
141
            $this->log($e->getMessage(), LogLevel::ERROR);
142
            $this->Flash->error($e->getMessage(), ['params' => $e]);
143
144
            if ($this->getRequest()->getData('id')) {
145
                $this->redirect([
146
                    '_name' => 'translations:edit',
147
                    'object_type' => $this->objectType,
148
                    'id' => $objectId,
149
                    'lang' => $lang,
150
                ]);
151
152
                return;
153
            }
154
155
            $this->redirect([
156
                '_name' => 'translations:add',
157
                'object_type' => $this->objectType,
158
                'id' => $objectId,
159
            ]);
160
161
            return;
162
        }
163
164
        $this->redirect([
165
            '_name' => 'translations:edit',
166
            'object_type' => $this->objectType,
167
            'id' => $objectId,
168
            'lang' => $lang,
169
        ]);
170
    }
171
172
    /**
173
     * Setup internal `_jsonKeys`, add `translated_fields.` prefix
174
     * to create the correct path to the single translated field.
175
     *
176
     * @return void
177
     */
178
    protected function setupJsonKeys(): void
179
    {
180
        $jsonKeys = (array)array_map(
181
            function ($v) {
182
                return sprintf('translated_fields.%s', $v);
183
            },
184
            explode(',', (string)$this->request->getData('_jsonKeys'))
185
        );
186
        $this->request = $this->request->withData('_jsonKeys', implode(',', $jsonKeys));
187
    }
188
189
    /**
190
     * Delete single translation.
191
     * Expected request:
192
     *     data: [
193
     *         {
194
     *             id: <translation id>,
195
     *             object_id: <translated object id>,
196
     *         }
197
     *     ]
198
     *
199
     * @return \Cake\Http\Response
200
     */
201
    public function delete(): Response
202
    {
203
        $this->getRequest()->allowMethod(['post']);
204
        $this->objectType = $this->typeFromUrl();
205
        $requestData = $this->getRequest()->getData();
206
        $translation = [];
207
        try {
208
            if (empty($requestData[0])) {
209
                throw new BadRequestException(__('Empty request data'));
210
            }
211
            $translation = $requestData[0];
212
            if (empty($translation['id'])) {
213
                throw new BadRequestException(__('Empty translation "id"'));
214
            }
215
            if (empty($translation['object_id'])) {
216
                throw new BadRequestException(__('Empty translation "object_id"'));
217
            }
218
            // remove completely the translation
219
            $this->apiClient->delete(sprintf('/translations/%s', $translation['id']));
220
        } catch (BEditaClientException $e) {
221
            $this->log($e->getMessage(), LogLevel::ERROR);
222
            $this->Flash->error($e->getMessage(), ['params' => $e]);
223
224
            // redir to main object view
225
            return $this->redirect(['_name' => 'modules:view', 'object_type' => $this->objectType, 'id' => $translation['object_id']]);
226
        }
227
        $this->Flash->success(__('Translation(s) deleted'));
228
229
        // redir to main object view
230
        return $this->redirect(['_name' => 'modules:view', 'object_type' => $this->objectType, 'id' => $translation['object_id']]);
231
    }
232
233
    /**
234
     * Get type from url, if objectType is 'translations'
235
     *
236
     * @return string
237
     */
238
    protected function typeFromUrl(): string
239
    {
240
        if ($this->objectType !== 'translations') {
241
            return $this->objectType;
242
        }
243
        $here = (string)$this->getRequest()->getAttribute('here');
244
245
        return substr($here, 1, strpos(substr($here, 1), '/'));
246
    }
247
}
248