Subversion-Projekte lars-tiefland.laravel_shop

Revision

Zur aktuellen Revision | Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
148 lars 1
<?php
2
 
3
namespace Illuminate\Foundation\Testing\Concerns;
4
 
5
use Illuminate\Contracts\Http\Kernel as HttpKernel;
6
use Illuminate\Cookie\CookieValuePrefix;
7
use Illuminate\Http\Request;
8
use Illuminate\Testing\LoggedExceptionCollection;
9
use Illuminate\Testing\TestResponse;
10
use Symfony\Component\HttpFoundation\File\UploadedFile as SymfonyUploadedFile;
11
use Symfony\Component\HttpFoundation\Request as SymfonyRequest;
12
 
13
trait MakesHttpRequests
14
{
15
    /**
16
     * Additional headers for the request.
17
     *
18
     * @var array
19
     */
20
    protected $defaultHeaders = [];
21
 
22
    /**
23
     * Additional cookies for the request.
24
     *
25
     * @var array
26
     */
27
    protected $defaultCookies = [];
28
 
29
    /**
30
     * Additional cookies will not be encrypted for the request.
31
     *
32
     * @var array
33
     */
34
    protected $unencryptedCookies = [];
35
 
36
    /**
37
     * Additional server variables for the request.
38
     *
39
     * @var array
40
     */
41
    protected $serverVariables = [];
42
 
43
    /**
44
     * Indicates whether redirects should be followed.
45
     *
46
     * @var bool
47
     */
48
    protected $followRedirects = false;
49
 
50
    /**
51
     * Indicates whether cookies should be encrypted.
52
     *
53
     * @var bool
54
     */
55
    protected $encryptCookies = true;
56
 
57
    /**
58
     * Indicated whether JSON requests should be performed "with credentials" (cookies).
59
     *
60
     * @see https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/withCredentials
61
     *
62
     * @var bool
63
     */
64
    protected $withCredentials = false;
65
 
66
    /**
67
     * The latest test response (if any).
68
     *
69
     * @var \Illuminate\Testing\TestResponse|null
70
     */
71
    public static $latestResponse;
72
 
73
    /**
74
     * Define additional headers to be sent with the request.
75
     *
76
     * @param  array  $headers
77
     * @return $this
78
     */
79
    public function withHeaders(array $headers)
80
    {
81
        $this->defaultHeaders = array_merge($this->defaultHeaders, $headers);
82
 
83
        return $this;
84
    }
85
 
86
    /**
87
     * Add a header to be sent with the request.
88
     *
89
     * @param  string  $name
90
     * @param  string  $value
91
     * @return $this
92
     */
93
    public function withHeader(string $name, string $value)
94
    {
95
        $this->defaultHeaders[$name] = $value;
96
 
97
        return $this;
98
    }
99
 
100
    /**
101
     * Add an authorization token for the request.
102
     *
103
     * @param  string  $token
104
     * @param  string  $type
105
     * @return $this
106
     */
107
    public function withToken(string $token, string $type = 'Bearer')
108
    {
109
        return $this->withHeader('Authorization', $type.' '.$token);
110
    }
111
 
112
    /**
113
     * Remove the authorization token from the request.
114
     *
115
     * @return $this
116
     */
117
    public function withoutToken()
118
    {
119
        unset($this->defaultHeaders['Authorization']);
120
 
121
        return $this;
122
    }
123
 
124
    /**
125
     * Flush all the configured headers.
126
     *
127
     * @return $this
128
     */
129
    public function flushHeaders()
130
    {
131
        $this->defaultHeaders = [];
132
 
133
        return $this;
134
    }
135
 
136
    /**
137
     * Define a set of server variables to be sent with the requests.
138
     *
139
     * @param  array  $server
140
     * @return $this
141
     */
142
    public function withServerVariables(array $server)
143
    {
144
        $this->serverVariables = $server;
145
 
146
        return $this;
147
    }
148
 
149
    /**
150
     * Disable middleware for the test.
151
     *
152
     * @param  string|array|null  $middleware
153
     * @return $this
154
     */
155
    public function withoutMiddleware($middleware = null)
156
    {
157
        if (is_null($middleware)) {
158
            $this->app->instance('middleware.disable', true);
159
 
160
            return $this;
161
        }
162
 
163
        foreach ((array) $middleware as $abstract) {
164
            $this->app->instance($abstract, new class
165
            {
166
                public function handle($request, $next)
167
                {
168
                    return $next($request);
169
                }
170
            });
171
        }
172
 
173
        return $this;
174
    }
175
 
176
    /**
177
     * Enable the given middleware for the test.
178
     *
179
     * @param  string|array|null  $middleware
180
     * @return $this
181
     */
182
    public function withMiddleware($middleware = null)
183
    {
184
        if (is_null($middleware)) {
185
            unset($this->app['middleware.disable']);
186
 
187
            return $this;
188
        }
189
 
190
        foreach ((array) $middleware as $abstract) {
191
            unset($this->app[$abstract]);
192
        }
193
 
194
        return $this;
195
    }
196
 
197
    /**
198
     * Define additional cookies to be sent with the request.
199
     *
200
     * @param  array  $cookies
201
     * @return $this
202
     */
203
    public function withCookies(array $cookies)
204
    {
205
        $this->defaultCookies = array_merge($this->defaultCookies, $cookies);
206
 
207
        return $this;
208
    }
209
 
210
    /**
211
     * Add a cookie to be sent with the request.
212
     *
213
     * @param  string  $name
214
     * @param  string  $value
215
     * @return $this
216
     */
217
    public function withCookie(string $name, string $value)
218
    {
219
        $this->defaultCookies[$name] = $value;
220
 
221
        return $this;
222
    }
223
 
224
    /**
225
     * Define additional cookies will not be encrypted before sending with the request.
226
     *
227
     * @param  array  $cookies
228
     * @return $this
229
     */
230
    public function withUnencryptedCookies(array $cookies)
231
    {
232
        $this->unencryptedCookies = array_merge($this->unencryptedCookies, $cookies);
233
 
234
        return $this;
235
    }
236
 
237
    /**
238
     * Add a cookie will not be encrypted before sending with the request.
239
     *
240
     * @param  string  $name
241
     * @param  string  $value
242
     * @return $this
243
     */
244
    public function withUnencryptedCookie(string $name, string $value)
245
    {
246
        $this->unencryptedCookies[$name] = $value;
247
 
248
        return $this;
249
    }
250
 
251
    /**
252
     * Automatically follow any redirects returned from the response.
253
     *
254
     * @return $this
255
     */
256
    public function followingRedirects()
257
    {
258
        $this->followRedirects = true;
259
 
260
        return $this;
261
    }
262
 
263
    /**
264
     * Include cookies and authorization headers for JSON requests.
265
     *
266
     * @return $this
267
     */
268
    public function withCredentials()
269
    {
270
        $this->withCredentials = true;
271
 
272
        return $this;
273
    }
274
 
275
    /**
276
     * Disable automatic encryption of cookie values.
277
     *
278
     * @return $this
279
     */
280
    public function disableCookieEncryption()
281
    {
282
        $this->encryptCookies = false;
283
 
284
        return $this;
285
    }
286
 
287
    /**
288
     * Set the referer header and previous URL session value in order to simulate a previous request.
289
     *
290
     * @param  string  $url
291
     * @return $this
292
     */
293
    public function from(string $url)
294
    {
295
        $this->app['session']->setPreviousUrl($url);
296
 
297
        return $this->withHeader('referer', $url);
298
    }
299
 
300
    /**
301
     * Visit the given URI with a GET request.
302
     *
303
     * @param  string  $uri
304
     * @param  array  $headers
305
     * @return \Illuminate\Testing\TestResponse
306
     */
307
    public function get($uri, array $headers = [])
308
    {
309
        $server = $this->transformHeadersToServerVars($headers);
310
        $cookies = $this->prepareCookiesForRequest();
311
 
312
        return $this->call('GET', $uri, [], $cookies, [], $server);
313
    }
314
 
315
    /**
316
     * Visit the given URI with a GET request, expecting a JSON response.
317
     *
318
     * @param  string  $uri
319
     * @param  array  $headers
320
     * @return \Illuminate\Testing\TestResponse
321
     */
322
    public function getJson($uri, array $headers = [])
323
    {
324
        return $this->json('GET', $uri, [], $headers);
325
    }
326
 
327
    /**
328
     * Visit the given URI with a POST request.
329
     *
330
     * @param  string  $uri
331
     * @param  array  $data
332
     * @param  array  $headers
333
     * @return \Illuminate\Testing\TestResponse
334
     */
335
    public function post($uri, array $data = [], array $headers = [])
336
    {
337
        $server = $this->transformHeadersToServerVars($headers);
338
        $cookies = $this->prepareCookiesForRequest();
339
 
340
        return $this->call('POST', $uri, $data, $cookies, [], $server);
341
    }
342
 
343
    /**
344
     * Visit the given URI with a POST request, expecting a JSON response.
345
     *
346
     * @param  string  $uri
347
     * @param  array  $data
348
     * @param  array  $headers
349
     * @return \Illuminate\Testing\TestResponse
350
     */
351
    public function postJson($uri, array $data = [], array $headers = [])
352
    {
353
        return $this->json('POST', $uri, $data, $headers);
354
    }
355
 
356
    /**
357
     * Visit the given URI with a PUT request.
358
     *
359
     * @param  string  $uri
360
     * @param  array  $data
361
     * @param  array  $headers
362
     * @return \Illuminate\Testing\TestResponse
363
     */
364
    public function put($uri, array $data = [], array $headers = [])
365
    {
366
        $server = $this->transformHeadersToServerVars($headers);
367
        $cookies = $this->prepareCookiesForRequest();
368
 
369
        return $this->call('PUT', $uri, $data, $cookies, [], $server);
370
    }
371
 
372
    /**
373
     * Visit the given URI with a PUT request, expecting a JSON response.
374
     *
375
     * @param  string  $uri
376
     * @param  array  $data
377
     * @param  array  $headers
378
     * @return \Illuminate\Testing\TestResponse
379
     */
380
    public function putJson($uri, array $data = [], array $headers = [])
381
    {
382
        return $this->json('PUT', $uri, $data, $headers);
383
    }
384
 
385
    /**
386
     * Visit the given URI with a PATCH request.
387
     *
388
     * @param  string  $uri
389
     * @param  array  $data
390
     * @param  array  $headers
391
     * @return \Illuminate\Testing\TestResponse
392
     */
393
    public function patch($uri, array $data = [], array $headers = [])
394
    {
395
        $server = $this->transformHeadersToServerVars($headers);
396
        $cookies = $this->prepareCookiesForRequest();
397
 
398
        return $this->call('PATCH', $uri, $data, $cookies, [], $server);
399
    }
400
 
401
    /**
402
     * Visit the given URI with a PATCH request, expecting a JSON response.
403
     *
404
     * @param  string  $uri
405
     * @param  array  $data
406
     * @param  array  $headers
407
     * @return \Illuminate\Testing\TestResponse
408
     */
409
    public function patchJson($uri, array $data = [], array $headers = [])
410
    {
411
        return $this->json('PATCH', $uri, $data, $headers);
412
    }
413
 
414
    /**
415
     * Visit the given URI with a DELETE request.
416
     *
417
     * @param  string  $uri
418
     * @param  array  $data
419
     * @param  array  $headers
420
     * @return \Illuminate\Testing\TestResponse
421
     */
422
    public function delete($uri, array $data = [], array $headers = [])
423
    {
424
        $server = $this->transformHeadersToServerVars($headers);
425
        $cookies = $this->prepareCookiesForRequest();
426
 
427
        return $this->call('DELETE', $uri, $data, $cookies, [], $server);
428
    }
429
 
430
    /**
431
     * Visit the given URI with a DELETE request, expecting a JSON response.
432
     *
433
     * @param  string  $uri
434
     * @param  array  $data
435
     * @param  array  $headers
436
     * @return \Illuminate\Testing\TestResponse
437
     */
438
    public function deleteJson($uri, array $data = [], array $headers = [])
439
    {
440
        return $this->json('DELETE', $uri, $data, $headers);
441
    }
442
 
443
    /**
444
     * Visit the given URI with an OPTIONS request.
445
     *
446
     * @param  string  $uri
447
     * @param  array  $data
448
     * @param  array  $headers
449
     * @return \Illuminate\Testing\TestResponse
450
     */
451
    public function options($uri, array $data = [], array $headers = [])
452
    {
453
        $server = $this->transformHeadersToServerVars($headers);
454
 
455
        $cookies = $this->prepareCookiesForRequest();
456
 
457
        return $this->call('OPTIONS', $uri, $data, $cookies, [], $server);
458
    }
459
 
460
    /**
461
     * Visit the given URI with an OPTIONS request, expecting a JSON response.
462
     *
463
     * @param  string  $uri
464
     * @param  array  $data
465
     * @param  array  $headers
466
     * @return \Illuminate\Testing\TestResponse
467
     */
468
    public function optionsJson($uri, array $data = [], array $headers = [])
469
    {
470
        return $this->json('OPTIONS', $uri, $data, $headers);
471
    }
472
 
473
    /**
474
     * Visit the given URI with a HEAD request.
475
     *
476
     * @param  string  $uri
477
     * @param  array  $headers
478
     * @return \Illuminate\Testing\TestResponse
479
     */
480
    public function head($uri, array $headers = [])
481
    {
482
        $server = $this->transformHeadersToServerVars($headers);
483
 
484
        $cookies = $this->prepareCookiesForRequest();
485
 
486
        return $this->call('HEAD', $uri, [], $cookies, [], $server);
487
    }
488
 
489
    /**
490
     * Call the given URI with a JSON request.
491
     *
492
     * @param  string  $method
493
     * @param  string  $uri
494
     * @param  array  $data
495
     * @param  array  $headers
496
     * @return \Illuminate\Testing\TestResponse
497
     */
498
    public function json($method, $uri, array $data = [], array $headers = [])
499
    {
500
        $files = $this->extractFilesFromDataArray($data);
501
 
502
        $content = json_encode($data);
503
 
504
        $headers = array_merge([
505
            'CONTENT_LENGTH' => mb_strlen($content, '8bit'),
506
            'CONTENT_TYPE' => 'application/json',
507
            'Accept' => 'application/json',
508
        ], $headers);
509
 
510
        return $this->call(
511
            $method,
512
            $uri,
513
            [],
514
            $this->prepareCookiesForJsonRequest(),
515
            $files,
516
            $this->transformHeadersToServerVars($headers),
517
            $content
518
        );
519
    }
520
 
521
    /**
522
     * Call the given URI and return the Response.
523
     *
524
     * @param  string  $method
525
     * @param  string  $uri
526
     * @param  array  $parameters
527
     * @param  array  $cookies
528
     * @param  array  $files
529
     * @param  array  $server
530
     * @param  string|null  $content
531
     * @return \Illuminate\Testing\TestResponse
532
     */
533
    public function call($method, $uri, $parameters = [], $cookies = [], $files = [], $server = [], $content = null)
534
    {
535
        $kernel = $this->app->make(HttpKernel::class);
536
 
537
        $files = array_merge($files, $this->extractFilesFromDataArray($parameters));
538
 
539
        $symfonyRequest = SymfonyRequest::create(
540
            $this->prepareUrlForRequest($uri), $method, $parameters,
541
            $cookies, $files, array_replace($this->serverVariables, $server), $content
542
        );
543
 
544
        $response = $kernel->handle(
545
            $request = Request::createFromBase($symfonyRequest)
546
        );
547
 
548
        $kernel->terminate($request, $response);
549
 
550
        if ($this->followRedirects) {
551
            $response = $this->followRedirects($response);
552
        }
553
 
554
        return static::$latestResponse = $this->createTestResponse($response);
555
    }
556
 
557
    /**
558
     * Turn the given URI into a fully qualified URL.
559
     *
560
     * @param  string  $uri
561
     * @return string
562
     */
563
    protected function prepareUrlForRequest($uri)
564
    {
565
        if (str_starts_with($uri, '/')) {
566
            $uri = substr($uri, 1);
567
        }
568
 
569
        return trim(url($uri), '/');
570
    }
571
 
572
    /**
573
     * Transform headers array to array of $_SERVER vars with HTTP_* format.
574
     *
575
     * @param  array  $headers
576
     * @return array
577
     */
578
    protected function transformHeadersToServerVars(array $headers)
579
    {
580
        return collect(array_merge($this->defaultHeaders, $headers))->mapWithKeys(function ($value, $name) {
581
            $name = strtr(strtoupper($name), '-', '_');
582
 
583
            return [$this->formatServerHeaderKey($name) => $value];
584
        })->all();
585
    }
586
 
587
    /**
588
     * Format the header name for the server array.
589
     *
590
     * @param  string  $name
591
     * @return string
592
     */
593
    protected function formatServerHeaderKey($name)
594
    {
595
        if (! str_starts_with($name, 'HTTP_') && $name !== 'CONTENT_TYPE' && $name !== 'REMOTE_ADDR') {
596
            return 'HTTP_'.$name;
597
        }
598
 
599
        return $name;
600
    }
601
 
602
    /**
603
     * Extract the file uploads from the given data array.
604
     *
605
     * @param  array  $data
606
     * @return array
607
     */
608
    protected function extractFilesFromDataArray(&$data)
609
    {
610
        $files = [];
611
 
612
        foreach ($data as $key => $value) {
613
            if ($value instanceof SymfonyUploadedFile) {
614
                $files[$key] = $value;
615
 
616
                unset($data[$key]);
617
            }
618
 
619
            if (is_array($value)) {
620
                $files[$key] = $this->extractFilesFromDataArray($value);
621
 
622
                $data[$key] = $value;
623
            }
624
        }
625
 
626
        return $files;
627
    }
628
 
629
    /**
630
     * If enabled, encrypt cookie values for request.
631
     *
632
     * @return array
633
     */
634
    protected function prepareCookiesForRequest()
635
    {
636
        if (! $this->encryptCookies) {
637
            return array_merge($this->defaultCookies, $this->unencryptedCookies);
638
        }
639
 
640
        return collect($this->defaultCookies)->map(function ($value, $key) {
641
            return encrypt(CookieValuePrefix::create($key, app('encrypter')->getKey()).$value, false);
642
        })->merge($this->unencryptedCookies)->all();
643
    }
644
 
645
    /**
646
     * If enabled, add cookies for JSON requests.
647
     *
648
     * @return array
649
     */
650
    protected function prepareCookiesForJsonRequest()
651
    {
652
        return $this->withCredentials ? $this->prepareCookiesForRequest() : [];
653
    }
654
 
655
    /**
656
     * Follow a redirect chain until a non-redirect is received.
657
     *
658
     * @param  \Illuminate\Http\Response  $response
659
     * @return \Illuminate\Http\Response|\Illuminate\Testing\TestResponse
660
     */
661
    protected function followRedirects($response)
662
    {
663
        $this->followRedirects = false;
664
 
665
        while ($response->isRedirect()) {
666
            $response = $this->get($response->headers->get('Location'));
667
        }
668
 
669
        return $response;
670
    }
671
 
672
    /**
673
     * Create the test response instance from the given response.
674
     *
675
     * @param  \Illuminate\Http\Response  $response
676
     * @return \Illuminate\Testing\TestResponse
677
     */
678
    protected function createTestResponse($response)
679
    {
680
        return tap(TestResponse::fromBaseResponse($response), function ($response) {
681
            $response->withExceptions(
682
                $this->app->bound(LoggedExceptionCollection::class)
683
                    ? $this->app->make(LoggedExceptionCollection::class)
684
                    : new LoggedExceptionCollection
685
            );
686
        });
687
    }
688
}