Nyholm / psr7

A super lightweight PSR-7 implementation
MIT License
1.16k stars 75 forks source link

Psr17Factory does not construct ServerRequest with body? #128

Closed burzum closed 4 years ago

burzum commented 5 years ago

Why is https://github.com/Nyholm/psr7/blob/master/src/Factory/Psr17Factory.php#L69 the factory not initialized with the body?

I figured out that there is a separate package (Nyholm\Psr7Server). OK, But why!?

Now I have to add another dependency and I basically have to copy and paste the code from the docs into my own ServerRequestFactory? Why?

I had the hope to just use this package and start off with a working server request by using the factory included in this package.

<?php
declare(strict_types=1);

namespace App\Infrastructure\Http;

use Nyholm\Psr7\Factory\Psr17Factory;
use Nyholm\Psr7\ServerRequest;
use Nyholm\Psr7Server\ServerRequestCreator;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestFactoryInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\UriInterface;

class ServerRequestFactory implements ServerRequestFactoryInterface
{
    public function createServerRequest(string $method, $uri, array $serverParams = []): ServerRequestInterface
    {
        $psr17Factory = new Psr17Factory();

        $creator = new ServerRequestCreator(
            $psr17Factory, // ServerRequestFactory
            $psr17Factory, // UriFactory
            $psr17Factory, // UploadedFileFactory
            $psr17Factory  // StreamFactory
        );

        return $creator->fromGlobals();
    }
}
Zegnat commented 4 years ago

Now I have to add another dependency and I basically have to copy and paste the code from the docs into my own ServerRequestFactory? Why?

This repo implements the PSR standards with as little extras as possible. PSR-17 only defines a method for creating a ServerRequest with its HTTP method, an URI, and a collection of parameters. There is no standard way of creating it with more than those things already set, so if one would be added here it could lead to incompatibilities between PSR-17 implementations.

In fact, the unit tests for PSR-17 HTTP Factories specifically include tests to make sure an implementation never reads the global server values. PSR-17 implementations are not allowed to do so.

This combines means the “correct” way to fill a ServerRequest object based on the current request that came to your webserver is to write your own code to do so. That is why psr7-server was written.

I hope I was able to shine some light on the situation for you! I am going to close this issue as it isn’t actually an issue with this library.

burzum commented 4 years ago

@Zegnat so what would be a proper, standard conform way of getting the body filled with the expected data of a POST request that would respect the PSR standards?

Zegnat commented 4 years ago

@burzum something like this:

// Pick your favourite PSR-17 factory, using Nyholm here:
$psr17Factory = new \Nyholm\Psr7\Factory\Psr17Factory();
// Create the ServerRequest with whatever parameters you have:
$serverRequest = $psr17Factory->createServerRequest($method, $uri, $serverParams)
// And add the value of $_POST:
    ->withParsedBody($_POST);

Although to be really fully standard conform, you have to do a whole bunch of checks before doing the withParsedBody() call. Even psr7-server may not be completely correct, see my PR over there with the extra checks that are needed. But in most cases it gets the job done right.

In part because of all these little small details did the PHP-FIG (makers of the PSR) not standardise a way to create a ServerRequest from an actual request. How to create this object depends completely on what server you have, what sort of context your application is running in, and more. So only you know how to fill a ServerRequest in the correct way.