Slim 4 Alpha Release Feedback

Created on 23 Apr 2019  路  50Comments  路  Source: slimphp/Slim

Slim 4 Alpha Release
See the full release notes

Before doing anything read the docs
I just finished the first draft of the docs for Slim 4 which are available here. I need feedback please:
http://dev.slimframework.com/docs/v4

Download an test the 4.0.0-alpha release
You may also play around with the 4.x branch and create a simple app with it to test things out.
composer require slim/slim:4.0.0-alpha

Install a PSR-7 Implementation
You will also need to install a PSR-7 implementation and ServerRequestCreator combo. You can use Slim's PSR-7 Implementation or choose one of the ones described on the 4.x branch README: https://github.com/slimphp/Slim/blob/4.x/README.md
composer require slim/psr7:dev-master

Slim 4 DDD API Skeleton Prototype
I also just created a Slim4 Skeleton with a DDD style directory structure with example files and test coverage for everything. I'm not sure if it's the right fit yet as it may be a bit too opinionated but I'd love some feedback:

git clone https://github.com/l0gicgate/Slim-Skeleton
git checkout 4.x

If you have any questions don't hesitate to ping me on Slack or ask questions in this thread directly, I'm available to help!

Slim 4 discussion

Most helpful comment

How about adding suggestions for the PSR-7 implementations mentioned in the README.md to composer.json?

{
    "suggest": {
        "slim/psr7": "This is the Slim Framework projects PSR-7 implementation.",
        ...
    }
}

See: https://getcomposer.org/doc/04-schema.md#suggest

All 50 comments

@l0gicgate Just a little nitpik:
The link to "contributing: Branching Strategy" on this page: http://slim-website.lgse.com/docs/v4/cookbook/uploading-files.html -- Links to version 3 (http://slim-website.lgse.com/docs/v3/contributors/strategy.html)

Good catch @RyanNerd! Fixed

@l0gicgate Version 3 has a Tutorial link with a guide to creating a "first application". Slim 4 with all the decoupling and _plug-in_ choices (PSR-7, Containers, Route & ErrorHandling as middleware, etc.) is much more complex than Slim 3. This can be overwhelming to someone new to Slim (and even those like myself that are familiar with version 3).
Perhaps the docs could include a Tutorial for v4 showing how to create a "first application" using bare bones concepts and the _plug-in_ defaults.

@RyanNerd I removed the tutorial from the v4 docs for now. It does need to be written and will be added to the docs later. In the mean time someone can look at the skeleton repository to see how things are implemented in a "real life" scenario.

I also think that a video tutorial would be much better. I just need time to get it done.

Install a PSR-7 Implementation
You will also need to install a PSR-7 implementation and ServerRequestCreator combo. You can use Slim's PSR-7 Implementation or choose one of the ones described on the 4.x branch README: https://github.com/slimphp/Slim/blob/4.x/README.md
composer slim/psr-7:dev-master

composer require slim/psr-7:dev-master 馃槈

Install a PSR-7 Implementation
You will also need to install a PSR-7 implementation and ServerRequestCreator combo. You can use Slim's PSR-7 Implementation or choose one of the ones described on the 4.x branch README: https://github.com/slimphp/Slim/blob/4.x/README.md
composer slim/psr-7:dev-master

composer require slim/psr-7:dev-master 馃槈

composer require slim/psr7:dev-master it's not "psr-7"

See if you can tell who didn't run it but commented anyway... 馃槅

@RyanNerd simply return a response object without calling $handler->handle($request)

It looks like ErrorHandler will only catch exceptions thrown from further down the middleware stack. What about exceptions/errors thrown before then, eg a misconfiguration throwing an exception when initializing everything? Would you just register methods within ErrorHandler to the PHP exception and error handlers via set_error_handler() and set_exception_handler() to handle those?

@davidbyoung I documented on how to handle all errors in the docs under Notices & Warnings handling. This shows a more advanced way of handling all errors. See http://dev.slimframework.com/docs/v4/objects/application.html#notices-and-warnings-handling

Note the "Edit this page" links in the documentation refer to something like:

https://github.com/slimphp/Slim-Website/tree/gh-pages/docs/v4/objects/routing.md

which does not exist, while

https://github.com/slimphp/Slim-Website/tree/gh-pages-4.x/docs/v4/objects/routing.md

Should I create an issue for this? Or is it expected "for now"... 馃槃

@holtkamp thanks for reporting this. It has to stay the same until I merge the gh-pages-4.x branch into gh-pages which won't be until Slim 4 is released. It'll have to stay broken for a bit 馃槀

In the documentation and the readme file, index.php refers to '/vendor/autoload.php'. This seems to suggest that the vendor directory should be placed within the public directory, where index.php lives. That seems pretty dangerous. Would it make sense to change to this to refer to __DIR__ . '/../vendor/autoload.php' instead?

How about adding suggestions for the PSR-7 implementations mentioned in the README.md to composer.json?

{
    "suggest": {
        "slim/psr7": "This is the Slim Framework projects PSR-7 implementation.",
        ...
    }
}

See: https://getcomposer.org/doc/04-schema.md#suggest

Hi, I have a question about default middleware implementation. But first I need to clear my understanding the idea abou using this framework. When I look at your setup of App, it seems like whole idea is setup app via DI, cause the factories etc., is that right? Second is about middleware, I get idea, like all is middleware so everything is implemented same way. But It seems like I need to setup everyting by myself, is it right conclusion? And at the end, wouldn't be better if basic middlewares, like RouteMiddleware and ErrorMiddleware has been setup automaticly?

@bednic the App can run without a container. It sure makes one鈥檚 life a lot easier to provide one though.

RoutingMiddleware is added by default if the user does not add it to the middleware queue. It will run last however, which means that the routing data won鈥檛 be available through the middleware stack if you have other middleware that depends on it.

As for ErrorMiddleware you need to place it at the outer most edge of your application (add it last, right before run, so it runs first) and we can鈥檛 automatically add it based on assumptions otherwise it wouldn鈥檛 behave correctly.

Hello.

Missing an example of using sessions with cookies

@danielspk I'm not sure exactly how to show an example of that since Slim doesn't handle sessions. That's typically something you'd implement via middleware or if you want sessions turned on at all times just use session_start() after the require __DIR__ . '/../vendor/autoload.php';

I can't get the middleware examples to work.
e.g.: http://dev.slimframework.com/docs/v4/concepts/middleware.html#application-middleware
From what I can tell, the 'BEFORE' middleware prevents the route from being called.. somehow.

EDIT: I've figured out how it works, but the example remains incredibly confusing. As far as I can tell there's no way to write to the body in middleware _before_ the route does its thing.

Hi, I made a simple repository that uses travis-ci to automatically test the slim4 framework against multiple PSR-7 implementations. See https://github.com/adriansuter/Slim4-CI

Currently, all are working fine!

Awesome @adriansuter thank you. You should join our Slack so we can chat

I'm having trouble with POST requests always returning null for getParsedBody()
I'm testing using Insomnia POST payload like {"test":"test"}

Here's the code:

<?php
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Slim\Factory\AppFactory;
use Slim\Middleware\ErrorMiddleware;
use Slim\Middleware\RoutingMiddleware;

require __DIR__ . '/vendor/autoload.php';

$app = AppFactory::create();

// Add Routing Middleware
$routeResolver = $app->getRouteResolver();
$routingMiddleware = new RoutingMiddleware($routeResolver);
$app->add($routingMiddleware);

// Error middleware
$callableResolver = $app->getCallableResolver();
$responseFactory = $app->getResponseFactory();
$errorMiddleware = new ErrorMiddleware($callableResolver, $responseFactory, true, true, true);
$app->add($errorMiddleware);

// Define app routes
$app->post('/posttest', function (Request $request, Response $response, $args) {
    $content = $request->getParsedBody();
    if ($content === null) {
          $response->getBody()->write('Error no JSON in request body or something else?!?!?!?!?');
    } else {
        $response->getBody()->write('getParsedBody() actually worked');
    }
    return $response;
});

// Run app
$app->run();

@RyanNerd - parsedBody gets populated with $_POST, but in PHP you have to get JSON data from php://input
As far as I can tell there's no method in Slim to retrieve JSON, so you'll have to do it manually I guess.

@RyanNerd maybe related to this:

https://github.com/slimphp/Slim-Psr7/issues/38, which is fixed already.

When doing your POST request, what headers are sent in the request?

@holtkamp These are the headers ($request->getHeaders()):

Host: localhost
User-Agent: insomnia/6.4.2
Content-Type: application/json
Accept: */*
Content-Length: 135 

The Content-Length matches _exactly_ to the test JSON I sent as a request. Not sure what is going on here?!? What's interesting is if I do $content = file_get_contents('php://input'); then the POST body is assigned to $content as a string. I suspect that somewhere in the Slim code 'php://input' is missing...

Try running the code yourself and see if you get the same results. Here's the composer.json I am using:

{
    "minimum-stability": "dev",
    "require": {
        "slim/slim": "4.0.0-alpha@dev",
        "slim/psr7": "dev-master"
    }
}

In terminal:

composer install
 php -S localhost:8080

Fire up either PostMan or Insomnia endpoint: localhost:8088/posttest
POST request (any valid JSON) and the getParsedBody() will return a null every time.

@Serdan The docs state differently :

Every HTTP request has a body. If you are building a Slim application that consumes JSON or XML data, you can use the PSR-7 Request object鈥檚 getParsedBody() method to parse the HTTP request body into a native PHP format. Slim can parse JSON, XML, and URL-encoded data out of the box.

$parsedBody = $request->getParsedBody();

@l0gicgate I think the docs need to be corrected. Not every HTTP request has a body (per the HTTP spec all requests MAY have a body),
For a GET request for example $request->getParsedBody() _should_ return a null if no body exists.

https://github.com/slimphp/Slim/issues/2653#issuecomment-490040007

To get parsed, I think the ContentType header in the POST request should contains something like:

  • application/x-www-form-urlencoded
  • multipart/form-data

Also see this line https://github.com/slimphp/Slim-Psr7/blob/bd3737bc6fe94d4ba30febe3aa7bc25d3f07f6ca/src/Factory/ServerRequestFactory.php#L105

@RyanNerd I need to update the docs for sure. Slim PSR-7 does not parse the body like Slim 3 used to. All that functionality has been moved over to Slim-Http. However you can write simple middleware to parse the body and append it to the incoming Request object.

In case of application/json content type, it's not valid $_POST data, hence why you can't retrieve it from there.

In order for actual form data to be parsed it needs to be a POST request and the Content-Type header needs to be application/x-www-form-urlencoded or multipart/form-data.

Note that this is very basic middleware and you could add more content types.

<?php

use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as RequestInterface;
use Psr\Http\Server\RequestHandlerInterface as RequestHandler;

class JsonBodyParserMiddleware implements MiddlewareInterface {
    public function process(Request $request, RequestHandler $handler): Response
    {
        $contentType = $request->getHeaderLine('Content-Type');

        if (strstr($contentType, 'application/json')) {
            $contents = json_decode(file_get_contents('php://input'));
            if (json_last_error() !== JSON_ERROR_NONE) {
                $request = $request->withParsedBody($contents);
            }
        }

        return $handler->handle($request);
    }
}

In any case, I will update the docs to remove the outdated portion of the docs about parsing the body.

Is there a release schedule of Slim's 4.x branch available?

Until when is Slim's 3.x branch planned to be maintained?

I'm about to start a new project and I'm hesitating between which branch to use for it.

@magikstm I don't know the scope of your project but I've started a new project using 4.x alpha and other than one misunderstanding (on my part, and partly because the docs were unclear) I've not had any issues.
One of the big differences between 3 and 4 is the amount of setup of middleware you need to have in place -- even the error handling is middleware (this is a good thing) just something to know going in: There's some configurations you need to set up in 4.x that were already in place with version 3.x.
Slim 4 is in alpha so there's a risk that things could change. I'm aware of this risk and that my project must _play along_ with Slim until it is production ready.
One of the reasons I decided to go this route (no pun intended) was to help test 4.x and post issues here as I came upon them.
Issues have mostly been with the documentation differing with how 3.x did things and not issues with the Slim 4.x app itself.
HTH

Question: Is there a performance or other advantages to have a middleware class implements MiddlewareInterface as opposed to using the __invoke() method?

@magikstm the 4.x branch is pretty stable despite being in alpha. I'd go with Slim 4 if you're starting a new project.

@RyanNerd no significant difference between the two.

As @Serdan mentioned already, the example code in the documentation is not working as expected.

I can't get the middleware examples to work.
e.g.: http://dev.slimframework.com/docs/v4/concepts/middleware.html#application-middleware
From what I can tell, the 'BEFORE' middleware prevents the route from being called.. somehow.

EDIT: I've figured out how it works, but the example remains incredibly confusing. As far as I can tell there's no way to write to the body in middleware _before_ the route does its thing.

I just created an issue for that. https://github.com/slimphp/Slim-Website/issues/356

I would like to ask Slim 4.x support Doctrine ORM?

@engineer-log you can use Doctrine ORM, Eloquent, or any other persistence library alongside with Slim.

I was thinking what probably most of you are dealing with and I presume that most scenario is building some API, probably REST. Whole back-end based on SlimPHP maybe with Doctrine, maybe with Eloquent. I'm currently working on library for the API part. It's implementation of JSON API ,but annotation based. So if you are using Doctrine, you get my idea rly quick. So if is someone interested, I would appreciate every idea or help. It's my first library, so i don't know how to get feedback.

I don't know if this isn't too unpolite 馃, advertise my library here. But I'm using combo Slim + Doctrine + API some time, and I think maybe it will help someone. But if this doesn't belong here I will delete it and of course I'm sorry.

P.S.: Good work, this is most clean and straightforward framework I ever seen. I was searching for this kind of framework for a years! Thank you, all of you.馃憤

@bednic that's cool! I went through the README of your repo and I understand what you're doing. I'd like to see an example of a route with Slim 4 馃槃 you should put a skeleton repository together with Doctrine, Slim and your JSON API library!

Like @bednic I've been working on a framework as well called Willow.
Willow is a marriage between Slim 4 & Eloquent. Documentation is here.
Let me know what you think.

a bit off-topic (sorry), but @bednic: you check these libraries for usage with JSON-API by @kocsismate, very elegant and clean!

@holtkamp

a bit off-topic (sorry), but @bednic: you check these libraries for usage with JSON-API by @kocsismate, very elegant and clean!

That kind of library is the reason why I make my own. Almost in every library it's necessary to create some ResourceObject, then gather all attributes and relationships, pass them to object, or schema and then serialize object to valid JSON. My library map all attributes and relationships by annotations, same as Doctrine. I'm gathering most of needed informations by reflection. If you are writing code standardized like object with private props with getters and setters, then I don't need anything else and just make valid JSON-API document for you from your object(s). It's much less writing.

HomeController:

class HomeController
{
    public function __construct()
    {
        $renderer = new \Slim\Views\PhpRenderer();
        // other codes...
        return $renderer;
    }

    public function index(Request $request, Response $response, $args): Response
    {
        return $this->renderer->render([$response], 'index.phtml');
    }
    // other functions...
}
  • The [$response] is expected to be $response.

Middleware:

$callableResolver = $app->getCallableResolver();
$responseFactory = $app->getResponseFactory();
$errorMiddleware = new ErrorMiddleware($callableResolver, $responseFactory, false, false, false);
$handler = function ($request, $exception, $displayErrorDetails, $logErrors, $logErrorDetails) {
    $code = $exception->getCode();
    $response = new Slim\Psr7\Response();
    switch ($code) {
        case 404:
            return $response->withHeader('Location', '/404')->withStatus(302);
        case 405:
            return $response->withHeader('Location', '/405')->withStatus(302);
        case 500:
            return $response->withHeader('Location', '/500')->withStatus(302);
    }
};
$errorMiddleware->setDefaultErrorHandler($handler);
$app->add($errorMiddleware);

Route:

$app->get('/', \HomeController::class . ':index');

I expected to get a Slim 500 error with details and trace.
But i actually got...

Fatal error:  Uncaught TypeError: Return value of Slim/Middleware/ErrorMiddleware::handleException() must implement interface Psr/Http/Message/ResponseInterface, null returned in /path/vendor/slim/slim/Slim/Middleware/ErrorMiddleware.php:109
Stack trace:
#0 /path/vendor/slim/slim/Slim/Middleware/ErrorMiddleware.php(91): Slim/Middleware/ErrorMiddleware->handleException(Object(Slim/Psr7/Request), Object(TypeError))
#1 /path/vendor/slim/slim/Slim/MiddlewareDispatcher.php(123): Slim/Middleware/ErrorMiddleware->process(Object(Slim/Psr7/Request), Object(class@anonymous))
#2 /path/vendor/slim/slim/Slim/MiddlewareDispatcher.php(64): class@anonymous->handle(Object(Slim/Psr7/Request))
#3 /path/vendor/slim/slim/Slim/App.php(136): Slim/MiddlewareDispatcher->handle(Object(Slim/Psr7/Request))
#4 /path/vendor/slim/slim/Slim/App.php(120): in /path/vendor/slim/slim/Slim/Middleware/ErrorMiddleware.php on line 109

It might be problem with Eception::getCode(), maybe it's not Slim HttpException and therefore getCode might return 0, in which case return value from handler will be null.

Yeah..You are right...Sorry for my bother.

@SakuraSa233 hence why you should always handle default cases, this is a prime example of it.

Here is another question is that my Slim 3 code always get undefined method Slim\Psr7\Request::getParam() in Slim 4.

public function update($request, $response, $args)
{
    $data = $request->getParam('data');
    // ...
}

I have known that getParam() is in SlimHttp, how can I use it to adapt my project?

@SakuraSa233 do you have Slim-Http decorators installed?

Also you may need to require the 4.x branch right now instead of the 4.0.0-alpha pre-release since the automatic detection for Slim-Http decorators isn鈥檛 in the 4.0.0-alpha release.

Closing this. Follow thread in Slim 4 Beta Release Feedback Thread.

There is some mistake. The HTTP 200 status is returned with the middleware of the example and the HTTP 404 return code

`
$app->add(function (Request $request, RequestHandler $handler) {
$response = $handler->handle($request);
$existingContent = (string) $response->getBody();

$response = new Response();
$response->getBody()->write('BEFORE-' . $existingContent);
return $response;

});

$app->add(function (Request $request, RequestHandler $handler) {
$response = $handler->handle($request);
$response->getBody()->write('AFTER ');
return $response;
});

$app->get('/', function (Request $request, Response $response, $args) {

$response->getBody()->write('-Hello World  -');
//throw new Slim\Exception\HttpNotFoundException($request, "Product not found..."); // Does not work returns 200
return $response->withStatus(404); // <<<  Does not work returns 200
//return $response;

});

$app->run();

`

Was this page helpful?
0 / 5 - 0 ratings

Related issues

boosis picture boosis  路  25Comments

codeguy picture codeguy  路  43Comments

l0gicgate picture l0gicgate  路  27Comments

alexweissman picture alexweissman  路  38Comments

konskript picture konskript  路  62Comments