Как использовать ответы PSR-7?

Большинство ответов в моем приложении представляют собой либо представления, либо JSON. Я не могу понять, как поместить их в объекты, реализующие ResponseInterface в PSR-7.

Вот что я сейчас делаю:

// Views
header('Content-Type: text/html; charset=utf-8');
header('Content-Language: en-CA');
echo $twig->render('foo.html.twig', array(
    'param' => 'value'
    /* ... */
));

// JSON
header('Content-Type: application/json; charset=utf-8');
echo json_encode($foo);

Вот что я пытаюсь сделать с PSR-7:

// Views
$response = new Http\Response(200, array(
    'Content-Type' => 'text/html; charset=utf-8',
    'Content-Language' => 'en-CA'
));

// what to do here to put the Twig output in the response??

foreach ($response->getHeaders() as $k => $values) {
    foreach ($values as $v) {
        header(sprintf('%s: %s', $k, $v), false);
    }
}
echo (string) $response->getBody();

И я полагаю, что это будет похоже на ответ JSON, только с другими заголовками. Насколько я понимаю, тело сообщения представляет собой StreamInterface и это работает, когда я пытаюсь вывести файловый ресурс, созданный с помощью fopen, но как мне это сделать со строками?

Обновить

Http\Response в моем коде на самом деле является моей собственной реализацией ResponseInterface в PSR-7. Я реализовал все интерфейсы, поскольку в настоящее время я застрял на PHP 5.3, и я не смог найти никаких реализаций, совместимых с PHP ‹ 5.4. Вот конструктор Http\Response:

public function __construct($code = 200, array $headers = array()) {
    if (!in_array($code, static::$validCodes, true)) {
        throw new \InvalidArgumentException('Invalid HTTP status code');
    }

    parent::__construct($headers);
    $this->code = $code;
}

Я могу изменить свою реализацию, чтобы принимать вывод в качестве аргумента конструктора, или же я могу использовать метод withBody реализации MessageInterface. Независимо от того, как я это делаю, проблема заключается в том, как поместить строку в поток.


person rink.attendant.6    schedule 22.11.2015    source источник


Ответы (1)


ResponseInterface расширяет MessageInterface, который предоставляет найденный вами геттер getBody(). PSR-7 предполагает, что объект, реализующий ResponseInterface, будет неизменяемым, чего вы не сможете добиться, не изменив свой конструктор.

Поскольку вы используете PHP ‹ 5.4 (и не можете эффективно использовать подсказки), измените его следующим образом:

public function __construct($code = 200, array $headers = array(), $content='') {
  if (!in_array($code, static::$validCodes, true)) {
    throw new \InvalidArgumentException('Invalid HTTP status code');
  }

  parent::__construct($headers);
  $this->code = $code;
  $this->content = (string) $content;
}

Определите закрытый член $content следующим образом:

private $content = '';

И геттер:

public function getBody() {
  return $this->content;
}

И вы готовы идти!

person Sébastien Renauld    schedule 22.11.2015
comment
Я не использую Slim, и Http\Response на самом деле является моей собственной реализацией ResponseInterface (конструктор принимает два параметра). Я реализовал метод withBody в MessageInterface, но он принимает StreamInterface в качестве параметра, поэтому та же проблема остается с созданием потока строки. Я могу изменить свою реализацию ResponseInterface, чтобы принять строку $body, но я не знаю, как это реализовать... - person rink.attendant.6; 22.11.2015
comment
@rink.attendant.6: Тогда, очевидно, вам нужно реализовать установщик для тела или аргумента конструктора. Поскольку согласно PSR-7 все объекты ответа должны быть неизменяемыми, это должен быть аргумент конструктора. Можете ли вы опубликовать свой код для объекта Response? Я отредактирую свой ответ позже. - person Sébastien Renauld; 22.11.2015
comment
Я обновил вопрос с помощью конструктора объекта Response. Помимо метода проверки правильности кода, он имеет самый минимум для реализации трех методов в интерфейсе. - person rink.attendant.6; 22.11.2015
comment
Это работает... но разве я не должен возвращать StreamInterface с getBody()? По крайней мере, я ожидал бы, что подкласс, который переопределяет метод, вернет объект, совместимый с этим интерфейсом. - person rink.attendant.6; 22.11.2015
comment
@rink.attendant.6: Если вы хотите зайти так далеко, получите интерфейс StreamInterface. Это не помещается в комментарий, поэтому я отредактирую снова. Однако в большинстве случаев основные фреймворки в настоящее время действительно используют только __toString(). - person Sébastien Renauld; 22.11.2015
comment
Сначала вы должны получить тело ответа $body = $response->getBody();, написать все, что вам нужно, в тело сообщения $body->write('only string content here');. Не забудьте добавить поток обратно в ответ $response->withBody($body);. - person David Cery; 06.01.2017