Completed
Pull Request — develop (#512)
by Adrian
16:23 queued 09:34
created

MainController::decideApiAndEndpoint()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 11
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
dl 0
loc 11
ccs 0
cts 10
cp 0
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 6
nc 2
nop 1
crap 6
1
<?php
2
/**
3
 * controller for start page
4
 */
5
6
namespace Graviton\CoreBundle\Controller;
7
8
use Graviton\ProxyBundle\Service\ApiDefinitionLoader;
9
use Graviton\RestBundle\HttpFoundation\LinkHeader;
10
use Graviton\RestBundle\HttpFoundation\LinkHeaderItem;
11
use Graviton\RestBundle\Service\RestUtilsInterface;
12
use Symfony\Bundle\FrameworkBundle\Templating\EngineInterface;
13
use Symfony\Component\HttpFoundation\Request;
14
use Symfony\Component\HttpFoundation\Response;
15
use Symfony\Component\Routing\Router;
16
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
17
18
/**
19
 * MainController
20
 *
21
 * @author   List of contributors <https://github.com/libgraviton/graviton/graphs/contributors>
22
 * @license  http://opensource.org/licenses/gpl-license.php GNU Public License
23
 * @link     http://swisscom.ch
24
 */
25
class MainController
26
{
27
    /**
28
     * @var Router
29
     */
30
    private $router;
31
32
    /**
33
     * @var Response
34
     */
35
    private $response;
36
37
    /**
38
     * @var RestUtilsInterface
39
     */
40
    private $restUtils;
41
42
    /**
43
     * @var EngineInterface
44
     */
45
    private $templating;
46
47
    /**
48
     * @var ApiDefinitionLoader
49
     */
50
    private $apiLoader;
51
52
    /**
53
     * @var array
54
     */
55
    private $addditionalRoutes;
56
57
    /**
58
     * @var array
59
     */
60
    private $pathWhitelist;
61
62
    /**
63
     * @var array
64
     */
65
    private $proxySourceConfiguration;
66
67
    /**
68
     * @param Router              $router                   router
69
     * @param Response            $response                 prepared response
70
     * @param RestUtilsInterface  $restUtils                rest-utils from GravitonRestBundle
71
     * @param EngineInterface     $templating               templating-engine
72
     * @param ApiDefinitionLoader $apiLoader                loader for third party api definition
73
     * @param array               $additionalRoutes         custom routes
74
     * @param array               $pathWhitelist            serviec path that always get aded to the main page
75
     * @param array               $proxySourceConfiguration Set of sources to be recognized by the controller
76
     */
77
    public function __construct(
78
        Router $router,
79
        Response $response,
80
        RestUtilsInterface $restUtils,
81
        EngineInterface $templating,
82
        ApiDefinitionLoader $apiLoader,
83
        $additionalRoutes = array(),
84
        $pathWhitelist = [],
85
        array $proxySourceConfiguration = array()
86
    ) {
87
        $this->router = $router;
88
        $this->response = $response;
89
        $this->restUtils = $restUtils;
90
        $this->templating = $templating;
91
        $this->apiLoader = $apiLoader;
92
        $this->addditionalRoutes = $additionalRoutes;
93
        $this->pathWhitelist = $pathWhitelist;
94
        $this->proxySourceConfiguration = $proxySourceConfiguration;
95
    }
96
97
    /**
98
     * create simple start page.
99
     *
100
     * @return Response $response Response with result or error
101
     */
102
    public function indexAction()
103
    {
104
        $response = $this->response;
105
106
        $mainPage = new \stdClass();
107
        $mainPage->services = $this->determineServices(
108
            $this->restUtils->getOptionRoutes()
109
        );
110
111
        $mainPage->thirdparty = $this->registerThirdPartyServices();
112
113
        $response->setContent(json_encode($mainPage));
114
        $response->setStatusCode(Response::HTTP_OK);
115
        $response->headers->set('Link', $this->prepareLinkHeader());
116
117
        // todo: make sure, that the correct content type is set.
118
        // todo: this should be covered by a kernel.response event listener?
119
        $response->headers->set('Content-Type', 'application/json');
120
121
        return $this->render(
122
            'GravitonCoreBundle:Main:index.json.twig',
123
            array('response' => $response->getContent()),
124
            $response
125
        );
126
    }
127
128
    /**
129
     * Renders a view.
130
     *
131
     * @param string   $view       The view name
132
     * @param array    $parameters An array of parameters to pass to the view
133
     * @param Response $response   A response instance
0 ignored issues
show
Documentation introduced by
Should the type for parameter $response not be null|Response?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
134
     *
135
     * @return Response A Response instance
136
     */
137
    public function render($view, array $parameters = array(), Response $response = null)
138
    {
139
        return $this->templating->renderResponse($view, $parameters, $response);
140
    }
141
142
    /**
143
     * Determines what service endpoints are available.
144
     *
145
     * @param array $optionRoutes List of routing options.
146
     *
147
     * @return array
148
     */
149
    protected function determineServices(array $optionRoutes)
150
    {
151
        $sortArr = array();
152
        $router = $this->router;
153
        foreach ($this->addditionalRoutes as $route) {
154
            // hack because only array keys are used
155
            $optionRoutes[$route] = null;
156
        }
157
158
        $services = array_map(
159
            function ($routeName) use ($router) {
160
                list($app, $bundle, $rest, $document) = explode('.', $routeName);
161
                $schemaRoute = implode('.', array($app, $bundle, $rest, $document, 'canonicalSchema'));
162
163
                return array(
164
                    '$ref' => $router->generate($routeName, array(), UrlGeneratorInterface::ABSOLUTE_URL),
165
                    'profile' => $router->generate($schemaRoute, array(), UrlGeneratorInterface::ABSOLUTE_URL),
166
                );
167
            },
168
            array_keys($optionRoutes)
169
        );
170
171
        foreach ($services as $key => $val) {
172
            if ($this->isRelevantForMainPage($val) && !in_array($val['$ref'], $sortArr)) {
173
                $sortArr[$key] = $val['$ref'];
174
            } else {
175
                unset($services[$key]);
176
            }
177
        }
178
        array_multisort($sortArr, SORT_ASC, $services);
179
180
        return $services;
181
    }
182
183
    /**
184
     * Prepares the header field containing information about pagination.
185
     *
186
     * @return string
187
     */
188
    protected function prepareLinkHeader()
189
    {
190
        $links = new LinkHeader(array());
191
        $links->add(
192
            new LinkHeaderItem(
193
                $this->router->generate('graviton.core.rest.app.all', array (), UrlGeneratorInterface::ABSOLUTE_URL),
194
                array ('rel' => 'apps', 'type' => 'application/json')
195
            )
196
        );
197
198
        return (string) $links;
199
    }
200
201
    /**
202
     * tells if a service is relevant for the mainpage
203
     *
204
     * @param array $val value of service spec
205
     *
206
     * @return boolean
207
     */
208
    private function isRelevantForMainPage($val)
209
    {
210
        return (substr($val['$ref'], -1) === '/')
211
            || in_array(parse_url($val['$ref'], PHP_URL_PATH), $this->pathWhitelist);
212
    }
213
214
    /**
215
     * Resolves all third party routes and add schema info
216
     *
217
     * @param array $thirdApiRoutes list of all routes from an API
218
     *
219
     * @return array
220
     */
221
    protected function determineThirdPartyServices(array $thirdApiRoutes)
222
    {
223
        $definition = $this->apiLoader;
224
        $mainRoute = $this->router->generate(
225
            'graviton.core.static.main.all',
226
            array(),
227
            UrlGeneratorInterface::ABSOLUTE_URL
228
        );
229
        $services = array_map(
230
            function ($apiRoute) use ($mainRoute, $definition) {
231
232
                return array (
233
                    '$ref' => $mainRoute.$apiRoute,
234
                    'profile' => $mainRoute."schema/".$apiRoute."/item",
235
                );
236
            },
237
            $thirdApiRoutes
238
        );
239
240
        return $services;
241
    }
242
243
    /**
244
     * Finds configured external apis to be exposed via G2.
245
     *
246
     * @return array
247
     */
248
    private function registerThirdPartyServices()
249
    {
250
        $services = [];
251
252
        // getenv()... it's a workaround for run all tests on travis! will be removed!
253
        if (getenv('USER') !== 'travis' && getenv('HAS_JOSH_K_SEAL_OF_APPROVAL') !== true) {
254
            foreach (array_keys($this->proxySourceConfiguration) as $source) {
255
                foreach ($this->proxySourceConfiguration[$source] as $thirdparty => $option) {
256
                    $this->apiLoader->resetDefinitionLoader();
257
                    $this->apiLoader->setOption($option);
258
                    $this->apiLoader->addOptions($this->decideApiAndEndpoint($option));
259
                    $services[$thirdparty] = $this->determineThirdPartyServices(
260
                        $this->apiLoader->getAllEndpoints(false, true)
261
                    );
262
                }
263
            }
264
        }
265
266
        return $services;
267
    }
268
269
    /**
270
     * get API name and endpoint from the url (third party API)
271
     *
272
     * @param array $config Configuration information ['prefix', 'serviceEndpoint']
273
     *
274
     * @return array
275
     */
276
    protected function decideApiAndEndpoint(array $config)
277
    {
278
        if (array_key_exists('serviceEndpoint', $config)) {
279
            return array (
280
                "apiName" => $config['prefix'],
281
                "endpoint" => $config['serviceEndpoint'],
282
            );
283
        }
284
285
        return [];
286
    }
287
}
288