Completed
Pull Request — master (#50)
by
unknown
16:29
created

RestlerExtended   A

Complexity

Total Complexity 12

Size/Duplication

Total Lines 135
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 2

Test Coverage

Coverage 0%

Importance

Changes 0
Metric Value
wmc 12
lcom 2
cbo 2
dl 0
loc 135
ccs 0
cts 43
cp 0
rs 10
c 0
b 0
f 0

5 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 14 1
A handle() 0 12 3
A postCall() 0 16 2
A getRequestStream() 0 8 1
A handleRequestByTypo3Cache() 0 30 5
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
83
    /**
84
     * Main function for processing the api request
85
     * and return the response
86
     *
87
     * @throws Exception     when the api service class is missing
88
     * @throws RestException to send error response
89
     */
90
    public function handle()
91
    {
92
        // get information about the REST-request
93
        $this->get();
94
95
        if ($this->requestMethod === 'GET' && $this->typo3Cache->hasCacheEntry($this->url, $_GET)) {
96
            return $this->handleRequestByTypo3Cache();
97
        }
98
99
        // if no cache exist: restler should handle the request
100
        return parent::handle();
101
    }
102
103
    /**
104
     * override postCall so that we can cache response via TYPO3-caching-framework - if it's possible
105
     */
106
    protected function postCall()
107
    {
108
        parent::postCall();
109
110
        if ($this->typo3Cache->isResponseCacheableByTypo3Cache($this->requestMethod, $this->apiMethodInfo->metadata)) {
111
            $this->typo3Cache->cacheResponseByTypo3Cache(
112
                $this->responseCode,
113
                $this->url,
114
                $_GET,
115
                $this->apiMethodInfo->metadata,
116
                $this->responseData,
117
                get_class($this->responseFormat),
118
                headers_list()
119
            );
120
        }
121
    }
122
123
    /**
124
     * Rewrap the not accessible private stream in a new one.
125
     *
126
     * @return bool|resource
127
     */
128
    public function getRequestStream()
129
    {
130
        $stream = fopen('php://temp', 'wb+');
131
        fwrite($stream, (string)$this->request->getBody());
132
        fseek($stream, 0, SEEK_SET);
133
134
        return $stream;
135
    }
136
137
    /***************************************************************************************************************************/
138
    /***************************************************************************************************************************/
139
    /* Block of methods, which does NOT override logic from parent-class *******************************************************/
140
    /***************************************************************************************************************************/
141
    /***************************************************************************************************************************/
142
    /**
143
     * @return string
144
     */
145
    private function handleRequestByTypo3Cache()
146
    {
147
        $cacheEntry = $this->typo3Cache->getCacheEntry($this->url, $_GET);
148
149
        if (count($cacheEntry['responseHeaders']) === 0) {
150
            // the cache is from an internal REST-API-call, so we must manually send some headers
151
            @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...
152
            @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...
153
        } else {
154
            // set/manipulate headers
155
            foreach ($cacheEntry['responseHeaders'] as $responseHeader) {
156
                if (substr($responseHeader, 0, 8) === 'Expires:') {
157
                    if ($cacheEntry['frontendCacheExpires'] === 0) {
158
                        $expires = $cacheEntry['frontendCacheExpires'];
159
                    } else {
160
                        $expires = gmdate('D, d M Y H:i:s \G\M\T', time() + $cacheEntry['frontendCacheExpires']);
161
                    }
162
                    @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...
163
                } else {
164
                    @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...
165
                }
166
            }
167
        }
168
        @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...
169
170
        // send data to client
171
        $this->responseCode = $cacheEntry['responseCode'];
172
        $this->responseData = $cacheEntry['responseData'];
173
        return $this->respond();
174
    }
175
}
176