Доступ к Slim framework в ваших собственных классах

#php #slim

#php #тонкий

Вопрос:

Я использую Slim Framework версии 3.

Я следовал руководству по созданию приложения. Частично это включает в себя настройку classes каталога, в который вы можете поместить свои собственные классы PHP.

Чего я не могу понять, так это как вы можете получить доступ к Slim внутри них. Например, если у меня есть класс src/classes/Users.php и я хотел использовать тонкий код ответа, например

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

Очевидно, $response , на данный момент недоступен. Кажется, что это только в index.php где каждый обратный вызов получает его в качестве аргумента.

Должен ли я передавать что-то каждому конструктору моих собственных классов, или операторам use or require в моих классах?

Комментарии:

1. Вы должны передавать все, что вам нужно, в свои классы, подробнее о внедрении зависимостей: phptherightway.com/#dependency_injection

2. @JimL Спасибо за ссылку, но мне нужны конкретные указания по выполнению этого, а не только теория. В основном все, что я пытаюсь сделать, это использовать объект ответа (или как вы его называете) в моем Users.php класс. Я не знаю, что передать в мой класс или куда.

Ответ №1:

Я бы сказал, когда компонентам уровня домена требуется доступ к компонентам уровня приложения — это запах кода. Итак, подумайте о том, чтобы поступить иначе, объект запроса описывает запрос. Запрос содержит некоторые данные, и эти данные должны быть переданы вашему User классу, а не самому объекту запроса.

Если вы все еще хотите использовать Request объект в Users классе, просто передайте его в качестве аргумента, вот так:

 // 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(
        PsrHttpMessageServerRequestInterface $request,
        PsrHttpMessageResponseInterface $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);
    }
}
  

Однако в этом случае ваш User класс сильно связан с объектами запроса и ответа PSR-7. Иногда соединение не является проблемой, но в вашем случае User класс принадлежит к уровню домена (поскольку он описывает пользовательскую сущность), в то время как $request и $response являются компонентами уровня приложения.

Попробуйте уменьшить сцепление:

 $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;
    }
}
  

Видите преимущество? User::hydrateAndPersist теперь принимает array в качестве аргумента, он не знает о $request и $response . Таким образом, он не привязан к HTTP ( PSR-7 описывает HTTP-сообщения), он может работать с чем угодно. Классы разделены, слои разделены, простота обслуживания.

Подводя итог: вы можете получить доступ к $request объекту в вашем User классе, просто перейдя $request к одному из User методов. Однако это плохой дизайн, который снизит удобство сопровождения вашего кода.