Passed
Push — main ( 846b4b...9d0fba )
by Felix
12:18
created

RestlerExtended::getPath()   A

Complexity

Conditions 6
Paths 4

Size

Total Lines 19
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 6
eloc 11
c 2
b 0
f 0
nc 4
nop 0
dl 0
loc 19
rs 9.2222
1
<?php
2
namespace Aoe\Restler\System\Restler;
3
4
/***************************************************************
5
 *  Copyright notice
6
 *
7
 *  (c) 2016 AOE GmbH <[email protected]>
8
 *
9
 *  All rights reserved
10
 *
11
 *  This script is part of the TYPO3 project. The TYPO3 project is
12
 *  free software; you can redistribute it and/or modify
13
 *  it under the terms of the GNU General Public License as published by
14
 *  the Free Software Foundation; either version 3 of the License, or
15
 *  (at your option) any later version.
16
 *
17
 *  The GNU General Public License can be found at
18
 *  http://www.gnu.org/copyleft/gpl.html.
19
 *
20
 *  This script is distributed in the hope that it will be useful,
21
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
22
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23
 *  GNU General Public License for more details.
24
 *
25
 *  This copyright notice MUST APPEAR in all copies of the script!
26
 ***************************************************************/
27
28
use Aoe\Restler\System\TYPO3\Cache as Typo3Cache;
29
use Exception;
30
use Luracast\Restler\Defaults;
31
use Luracast\Restler\RestException;
32
use Luracast\Restler\Restler;
33
use Luracast\Restler\Scope;
34
use Psr\Http\Message\ServerRequestInterface;
35
36
class RestlerExtended extends Restler
37
{
38
    /**
39
     * @var Typo3Cache
40
     */
41
    private $typo3Cache;
42
43
    /** @var ServerRequestInterface  */
44
    protected $request;
45
46
    /***************************************************************************************************************************/
47
    /***************************************************************************************************************************/
48
    /* Block of methods, which MUST be overriden from parent-class (otherwise we can't use the TYPO3-caching-framework) ********/
49
    /***************************************************************************************************************************/
50
    /***************************************************************************************************************************/
51
    /**
52
     * Constructor
53
     *
54
     * @param Typo3Cache $typo3Cache
55
     * @param bool $productionMode    When set to false, it will run in
56
     *                                   debug mode and parse the class files
57
     *                                   every time to map it to the URL
58
     *
59
     * @param bool $refreshCache      will update the cache when set to true
60
     * @param ServerRequestInterface     frontend request
0 ignored issues
show
Bug introduced by
The type Aoe\Restler\System\Restler\frontend was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
61
     */
62
    public function __construct(Typo3Cache $typo3Cache, $productionMode = false, $refreshCache = false, ServerRequestInterface $request = null)
63
    {
64
        parent::__construct($productionMode, $refreshCache);
65
66
        if (interface_exists('\Psr\Http\Server\MiddlewareInterface')) {
67
            // restler uses echo;die otherwise and then Typo3 standard mechanisms will not be called
68
            Defaults::$returnResponse = true;
69
        }
70
71
        // adds format support for application/hal+json
72
        Scope::$classAliases['HalJsonFormat'] = 'Aoe\Restler\System\Restler\Format\HalJsonFormat';
73
        $this->setSupportedFormats('HalJsonFormat');
74
75
        $this->typo3Cache = $typo3Cache;
76
        $this->request = $request;
77
78
        // set pathes from request if present
79
        if ($this->request !== null) {
80
            $this->url = $this->getPath();
81
        }
82
    }
83
84
    /**
85
     * Main function for processing the api request
86
     * and return the response
87
     *
88
     * @throws Exception     when the api service class is missing
89
     * @throws RestException to send error response
90
     */
91
    public function handle()
92
    {
93
        // get information about the REST-request
94
        $this->get();
95
96
        if ($this->requestMethod === 'GET' && $this->typo3Cache->hasCacheEntry($this->url, $_GET)) {
97
            return $this->handleRequestByTypo3Cache();
98
        }
99
100
        // if no cache exist: restler should handle the request
101
        return parent::handle();
0 ignored issues
show
Bug introduced by
Are you sure the usage of parent::handle() targeting Luracast\Restler\Restler::handle() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
102
    }
103
104
    /**
105
     * Determine path (and baseUrl) for current request.
106
     *
107
     * @return string|string[]|null
108
     */
109
    protected function getPath()
110
    {
111
        if ($this->request !== null) {
112
            // set base path depending on site config
113
            $site = $this->request->getAttribute('site');
114
            if ($site !== null && $site instanceof \TYPO3\CMS\Core\Site\Entity\Site) {
115
                $siteBasePath = $this->request->getAttribute('site')->getBase()->getPath();
116
                if ($siteBasePath !== '/' && $siteBasePath[-1] !== '/') {
117
                    $siteBasePath .= '/';
118
                }
119
            } else {
120
                $siteBasePath = '/';
121
            }
122
            $this->baseUrl = (string)$this->request->getUri()->withQuery('')->withPath($siteBasePath);
123
124
            // set url with base path removed
125
            return rtrim(preg_replace('%^' . preg_quote($siteBasePath, '%') . '%', '', $this->request->getUri()->getPath()), '/');
126
        }
127
        return parent::getPath();
128
    }
129
130
    /**
131
     * override postCall so that we can cache response via TYPO3-caching-framework - if it's possible
132
     */
133
    protected function postCall()
134
    {
135
        parent::postCall();
136
137
        if ($this->typo3Cache->isResponseCacheableByTypo3Cache($this->requestMethod, $this->apiMethodInfo->metadata)) {
138
            $this->typo3Cache->cacheResponseByTypo3Cache(
139
                $this->responseCode,
140
                $this->url,
141
                $_GET,
142
                $this->apiMethodInfo->metadata,
143
                $this->responseData,
144
                get_class($this->responseFormat),
145
                headers_list()
146
            );
147
        }
148
    }
149
150
    /**
151
     * Rewrap the not accessible private stream in a new one.
152
     *
153
     * @return bool|resource
154
     */
155
    public function getRequestStream()
156
    {
157
        $stream = fopen('php://temp', 'wb+');
158
        fwrite($stream, (string)$this->request->getBody());
159
        fseek($stream, 0, SEEK_SET);
160
161
        return $stream;
162
    }
163
164
    /***************************************************************************************************************************/
165
    /***************************************************************************************************************************/
166
    /* Block of methods, which does NOT override logic from parent-class *******************************************************/
167
    /***************************************************************************************************************************/
168
    /***************************************************************************************************************************/
169
    /**
170
     * @return string
171
     */
172
    private function handleRequestByTypo3Cache()
173
    {
174
        $cacheEntry = $this->typo3Cache->getCacheEntry($this->url, $_GET);
175
176
        if (count($cacheEntry['responseHeaders']) === 0) {
177
            // the cache is from an internal REST-API-call, so we must manually send some headers
178
            @header('Content-Type: application/json; charset=utf-8');
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for header(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

178
            /** @scrutinizer ignore-unhandled */ @header('Content-Type: application/json; charset=utf-8');

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
Bug introduced by
Are you sure the usage of header('Content-Type: ap...n/json; charset=utf-8') is correct as it seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
179
            @header('Cache-Control: private, no-cache, no-store, must-revalidate');
0 ignored issues
show
Bug introduced by
Are you sure the usage of header('Cache-Control: p...tore, must-revalidate') is correct as it seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
180
        } else {
181
            // set/manipulate headers
182
            foreach ($cacheEntry['responseHeaders'] as $responseHeader) {
183
                if (substr($responseHeader, 0, 8) === 'Expires:') {
184
                    if ($cacheEntry['frontendCacheExpires'] === 0) {
185
                        $expires = $cacheEntry['frontendCacheExpires'];
186
                    } else {
187
                        $expires = gmdate('D, d M Y H:i:s \G\M\T', time() + $cacheEntry['frontendCacheExpires']);
188
                    }
189
                    @header('Expires: ' . $expires);
0 ignored issues
show
Bug introduced by
Are you sure the usage of header('Expires: ' . $expires) is correct as it seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
190
                } else {
191
                    @header($responseHeader);
0 ignored issues
show
Bug introduced by
Are you sure the usage of header($responseHeader) is correct as it seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
192
                }
193
            }
194
        }
195
        @header('X-Cached-By-Typo3: 1');
0 ignored issues
show
Bug introduced by
Are you sure the usage of header('X-Cached-By-Typo3: 1') is correct as it seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
196
197
        // send data to client
198
        $this->responseCode = $cacheEntry['responseCode'];
199
        $this->responseData = $cacheEntry['responseData'];
200
        return $this->respond();
201
    }
202
}
203