Passed
Pull Request — master (#818)
by Stefano
02:49
created

ApiConfigTrait::readApiConfig()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 19
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 12
c 1
b 0
f 0
nc 3
nop 0
dl 0
loc 19
rs 9.8666
1
<?php
2
declare(strict_types=1);
3
4
/**
5
 * BEdita, API-first content management framework
6
 * Copyright 2022 Atlas Srl, Chialab Srl
7
 *
8
 * This file is part of BEdita: you can redistribute it and/or modify
9
 * it under the terms of the GNU Lesser General Public License as published
10
 * by the Free Software Foundation, either version 3 of the License, or
11
 * (at your option) any later version.
12
 *
13
 * See LICENSE.LGPL or <http://gnu.org/licenses/lgpl-3.0.html> for more details.
14
 */
15
namespace App\Utility;
16
17
use BEdita\SDK\BEditaClientException;
18
use BEdita\WebTools\ApiClientProvider;
19
use Cake\Cache\Cache;
20
use Cake\Collection\Collection;
21
use Cake\Core\Configure;
22
use Cake\Log\Log;
23
use Cake\Utility\Hash;
24
25
/**
26
 * Read and write configuration via API
27
 */
28
trait ApiConfigTrait
29
{
30
    /**
31
     * Cache config key
32
     *
33
     * @var string
34
     */
35
    protected static $cacheKey = 'api_config';
36
37
    /**
38
     * Read cached configuration items from API and update configuration
39
     * using `Configure::write`.
40
     *
41
     * @return void
42
     */
43
    protected function readApiConfig(): void
44
    {
45
        try {
46
            $configs = (array)Cache::remember(
47
                CacheTools::cacheKey(static::$cacheKey),
48
                function () {
49
                    return $this->fetchConfig();
50
                }
51
            );
52
        } catch (BEditaClientException $e) {
53
            Log::error($e->getMessage());
54
55
            return;
56
        }
57
58
        foreach ($configs as $config) {
59
            $content = (array)json_decode((string)Hash::get($config, 'attributes.content'), true);
60
            $key = (string)Hash::get($config, 'attributes.name');
61
            Configure::write($key, $content);
62
        }
63
    }
64
65
    /**
66
     * Fetch configurations from API
67
     *
68
     * @param null|string $key Configuration key to fetch, fetch all keys if null.
69
     * @return array
70
     */
71
    protected function fetchConfig(?string $key = null): array
72
    {
73
        $query = ['page_size' => 100];
74
        $response = (array)ApiClientProvider::getApiClient()->get('/config', $query);
75
        $collection = new Collection((array)Hash::get($response, 'data'));
76
77
        return (array)$collection->reject(function ($item) use ($key) {
78
            return !$this->isAppConfig($key, (array)$item);
79
        })->toArray();
80
    }
81
82
    /**
83
     * Check if a configuration is a valid application configuration.
84
     *
85
     * @param string|null $key Configuration key, if `null` consider any configuration key as valid
86
     * @param array $config Configuration data array from API.
87
     * @return bool
88
     */
89
    protected function isAppConfig(?string $key = null, array $config): bool
90
    {
91
        $attr = (array)Hash::get($config, 'attributes');
92
        if (
93
            empty($attr['application_id']) ||
94
            empty($attr['context']) || $attr['context'] !== 'app' ||
95
            empty($attr['name'])
96
        ) {
97
            return false;
98
        }
99
100
        if ($key === null) {
101
            return true;
102
        }
103
104
        return $attr['name'] === $key;
105
    }
106
107
    /**
108
     * Get BEdita Manager application ID
109
     *
110
     * @return int
111
     */
112
    public function managerApplicationId(): int
113
    {
114
        $name = (string)Configure::read('ManagerAppName', 'manager');
115
        $filter = compact('name');
116
        $response = (array)ApiClientProvider::getApiClient()->get('/admin/applications', compact('filter'));
117
118
        return (int)Hash::get($response, 'data.0.id');
119
    }
120
121
    /**
122
     * Save configuration to API
123
     *
124
     * @param string $key Configuration key
125
     * @param array $data Configuration data
126
     * @return void
127
     */
128
    public function saveApiConfig(string $key, array $data): void
129
    {
130
        $items = array_values($this->fetchConfig($key));
131
        $config = (array)Hash::get($items, '0');
132
        $configId = Hash::get($config, 'id');
133
        $managerAppId = Hash::get($config, 'attributes.application_id');
134
        if (empty($managerAppId)) {
135
            $managerAppId = $this->managerApplicationId();
136
        }
137
        $endpoint = '/admin/config';
138
        $body = [
139
            'data' => [
140
                'type' => 'config',
141
                'attributes' => [
142
                    'name' => $key,
143
                    'context' => 'app',
144
                    'content' => json_encode($data),
145
                    'application_id' => $managerAppId,
146
                ],
147
            ],
148
        ];
149
150
        if (empty($configId)) {
151
            ApiClientProvider::getApiClient()->post($endpoint, json_encode($body));
152
        } else {
153
            $body['data']['id'] = (string)$configId;
154
            ApiClientProvider::getApiClient()->patch(sprintf('%s/%s', $endpoint, $configId), json_encode($body));
155
        }
156
        Cache::delete(CacheTools::cacheKey(static::$cacheKey));
157
        Cache::delete(CacheTools::cacheKey('properties'));
158
    }
159
}
160