Andy
Andy

Reputation: 5395

Accessing Slim framework in your own classes

I'm using Slim Framework version 3.

I've followed the tutorial on creating an app. Part of this involves setting up a classes directory where you can put your own PHP classes.

What I can't understand is how you can access Slim inside those. For example if I have a class src/classes/Users.php and wanted to use the Slim Response code e.g.

return $response->withStatus(302)->withHeader('Location', 'login');

Obviously, $response, is not accessible at that point. It only seems to be in index.php where each callback recieves it as an argument.

Do I have to pass something to every constructor of my own classes, or use or require statements in my classes?

Upvotes: 0

Views: 691

Answers (1)

Georgy Ivanov
Georgy Ivanov

Reputation: 1579

I'd say when domain layer components need to access application level components - this is a code smell. So, consider doing things otherwise, request object describes request. Request contains some data, and that data should be passed to your User class, not request object itself.

If you still wish to use Request object in Users class, simply pass it as argument, like this:

// in your routes
$app->post('users', function($request, $response) {
    $user = new User;
    $user->hydrateAndPersist($request); // there you pass it as argument
});

// in your user class
class User
{
    public function hydrateAndPersist(
        \Psr\Http\Message\ServerRequestInterface $request,
        \Psr\Http\Message\ResponseInterface $response // yes, you force yourself into injecting response object
    ) {
        // request is here, let's extract data from it
        $submittedData = $request->getParams();
        // terrible indeed, but this is just an example:
        foreach ($submittedData as $prop => $value) {
            $this->prop = $value;
        }
        $result = $this->save();
        return $response->withJson($result);
    }
}

However, in this case your User class is coupled heavily with PSR-7 request and response objects. Sometimes coupling is not a problem, but in your case User class belongs to domain layer (since it describes User entity), while $request and $response are components of application layer.

Try to reduce coupling:

$app->post('users', function($request, $response) {

    $submittedData = $request->getParams();

    $user = new User;
    $result = $user->hydrateAndPersist($submittedData);
    // response is already declared in this scope, let's "put" result of the operation into it
    $response = $response->withJson($result);
    return $response;
});

class User
{
    public function hydrateAndPersist(array $data) : bool
    {
        $result = false;
        foreach ($submittedData as $prop => $value) {
            $this->prop = $value;
        }
        $result = $this->save();
        return $result;
    }
}

See the benefit? User::hydrateAndPersist now accepts array as argument, it has no knowledge of $request and $response. So, it is not tied to HTTP (PSR-7 describes HTTP messages), it can work with anything. Classes separated, layers separated, ease of maintenance.

To sum up: you can access $request object in your User class by simply passing $request to one of User methods. However, this is poor design that will reduce maintainability of your code.

Upvotes: 1

Related Questions