1<?php
2
3namespace ComboStrap;
4
5
6use ComboStrap\Web\Url;
7use ComboStrap\Web\UrlEndpoint;
8
9/**
10 * A request to the application
11 * It's now a wrapper around {@link \TestRequest}
12 */
13class HttpRequest
14{
15
16    const CANONICAL = "httpRequest";
17    const POST = "post";
18    const GET = "get";
19    private bool $withTestRequest = true;
20
21    private Url $url;
22    private HttpResponse $response;
23    private string $method = self::GET;
24    private bool $asAdmin = false;
25    private array $postData = [];
26
27
28    public function __construct(Url $url)
29    {
30        $this->url = $url;
31
32
33    }
34
35
36    /**
37     * @param string $wikiId
38     * @return HttpResponse
39     * With the path uri: '/doku.php'
40     */
41    public static function fetchXhtmlPageResponse(string $wikiId): HttpResponse
42    {
43
44
45        $url = FetcherPage::createPageFetcherFromId($wikiId)
46            ->getFetchUrl();
47
48
49        return HttpRequest::createRequest($url)
50            ->withTestRequest()
51            ->fetch();
52
53    }
54
55
56    private function withTestRequest(): HttpRequest
57    {
58        $this->withTestRequest = true;
59        return $this;
60    }
61
62    public static function createRequest(Url $url): HttpRequest
63    {
64        return new HttpRequest($url);
65    }
66
67
68    /**
69     * @param array $data - data post body as if it was from a form
70     * @return $this
71     */
72    public function post(array $data = array()): HttpRequest
73    {
74        $this->method = self::POST;
75        $this->postData = $data;
76        return $this;
77    }
78
79
80    public function fetch(): HttpResponse
81    {
82        if (!$this->withTestRequest) {
83
84            throw new ExceptionRuntime("Real HTTP fetch not yet implemented, only test fetch");
85
86        }
87
88        if (ExecutionContext::getActualOrCreateFromEnv()->response()->hasEnded()) {
89            /**
90             * As of today, the execution context is responsible to
91             * send back the response
92             * (There is no routing context, therefore for
93             * each http request, a new context needs to be created)
94             */
95            throw new ExceptionRuntimeInternal("The execution context has ended, you should reopen another one");
96        }
97
98        try {
99            $path = $this->url->getPath();
100            if (!in_array($path, UrlEndpoint::DOKU_ENDPOINTS)) {
101                throw new ExceptionRuntime("The url path is not a doku endpoint path");
102            }
103        } catch (ExceptionNotFound $e) {
104            throw new ExceptionRuntime("The path is mandatory");
105        }
106
107        $testRequest = new \TestRequest();
108        $testRequest->setServer('REQUEST_TIME', time());
109
110        if ($this->asAdmin) {
111            Identity::becomeSuperUser($testRequest);
112        }
113
114        /**
115         * Deprecation are going into the HTML
116         * and break the parsing
117         */
118        $level = error_reporting(E_ALL ^ (E_DEPRECATED));
119        try {
120            switch ($this->method) {
121                case self::GET:
122                    $query = $this->url->getQueryProperties();
123                    $response = $testRequest->get($query, $path);
124                    break;
125                case self::POST:
126                    $query = $this->url->getQueryProperties();
127                    foreach ($query as $queryKey => $queryValue) {
128                        $testRequest->setGet($queryKey, $queryValue);
129                    }
130                    $response = $testRequest->post($this->postData, $path);
131                    break;
132                default:
133                    throw new ExceptionRuntime("The method ({$this->method}) is not implemented");
134            }
135        } finally {
136            error_reporting($level);
137        }
138
139
140        return HttpResponse::createFromDokuWikiResponse($response);
141    }
142
143    public function asAdmin(): HttpRequest
144    {
145        $this->asAdmin = true;
146        return $this;
147    }
148
149    public function get(): HttpRequest
150    {
151        $this->method = self::GET;
152        return $this;
153    }
154
155    public function fetchAndExcuteBodyAsHtml(int $waitTimeInSecondToComplete = 0): HttpResponse
156    {
157        return $this->fetch()->executeBodyAsHtmlPage($waitTimeInSecondToComplete);
158    }
159
160
161}
162