Completed
Pull Request — master (#50)
by
unknown
03:45
created

RestlerExtended::getPath()   A

Complexity

Conditions 5
Paths 4

Size

Total Lines 21

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 30

Importance

Changes 0
Metric Value
dl 0
loc 21
ccs 0
cts 7
cp 0
rs 9.2728
c 0
b 0
f 0
cc 5
nc 4
nop 0
crap 30
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\Restler\Format\HalJsonFormat;
29
use Aoe\Restler\System\TYPO3\Cache as Typo3Cache;
30
use Luracast\Restler\Defaults;
31
use Luracast\Restler\Restler;
32
use Luracast\Restler\RestException;
33
use Exception;
34
use Luracast\Restler\Scope;
35
use Psr\Http\Message\ServerRequestInterface;
36
use Symfony\Component\DependencyInjection\Tests\Compiler\H;
37
38
/**
39
 * @package Restler
40
 */
41
class RestlerExtended extends Restler
42
{
43
    /**
44
     * @var Typo3Cache
45
     */
46
    private $typo3Cache;
47
48
49
    /** @var ServerRequestInterface  */
50
    protected $request;
51
52
    /***************************************************************************************************************************/
53
    /***************************************************************************************************************************/
54
    /* Block of methods, which MUST be overriden from parent-class (otherwise we can't use the TYPO3-caching-framework) ********/
55
    /***************************************************************************************************************************/
56
    /***************************************************************************************************************************/
57
    /**
58
     * Constructor
59
     *
60
     * @param Typo3Cache $typo3Cache
61
     * @param boolean $productionMode    When set to false, it will run in
62
     *                                   debug mode and parse the class files
63
     *                                   every time to map it to the URL
64
     *
65
     * @param boolean $refreshCache      will update the cache when set to true
66
     * @param ServerRequestInterface     frontend request
67
     */
68
    public function __construct(Typo3Cache $typo3Cache, $productionMode = false, $refreshCache = false, ServerRequestInterface $request = null)
69
    {
70
        parent::__construct($productionMode, $refreshCache);
71
72
        // restler uses echo;die otherwise and then Typo3 standard mechanisms will not be called
73
        Defaults::$returnResponse = true;
74
75
        // adds format support for application/hal+json
76
        Scope::$classAliases['HalJsonFormat'] = 'Aoe\Restler\System\Restler\Format\HalJsonFormat';
77
        $this->setSupportedFormats('HalJsonFormat');
78
79
        $this->typo3Cache = $typo3Cache;
80
        $this->request = $request;
81
82
        // set pathes from request if present
83
        if ($this->request !== null) {
84
            $this->url = $this->getPath();
85
        }
86
    }
87
88
    /**
89
     * Main function for processing the api request
90
     * and return the response
91
     *
92
     * @throws Exception     when the api service class is missing
93
     * @throws RestException to send error response
94
     */
95
    public function handle()
96
    {
97
        // get information about the REST-request
98
        $this->get();
99
100
        if ($this->requestMethod === 'GET' && $this->typo3Cache->hasCacheEntry($this->url, $_GET)) {
101
            return $this->handleRequestByTypo3Cache();
102
        }
103
104
        // if no cache exist: restler should handle the request
105
        return parent::handle();
106
    }
107
108
    /**
109
     * Determine path (and baseUrl) for current request.
110
     *
111
     * @return string|string[]|null
112
     */
113
    protected function getPath()
114
    {
115
        if ($this->request !== null) {
116
            // set base path depending on site config
117
            $site = $this->request->getAttribute('site');
118
            if ($site !== null && $site instanceof TYPO3\CMS\Core\Site\Entity\Site) {
0 ignored issues
show
Bug introduced by
The class Aoe\Restler\System\Restl...S\Core\Site\Entity\Site does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
119
                $siteBasePath = $this->request->getAttribute('site')->getBase()->getPath();
120
                if ($siteBasePath !== '/') {
121
                    $siteBasePath .= '/';
122
                }
123
            } else {
124
                $siteBasePath = '/';
125
            }
126
            $this->baseUrl = (string)$this->request->getUri()->withQuery('')->withPath($siteBasePath);
127
128
            // set url with base path removed
129
            return preg_replace('%^' . preg_quote($siteBasePath, '%') . '%', '', $this->request->getUri()->getPath());
130
        } else {
131
            return parent::getPath();
132
        }
133
    }
134
135
    /**
136
     * override postCall so that we can cache response via TYPO3-caching-framework - if it's possible
137
     */
138
    protected function postCall()
139
    {
140
        parent::postCall();
141
142
        if ($this->typo3Cache->isResponseCacheableByTypo3Cache($this->requestMethod, $this->apiMethodInfo->metadata)) {
143
            $this->typo3Cache->cacheResponseByTypo3Cache(
144
                $this->responseCode,
145
                $this->url,
146
                $_GET,
147
                $this->apiMethodInfo->metadata,
148
                $this->responseData,
149
                get_class($this->responseFormat),
150
                headers_list()
151
            );
152
        }
153
    }
154
155
    /**
156
     * Rewrap the not accessible private stream in a new one.
157
     *
158
     * @return bool|resource
159
     */
160
    public function getRequestStream()
161
    {
162
        $stream = fopen('php://temp', 'wb+');
163
        fwrite($stream, (string)$this->request->getBody());
164
        fseek($stream, 0, SEEK_SET);
165
166
        return $stream;
167
    }
168
169
    /***************************************************************************************************************************/
170
    /***************************************************************************************************************************/
171
    /* Block of methods, which does NOT override logic from parent-class *******************************************************/
172
    /***************************************************************************************************************************/
173
    /***************************************************************************************************************************/
174
    /**
175
     * @return string
176
     */
177
    private function handleRequestByTypo3Cache()
178
    {
179
        $cacheEntry = $this->typo3Cache->getCacheEntry($this->url, $_GET);
180
181
        if (count($cacheEntry['responseHeaders']) === 0) {
182
            // the cache is from an internal REST-API-call, so we must manually send some headers
183
            @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 here. This can introduce security issues, and is generally not recommended.

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...
184
            @header('Cache-Control: private, no-cache, no-store, must-revalidate');
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

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...
185
        } else {
186
            // set/manipulate headers
187
            foreach ($cacheEntry['responseHeaders'] as $responseHeader) {
188
                if (substr($responseHeader, 0, 8) === 'Expires:') {
189
                    if ($cacheEntry['frontendCacheExpires'] === 0) {
190
                        $expires = $cacheEntry['frontendCacheExpires'];
191
                    } else {
192
                        $expires = gmdate('D, d M Y H:i:s \G\M\T', time() + $cacheEntry['frontendCacheExpires']);
193
                    }
194
                    @header('Expires: '.$expires);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

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...
195
                } else {
196
                    @header($responseHeader);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

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...
197
                }
198
            }
199
        }
200
        @header('X-Cached-By-Typo3: 1');
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

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...
201
202
        // send data to client
203
        $this->responseCode = $cacheEntry['responseCode'];
204
        $this->responseData = $cacheEntry['responseData'];
205
        return $this->respond();
206
    }
207
}
208