目次

Apricot レスポンスクラス

y2sunlight 2020-05-04

Apricot に戻る

関連記事

HTTPレスポンスには以下の3ケースがあります。

ここでは、正常レスポンスについて扱います。エラーレスポンスは集約例外ハンドラー経由で処理されます。


Responseクラス

Responseクラスはレスポンスのベースクラスで、その目的はHTMLヘッダーとフラッシュデータの管理です。後述の RenderResponse(レンダリング用) と RedirectResponse(リダイレクト用) はResponseクラスから派生します。Responseクラスは以下のメソッドを持ちます。

メソッド機能
addHeader($headers):ResponseHTMLヘッダーの追加
hasFlash(string $key):boolフラッシュデータの存在確認
addFlash(string $key, $value):Responseフラッシュデータの追加
commit(int $response_code=null)レスポンスの確定

/apricot/core/Foundation

Response.php
<?php
namespace Core\Foundation;
 
use Core\Session;
 
/**
 * Improvised Response Class
 */
class Response
{
    /**
     *
     * @var array
     */
    protected $headers = [];
 
    /**
     *
     * @var array
     */
    protected $flashes = [];
 
    /**
     * Flash key for old inputs
     */
    public const FLASH_KEY_OLD = '_old_inputs';
 
    /**
     * Flash key for old URL Path
     */
    public const FLASH_KEY_BACK = '_old_path';
 
    /**
     * Flash key for error bag
     */
    public const FLASH_KEY_ERRORS = 'errors';
 
    /**
     * Add a header
     * @param string|array $headers
     * @return Response
     */
    public function addHeader($headers):Response
    {
        $header_arr = is_array($headers) ? $headers : [$headers];
        foreach($header_arr as $header)
        {
            $this->headers[] = $header;
        }
        return $this;
    }
 
    /**
     * Check if a flash value is present
     * @param string $key
     * @return bool
     */
    public function hasFlash(string $key):bool
    {
        return array_key_exists($key, $this->flashes);
    }
 
    /**
     * Add a value to flash
     * @param string $key
     * @param mixed $value
     * @return Response
     */
    public function addFlash(string $key, $value):Response
    {
        $this->flashes[$key] = $value;
        return $this;
    }
 
    /**
     * Commit Response Data
     * @param int $response_code
     */
    public function commit(int $response_code=null)
    {
        // Set Http response code
        if (isset($response_code))
        {
            http_response_code($response_code);
        }
 
        // Output headers
        foreach($this->headers as $header)
        {
            header($header);
        }
 
        // Save old URL Path
        $this->addFlash(self::FLASH_KEY_BACK, $_SERVER['REQUEST_URI']);
 
        // Output flashes
        foreach($this->flashes as $key=>$value)
        {
            Session::flash()->set($key, $value);
        }
    }
}


RenderResponseクラス

RenderResponseクラスはResponseクラスから派生します。HTMLレンダリングを行うレスポンス用のクラスで、以下のメソッドを持ちます。addHeader()などのResponseクラスのメソッドも使用できます。

メソッド機能
__construct(string $html=null)RenderResponseの生成
setHtml(string $html=null):RenderResponseHTMLテキストの設定
commit(int $response_code=null)レスポンスの確定

/apricot/core/Foundation/Response

RenderResponse.php
<?php
namespace Core\Foundation\Response;
 
/*
 * Rendered Response Class
 */
class RenderResponse extends \Core\Foundation\Response
{
    /**
     * Html Data
     * @var string
     */
    private $html='';
 
    /**
     * Create RenderResponse
     * @param string $html
     * @param array $variables
     */
    public function __construct(string $html=null)
    {
        $this->setHtml($html);
    }
 
    /**
     * Set Html
     * @param string $html
     * @return RenderResponse
     */
    public function setHtml(string $html=null) : RenderResponse
    {
        if (isset($html)) $this->html = $html;
        return $this;
    }
 
    /**
     * commit
     * {@inheritDoc}
     * @see \Core\Foundation\Response::commit()
     */
    public function commit(int $response_code=null)
    {
        // headersに'Content-type'がなければ出力する
        $matchs= preg_grep('/^content-type.*?:/i', $this->headers);
        if(empty($matchs))
        {
            $this->addHeader("Content-type: text/html; charset=utf-8");
        }
 
        parent::commit($response_code);
 
        // HTMLのレンダリング
        echo $this->html;
        flush();
    }
}


RedirectResponseクラス

RedirectResponseクラスはResponseクラスから派生したリダイレクト用のクラスです。リダイレクトではフラッシュデータを使ってリダイレクト先のページにデータを送ることが多いので、フラッシュ用のメソッドが追加されています。RedirectResponseクラスは以下のメソッドを持ちます。addHeader()などのResponseクラスのメソッドも使用できます。

メソッド機能
__construct(string $url)RedirectResponseの生成
with(string $key, $value):RedirectResponseフラッシュデータの追加
withInputs():RedirectResponse入力データをフラッシュに追加する
withErrors(ErrorBag $errorBag):RedirectResponseエラーバッグをフラッシュに追加する
withOldErrors():RedirectResponse前回のエラーバッグを次のフラッシュに転送する

以下は、レスポンスで使用するフラッシュデータのキーとその内容です。特に _old_inputs と errors はHTMLテンプレートで良く使用されます。

フラッシュキー内容
_old_inputs前回の入力データ
_old_path前回のURIパス
errorsエラーバッグ

/apricot/core/Foundation/Response

RedirectResponse.php
<?php
namespace Core\Foundation\Response;
 
use Core\Flash;
use Core\Foundation\ErrorBag;
 
/**
 * Redirected Response Class
 */
class RedirectResponse extends \Core\Foundation\Response
{
    /**
     * Create RedirectResponse
     * @param string $url
     */
    public function __construct(string $url)
    {
        $this->addHeader("Location: {$url}");
    }
 
    /**
     * with
     * @param string $key
     * @param mixed $value
     * @return RedirectResponse
     */
    public function with(string $key, $value):RedirectResponse
    {
        $this->addFlash($key, $value);
        return $this;
    }
 
    /**
     * withInputs
     * @return RedirectResponse
     */
    public function withInputs():RedirectResponse
    {
        $this->addFlash(self::FLASH_KEY_OLD, \Core\Input::getRawData());
        return $this;
    }
 
    /**
     * withErrors
     * @param  \Core\Foundation\ErrorBag $message
     * @return RedirectResponse
     */
    public function withErrors(ErrorBag $errorBag):RedirectResponse
    {
        $this->addFlash(self::FLASH_KEY_ERRORS, $errorBag);
        return $this;
    }
 
    /**
     * withOldErrors
     * @return RedirectResponse
     */
    public function withOldErrors():RedirectResponse
    {
        if (Flash::has(self::FLASH_KEY_ERRORS))
        {
            $this->addFlash(self::FLASH_KEY_ERRORS, Flash::get(self::FLASH_KEY_ERRORS));
        }
        return $this;
    }
}


ヘルパー関数

レスポンス処理用のヘルパー関数を追加します。render()とredirect()はコントローラアクションで、その他はHTMLテンプレートでよく使われる関数です。

ヘルパー関数機能
render
(string $view=null, array $variables=[])
:RenderResponse
RenderResponseの生成
テンプレート名とテンプレート変数を指定します
redirect
(string $url)
:RedirectResponse
RedirectResponseの生成
リダイレクトURLを指定します
old
(string $key, $default = null)
キーを指定して前回の入力値を取得します
back():string前回のURIを取得します
errors():ErrorBag前回のエラーバッグを取得します

/apricot/core/helpers

boilerplates.php
/**
 * render
 * @param string $view テンプレート名
 * @param array $variables テンプレート変数のハッシュ
 * @return \Core\Foundation\Response\RenderResponse
 */
function render(string $view=null, array $variables=[]):Core\Foundation\Response\RenderResponse
{
    $variables['errors'] = errors();
    $html = isset($view) ? Core\View::run($view, $variables) : null;
    return new Core\Foundation\Response\RenderResponse($html);
}
 
/**
 * redirect
 * @param string $url URL
 * @return \Core\Foundation\Response\RedirectResponse
 */
function redirect(string $url):Core\Foundation\Response\RedirectResponse
{
    return new Core\Foundation\Response\RedirectResponse($url);
}
 
/**
 * Get old request inputs
 * @param string $key
 * @param mixed $default
 * @return string
 */
function old(string $key, $default = null)
{
    $old_inputs = flash(Core\Foundation\Response::FLASH_KEY_OLD);
    return isset($old_inputs) && array_key_exists($key, $old_inputs) ? $old_inputs[$key] : $default;
}
 
/**
 * Get old URL Path
 * @return string URL
 */
function back():string
{
    if (array_key_exists('HTTP_REFERER', $_SERVER) && isset($_SERVER['HTTP_REFERER']))
    {
        $url = '/';
        $info = parse_url($_SERVER['HTTP_REFERER']);
        if (array_key_exists('path',$info)) $url = $info['path'];
        if (array_key_exists('query',$info)) $url .= '?'.$info['query'];
        if (array_key_exists('fragment',$info)) $url .= '#'.$info['fragment'];
        return $url;
    }
    else
    {
        return flash(Core\Foundation\Response::FLASH_KEY_BACK, '/');
    }
}
 
/**
 * Get response errors
 * @return \Core\Foundation\ErrorBag
 */
function errors():Core\Foundation\ErrorBag
{
    $errors = Core\Flash::has(Core\Foundation\Response::FLASH_KEY_ERRORS)
    ? flash(Core\Foundation\Response::FLASH_KEY_ERRORS)
    : new Core\Foundation\ErrorBag();
 
    return $errors;
}