RestApiClient   A
last analyzed

Complexity

Total Complexity 13

Size/Duplication

Total Lines 95
Duplicated Lines 0 %

Test Coverage

Coverage 82.35%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 31
c 1
b 0
f 0
dl 0
loc 95
ccs 28
cts 34
cp 0.8235
rs 10
wmc 13

9 Methods

Rating   Name   Duplication   Size   Complexity  
A prepareRequest() 0 7 1
A createRequestException() 0 11 2
A executeRequest() 0 16 3
A isExecutingRequest() 0 3 1
A getRestlerBuilder() 0 3 1
A createRequest() 0 3 1
A isProductionContextSet() 0 3 1
A isRequestPreparationRequired() 0 3 2
A __construct() 0 5 1
1
<?php
2
3
namespace Aoe\Restler\System\RestApi;
4
5
/***************************************************************
6
 *  Copyright notice
7
 *
8
 *  (c) 2024 AOE GmbH <[email protected]>
9
 *
10
 *  All rights reserved
11
 *
12
 *  This script is part of the TYPO3 project. The TYPO3 project is
13
 *  free software; you can redistribute it and/or modify
14
 *  it under the terms of the GNU General Public License as published by
15
 *  the Free Software Foundation; either version 3 of the License, or
16
 *  (at your option) any later version.
17
 *
18
 *  The GNU General Public License can be found at
19
 *  http://www.gnu.org/copyleft/gpl.html.
20
 *
21
 *  This script is distributed in the hope that it will be useful,
22
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
23
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24
 *  GNU General Public License for more details.
25
 *
26
 *  This copyright notice MUST APPEAR in all copies of the script!
27
 ***************************************************************/
28
29
use Aoe\Restler\Configuration\ExtensionConfiguration;
30
use Aoe\Restler\System\Restler\Builder as RestlerBuilder;
31
use Aoe\Restler\System\TYPO3\Cache;
32
use Luracast\Restler\RestException;
33
use stdClass;
34
use TYPO3\CMS\Core\Http\ServerRequest;
35
use TYPO3\CMS\Core\SingletonInterface;
36
use TYPO3\CMS\Core\Utility\GeneralUtility;
37
38
class RestApiClient implements SingletonInterface
39
{
40
    private bool $isExecutingRequest = false;
41
42
    private bool $isRequestPrepared = false;
43
44
    public function __construct(
45
        private readonly ExtensionConfiguration $extensionConfiguration,
46
        private readonly RestApiRequestScope $restApiRequestScope,
47
        private readonly Cache $typo3Cache
48
    ) {
49
    }
50
51
    public function isExecutingRequest(): bool
52
    {
53 5
        return $this->isExecutingRequest;
54
    }
55
56
    public function isProductionContextSet(): bool
57
    {
58 5
        return $this->extensionConfiguration->isProductionContextSet();
59 5
    }
60 5
61 5
    /**
62
     * @param array|stdClass $getData
63 1
     * @param array|stdClass $postData
64
     * @return mixed can be a primitive or array or object
65 1
     */
66
    public function executeRequest(string $requestMethod, string $requestUri, $getData = null, $postData = null)
67
    {
68 2
        if ($this->isRequestPreparationRequired()) {
69
            $this->prepareRequest($requestMethod, $requestUri);
70 2
        }
71
72
        try {
73
            $this->isExecutingRequest = true;
74
            $result = $this->createRequest()
75
                ->executeRestApiRequest($requestMethod, $requestUri, $getData, $postData);
76
            $this->isExecutingRequest = false;
77
            return $result;
78
        } catch (RestException $restException) {
79 3
            $this->isExecutingRequest = false;
80
            $restException = $this->createRequestException($restException, $requestMethod, $requestUri);
81 3
            throw $restException;
82 1
        }
83
    }
84
85
    /**
86 3
     * We must create for every REST-API-request a new object, because the object will contain data, which is related to the request
87 3
     */
88 3
    protected function createRequest(): RestApiRequest
89 2
    {
90 2
        return new RestApiRequest($this->restApiRequestScope, $this->typo3Cache);
91 1
    }
92 1
93 1
    protected function createRequestException(RestException $e, string $requestMethod, string $requestUri): RestApiRequestException
94 1
    {
95
        $errorMessage = "internal REST-API-request '" . $requestMethod . ':' . $requestUri . "' could not be processed";
96
        if (!$this->isProductionContextSet()) {
97
            $errorMessage .= ' (message: ' . $e->getMessage() . ', details: ' . json_encode($e->getDetails(), JSON_THROW_ON_ERROR) . ')';
98
        }
99
100
        return new RestApiRequestException(
101
            $errorMessage,
102
            RestApiRequestException::EXCEPTION_CODE_REQUEST_COULD_NOT_PROCESSED,
103
            $e
104
        );
105
    }
106 1
107
    protected function getRestlerBuilder(): RestlerBuilder
108 1
    {
109 1
        return GeneralUtility::makeInstance(RestlerBuilder::class);
110 1
    }
111
112 1
    /**
113 1
     * We must prepare the REST-API-request when we are in the 'normal' TYPO3-context (the client, which called this PHP-request, has
114 1
     * NOT requested an REST-API-endpoint). In this case, we must build the 'original' REST-API-Request (aka Restler-object, which is
115
     * always required), before we can execute any REST-API-request via this PHP-client.
116
     */
117
    protected function isRequestPreparationRequired(): bool
118
    {
119
        return !defined('REST_API_IS_RUNNING') && !$this->isRequestPrepared;
120
    }
121
122
    /**
123
     * build the 'original' REST-API-Request (aka Restler-object, which is always
124
     * required) and store it in the REST-API-Request-Scope (aka Scope-object)
125
     */
126
    private function prepareRequest(string $requestMethod, string $requestUri): void
127
    {
128
        // TODO: pass along the post data
129
        $originalRestApiRequest = $this->getRestlerBuilder()
130
            ->build(new ServerRequest($requestUri, $requestMethod));
131
        $this->restApiRequestScope->storeOriginalRestApiRequest($originalRestApiRequest);
132
        $this->isRequestPrepared = true;
133
    }
134
}
135