roydejong/Enlighten

View on GitHub
lib/Http/Response.php

Summary

Maintainability
A
50 mins
Test Coverage
<?php

namespace Enlighten\Http;

/**
 * The HTTP response sent back based on an incoming Request.
 * Each response is built up over time as the application is executed, and then sent on execution end.
 */
class Response
{
    /**
     * The protocol that will be specified when sending response headers.
     * This is a constant value based on the HTTP spec that has been implemented in the framework code.
     *
     * @var string
     */
    const PROTOCOL_VERSION = 'HTTP/1.1';

    /**
     * The HTTP status code to be sent to the client.
     *
     * @var int
     */
    protected $statusCode;

    /**
     * Key/value array containing the headers to be sent to the client.
     *
     * @var array
     */
    protected $headers;

    /**
     * The cookies to be sent to the client.
     * Key/value array containing name => Cookie.
     *
     * @var Cookie[]
     */
    protected $cookies;

    /**
     * Raw body string to be sent to the client.
     *
     * @var string
     */
    protected $body;

    /**
     * Initializes a new, blank response.
     */
    public function __construct()
    {
        $this->statusCode = ResponseCode::HTTP_OK;
        $this->headers = [];
        $this->cookies = [];
        $this->body = '';
    }

    /**
     * Sets the HTTP response code.
     *
     * @param int $code
     * @return $this
     */
    public function setResponseCode($code)
    {
        if (!ResponseCode::isValid($code)) {
            throw new \InvalidArgumentException('setResponseCode(): Invalid HTTP response code given of value ' . strval($code));
        }

        $this->statusCode = $code;
        return $this;
    }

    /**
     * Gets the HTTP response status code.
     *
     * @return int
     */
    public function getResponseCode()
    {
        return $this->statusCode;
    }

    /**
     * Redirect the user to a specific URL.
     * Performs a HTTP 301 or HTTP 302 redirect.
     *
     * @param string $url
     * @param bool $permanent If true, a 301 Moved Permanently will be issued; otherwise a 307 Temporary Redirect.
     * @return $this
     */
    public function doRedirect($url, $permanent = false)
    {
        $this->setResponseCode($permanent ? ResponseCode::HTTP_MOVED_PERMANENTLY : ResponseCode::HTTP_FOUND);
        $this->setHeader('Location', $url);
        return $this;
    }

    /**
     * Sets a HTTP header to a certain value.
     *
     * @param string $key
     * @param string $value
     * @return $this
     */
    public function setHeader($key, $value)
    {
        $this->headers[strval($key)] = strval($value);
        return $this;
    }

    /**
     * Gets the current value of a given header.
     *
     * @param string $key
     * @return string|null The string value of the header, or null if the header was not set.
     */
    public function getHeader($key)
    {
        if (!isset($this->headers[$key])) {
            return null;
        }

        return $this->headers[$key];
    }

    /**
     * Sets the response body to a certain value.
     *
     * @param string $body
     * @return $this
     */
    public function setBody($body)
    {
        $this->body = strval($body);
        return $this;
    }

    /**
     * Appends to the response body.
     *
     * @param string $body
     * @return $this
     */
    public function appendBody($body)
    {
        $this->body .= strval($body);
        return $this;
    }

    /**
     * Gets the current value of the response body.
     *
     * @return string
     */
    public function getBody()
    {
        return $this->body;
    }

    /**
     * Creates or updates a cookie.
     *
     * @param string $name Cookie name.
     * @param string $value Cookie value.
     * @param int $expire Unix expiration timestamp, or 0 for session expire.
     * @param string|null $path The path the cookie can be used on.
     * @param string|null $domain The domain the cookie can be used on.
     * @param bool $secure True for HTTPS only.
     * @param bool $httpOnly True for HTTP(S) only (not accessible to JavaScript, etc).
     * @return $this
     */
    public function setCookie($name, $value, $expire = 0, $path = null, $domain = null, $secure = false, $httpOnly = false)
    {
        return $this->addCookie((new Cookie())
            ->setName($name)
            ->setValue($value)
            ->setExpireTimestamp($expire)
            ->setPath($path)
            ->setDomain($domain)
            ->setSecure($secure)
            ->setHttpOnly($httpOnly));
    }

    /**
     * Adds a cookie to be sent.
     *
     * @param Cookie $cookie
     * @return $this
     */
    public function addCookie(Cookie $cookie)
    {
        $this->cookies[$cookie->getName()] = $cookie;
        return $this;
    }

    /**
     * Tries to destroy a client cookie based on its name, by setting its expiration to a date in the future.
     *
     * @param $name
     * @return $this
     */
    public function unsetCookie($name)
    {
        $this->setCookie($name, '', time() - 3600, '/');
        return $this;
    }

    /**
     * Sends the HTTP cookies to the client.
     * Causes output!
     */
    protected function sendCookies()
    {
        foreach ($this->cookies as $cookie) {
            setcookie($cookie->getName(), $cookie->getValue(), $cookie->getExpireTimestamp(), $cookie->getPath(),
                $cookie->getDomain(), $cookie->isSecure(), $cookie->isHttpOnly());
        }
    }

    /**
     * Sends the HTTP headers to the client.
     * Causes output!
     */
    protected function sendHeaders()
    {
        header(sprintf('%s %s', self::PROTOCOL_VERSION, ResponseCode::getMessageForCode($this->statusCode)));

        foreach ($this->headers as $name => $value) {
            header(sprintf("%s: %s", $name, $value));
        }
    }

    /**
     * Sends the response body to the client.
     * Causes output!
     */
    protected function sendBody()
    {
        echo $this->body;
    }

    /**
     * Sends the HTTP response to the client.
     * Causes output!
     */
    public function send()
    {
        $this->sendHeaders();
        $this->sendCookies();

        if (ResponseCode::canHaveBody($this->statusCode)) {
            $this->sendBody();
        }
    }
}