Completed
Push — develop ( d2639f...6415b9 )
by
unknown
16s
created

ServiceManager::getCacheKey()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
dl 0
loc 6
c 1
b 0
f 0
ccs 0
cts 6
cp 0
rs 9.4285
cc 1
eloc 4
nc 1
nop 1
crap 2
1
<?php
2
/**
3
 * ParamConverter class for entry point to Analytics Bundle
4
 */
5
6
namespace Graviton\AnalyticsBundle\Manager;
7
8
use Graviton\AnalyticsBundle\Helper\JsonMapper;
9
use Graviton\AnalyticsBundle\Model\AnalyticModel;
10
use Symfony\Component\Finder\Finder;
11
use Symfony\Component\Filesystem\Filesystem;
12
use Doctrine\Common\Cache\CacheProvider;
13
use Symfony\Component\HttpFoundation\RequestStack;
14
use Symfony\Component\Routing\Router;
15
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
16
use Graviton\AnalyticsBundle\Exception\AnalyticUsageException;
17
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
18
19
/**
20
 * Service Request Converter and startup for Analytics
21
 *
22
 * @author   List of contributors <https://github.com/libgraviton/graviton/graphs/contributors>
23
 * @license  https://opensource.org/licenses/MIT MIT License
24
 * @link     http://swisscom.ch
25
 */
26
class ServiceManager
27
{
28
    /** Cache name for services */
29
    const CACHE_KEY_SERVICES = 'analytics_services';
30
    const CACHE_KEY_SERVICES_URLS = 'analytics_services_urls';
31
    const CACHE_KEY_SERVICES_PREFIX = 'analytics_';
32
33
    /** @var RequestStack */
34
    protected $requestStack;
35
36
    /** @var AnalyticsManager */
37
    protected $analyticsManager;
38
39
    /** @var CacheProvider */
40
    protected $cacheProvider;
41
42
    /** @var Router */
43
    protected $router;
44
45
    /** @var string */
46
    protected $directory;
47
48
    /** @var int */
49
    protected $cacheTimeMetadata;
50
51
    /** @var Filesystem */
52
    protected $fs;
53
54
    /**
55
     * ServiceConverter constructor.
56
     * @param RequestStack     $requestStack        Sf Request information service
57
     * @param AnalyticsManager $analyticsManager    Db Manager and query control
58
     * @param CacheProvider    $cacheProvider       Cache service
59
     * @param Router           $router              To manage routing generation
60
     * @param string           $definitionDirectory Where definitions are stored
61
     * @param int              $cacheTimeMetadata   How long to cache metadata
62
     */
63
    public function __construct(
64
        RequestStack $requestStack,
65
        AnalyticsManager $analyticsManager,
66
        CacheProvider $cacheProvider,
67
        Router $router,
68
        $definitionDirectory,
69
        $cacheTimeMetadata
70
    ) {
71
        $this->requestStack = $requestStack;
72
        $this->analyticsManager = $analyticsManager;
73
        $this->cacheProvider = $cacheProvider;
74
        $this->router = $router;
75
        $this->directory = $definitionDirectory;
76
        $this->cacheTimeMetadata = $cacheTimeMetadata;
77
        $this->fs = new Filesystem();
78
    }
79
80
    /**
81
     * Scan base root directory for analytic definitions
82
     * @return array
83
     */
84
    private function getDirectoryServices()
85
    {
86
        $services = $this->cacheProvider->fetch(self::CACHE_KEY_SERVICES);
87
88
        if (is_array($services)) {
89
            return $services;
90
        }
91
92
        $services = [];
93
        if (strpos($this->directory, 'vendor/graviton/graviton')) {
94
            $this->directory = str_replace('vendor/graviton/graviton/', '', $this->directory);
95
        }
96
        if (!is_dir($this->directory)) {
97
            return $services;
98
        }
99
100
        $finder = new Finder();
101
        $finder
102
            ->files()
103
            ->in($this->directory)
104
            ->path('/\/analytics\//i')
105
            ->name('*.json')
106
            ->notName('_*')
107
            ->sortByName();
108
109
        $finder = new Finder();
110
        $finder
111
            ->files()
112
            ->in($this->directory)
113
            ->path('/\/analytics\//i')
114
            ->name('*.json')
115
            ->notName('_*')
116
            ->notName('*pipeline.json')
117
            ->sortByName();
118
119
        foreach ($finder as $file) {
120
            $key = $file->getFilename();
121
            $data = json_decode($file->getContents());
122
            if (json_last_error()) {
123
                throw new InvalidConfigurationException(
124
                    sprintf('Analytics file: %s could not be loaded due to error: %s', $key, json_last_error_msg())
125
                );
126
            }
127
128
            // is there a pipeline file?
129
            $pipelineFile = substr($file->getPathname(), 0, -4).'pipeline.json';
130
            if ($this->fs->exists($pipelineFile)) {
131
                $data->aggregate = json_decode(file_get_contents($pipelineFile));
132
            }
133
134
            $services[$data->route] = $data;
135
        }
136
137
        $this->cacheProvider->save(self::CACHE_KEY_SERVICES, $services, $this->cacheTimeMetadata);
138
        return $services;
139
    }
140
141
    /**
142
     * Return array of available services
143
     *
144
     * @return array
145
     */
146
    public function getServices()
147
    {
148
        $services = $this->cacheProvider->fetch(self::CACHE_KEY_SERVICES_URLS);
149
        if (is_array($services)) {
150
            return $services;
151
        }
152
153
        $services = [];
154
        foreach ($this->getDirectoryServices() as $name => $service) {
155
            $services[] = [
156
                '$ref' => $this->router->generate(
157
                    'graviton_analytics_service',
158
                    [
159
                        'service' => $service->route
160
                    ],
161
                    false
162
                ),
163
                'profile' => $this->router->generate(
164
                    'graviton_analytics_service_schema',
165
                    [
166
                        'service' => $service->route
167
                    ],
168
                    true
169
                )
170
            ];
171
        }
172
        $this->cacheProvider->save(
173
            self::CACHE_KEY_SERVICES_URLS,
174
            $services,
175
            $this->cacheTimeMetadata
176
        );
177
        return $services;
178
    }
179
180
    /**
181
     * Get service definition
182
     *
183
     * @param string $name Route name for service
184
     * @throws NotFoundHttpException
185
     * @return AnalyticModel
186
     */
187
    private function getServiceSchemaByRoute($name)
188
    {
189
        $services = $this->getDirectoryServices();
190
        // Locate the schema definition
191
        if (!array_key_exists($name, $services)) {
192
            throw new NotFoundHttpException(
193
                sprintf('Service Analytics for %s was not found', $name)
194
            );
195
        }
196
197
        $mapper = new JsonMapper();
198
        /** @var AnalyticModel $schema */
199
        $schema = $mapper->map($services[$name], new AnalyticModel());
200
        return $schema;
201
    }
202
203
    /**
204
     * Will map and find data for defined route
205
     *
206
     * @return array
207
     */
208
    public function getData()
209
    {
210
        $serviceRoute = $this->requestStack->getCurrentRequest()->get('service');
211
212
        // Locate the schema definition
213
        $schema = $this->getServiceSchemaByRoute($serviceRoute);
214
        $cacheTime = $schema->getCacheTime();
215
        $cacheKey = $this->getCacheKey($schema);
216
217
        //Cached data if configured
218
        if ($cacheTime &&
219
            $cache = $this->cacheProvider->fetch($cacheKey)
220
        ) {
221
            return $cache;
222
        }
223
224
        $data = $this->analyticsManager->getData($schema, $this->getServiceParameters($schema));
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->analyticsManager-...ceParameters($schema)); of type array|object adds the type object to the return on line 230 which is incompatible with the return type documented by Graviton\AnalyticsBundle...ServiceManager::getData of type array.
Loading history...
225
226
        if ($cacheTime) {
227
            $this->cacheProvider->save($cacheKey, $data, $cacheTime);
228
        }
229
230
        return $data;
231
    }
232
233
    /**
234
     * generate a cache key also based on query
235
     *
236
     * @param AnalyticModel $schema schema
237
     *
238
     * @return string cache key
239
     */
240
    private function getCacheKey($schema)
241
    {
242
        return self::CACHE_KEY_SERVICES_PREFIX
243
            .$schema->getRoute()
244
            .sha1(serialize($this->requestStack->getCurrentRequest()->query->all()));
245
    }
246
247
    /**
248
     * Locate and display service definition schema
249
     *
250
     * @return mixed
251
     */
252
    public function getSchema()
253
    {
254
        $serviceRoute = $this->requestStack->getCurrentRequest()->get('service');
255
256
        // Locate the schema definition
257
        $schema =  $this->getServiceSchemaByRoute($serviceRoute);
258
259
        return $schema->getSchema();
260
    }
261
262
    /**
263
     * returns the params as passed from the user
264
     *
265
     * @param AnalyticModel $model model
266
     *
267
     * @return array the params, converted as specified
268
     * @throws AnalyticUsageException
269
     */
270
    private function getServiceParameters(AnalyticModel $model)
271
    {
272
        $params = [];
273
        if (!is_array($model->getParams())) {
274
            return $params;
275
        }
276
277
        foreach ($model->getParams() as $param) {
278
            if (!isset($param->name)) {
279
                throw new \LogicException("Incorrect spec (no name) of param in analytics route " . $model->getRoute());
280
            }
281
282
            $paramValue = $this->requestStack->getCurrentRequest()->query->get($param->name, null);
283
284
            // default set?
285
            if (is_null($paramValue) && isset($param->default)) {
286
                $paramValue = $param->default;
287
            }
288
289
            // required missing?
290
            if (is_null($paramValue) && (isset($param->required) && $param->required === true)) {
291
                throw new AnalyticUsageException(
292
                    sprintf(
293
                        "Missing parameter '%s' in analytics route '%s'",
294
                        $param->name,
295
                        $model->getRoute()
296
                    )
297
                );
298
            }
299
300
            if (!is_null($param->type)) {
301
                switch ($param->type) {
302
                    case "integer":
303
                        $paramValue = intval($paramValue);
304
                        break;
305
                    case "boolean":
306
                        $paramValue = boolval($paramValue);
307
                        break;
308
                    case "array":
309
                        $paramValue = explode(',', $paramValue);
310
                        break;
311
                    case "array<integer>":
312
                        $paramValue = array_map('intval', explode(',', $paramValue));
313
                        break;
314
                    case "array<boolean>":
315
                        $paramValue = array_map('boolval', explode(',', $paramValue));
316
                        break;
317
                }
318
            }
319
320
            $params[$param->name] = $paramValue;
321
        }
322
323
        return $params;
324
    }
325
}
326