src/Driver/FilesystemDriver.php

Summary

Maintainability
A
1 hr
Test Coverage
<?php

/*
 * This file is part of gpupo/cache
 * Created by Gilmar Pupo <contact@gpupo.com>
 * For the information of copyright and license you should read the file
 * LICENSE which is distributed with this source code.
 * Para a informação dos direitos autorais e de licença você deve ler o arquivo
 * LICENSE que é distribuído com este código-fonte.
 * Para obtener la información de los derechos de autor y la licencia debe leer
 * el archivo LICENSE que se distribuye con el código fuente.
 * For more information, see <https://www.gpupo.com/>.
 */

namespace Gpupo\Cache\Driver;

/**
 * Driver utilizing the filesystem.
 */
class FilesystemDriver extends DriverAbstract implements DriverInterface
{
    /**
     * Path to directory to cache contents in.
     *
     * @type string
     */
    protected $path = '';

    /**
     * FilesystemDriver constructor.
     *
     * @param null|string $path The path to set
     *
     * @author Benjamin Carl <opensource@clickalicious.de>
     */
    public function __construct($path = null)
    {
        // Use systems temp directory as default
        if (null === $path) {
            $path = sys_get_temp_dir();
        }

        $this
            ->path($path);
    }

    /**
     * Stores content in cache.
     *
     * @param string $id        Contents identifier
     * @param mixed  $obj       Content itself
     * @param int    $ttl       Time to live (Lifetime of content)
     * @param bool   $serialize Whether the content must be serialized, or not
     *
     * @return bool TRUE on success, otherwise FALSE
     */
    public function save($id, $obj, $ttl, $serialize = true)
    {
        // Check if driver supported by system
        if (false === $this->isSupported()) {
            throw new \RuntimeException(
                'Driver not supported!'
            );
        }

        // Check key
        if (false === $this->isValidKey($id)) {
            throw new \RuntimeException(
                sprintf('The key: "%s" is invalid!', var_export($id, true))
            );
        }

        // Get filename
        $filename = $this->getFilenameById($id);

        // If the file exists, check if writable ...
        if (true === file_exists($filename)) {
            if (false === is_writable($filename)) {
                throw new \RuntimeException(
                    sprintf('File: "%s" exists and isn\'t writable!', $filename)
                );
            }
        }

        $obj = $this->serialize($obj, $serialize);

        return file_put_contents($filename, $obj);
    }

    /**
     * Returns cached content by its Id.
     *
     * @param string $id          Id of the cached content
     * @param bool   $unserialize Controls whether unserialization is required or not
     *
     * @author Benjamin Carl <opensource@clickalicious.de>
     *
     * @return null|mixed The cached content if exist, otherwise NULL
     */
    public function get($id, $unserialize = true)
    {
        // Check if driver supported by system
        if (false === $this->isSupported()) {
            throw new \RuntimeException(
                'Driver not supported!'
            );
        }

        // Check key
        if (false === $this->isValidKey($id)) {
            throw new \RuntimeException(
                sprintf('The key: "%s" is invalid!', var_export($id, true))
            );
        }

        // Get filename
        $filename = $this->getFilenameById($id);
        $content = null;

        if (true === file_exists($filename)) {
            if (false === is_readable($filename)) {
                throw new \RuntimeException(
                    sprintf('File: "%s" isn\'t readable!', $filename)
                );
            }

            $content = file_get_contents($filename);
            $content = $this->unserialize($content, $unserialize);
        }

        return $content;
    }

    /**
     * Removes content from cache.
     *
     * @param string $id The Id of the content to delete from cache
     *
     * @author Benjamin Carl <opensource@clickalicious.de>
     *
     * @return bool TRUE on success, otherwise FALSE
     */
    public function delete($id)
    {
        // Check if driver supported by system
        if (false === $this->isSupported()) {
            throw new \RuntimeException(
                'Driver not supported!'
            );
        }

        // Check key
        if (false === $this->isValidKey($id)) {
            throw new \RuntimeException(
                sprintf('The key: "%s" is invalid!', var_export($id, true))
            );
        }

        // Get filename
        $filename = $this->getFilenameById($id);
        $result = false;

        if (true === file_exists($filename)) {
            if (false === is_writable($filename)) {
                throw new \RuntimeException(
                    sprintf('File: "%s" isn\'t writable and cannot be deleted!', $filename)
                );
            }

            if (true === is_dir($filename)) {
                throw new \RuntimeException(
                    sprintf('Filesystem protection: Delete failed - file: "%s" seems to be a directory!', $filename)
                );
            }

            $result = unlink($filename);
        }

        return $result;
    }

    /**
     * Setter for path.
     *
     * @param string $path The path to set
     *
     * @author Benjamin Carl <opensource@clickalicious.de>
     */
    public function setPath($path)
    {
        if (false === file_exists($path)) {
            throw new \RuntimeException(
                sprintf('Path "%s" does not exist!', $path)
            );
        }

        if (false === is_writable($path)) {
            throw new \RuntimeException(
                sprintf('Path "%s" isn\'t writable!', $path)
            );
        }

        if (DIRECTORY_SEPARATOR !== $path[strlen($path) - 1]) {
            $path .= DIRECTORY_SEPARATOR;
        }

        $this->path = $path;
    }

    /**
     * Fluent: Setter for path.
     *
     * @param string $path The path to set
     *
     * @author Benjamin Carl <opensource@clickalicious.de>
     *
     * @return $this Instance for chaining
     */
    protected function path($path)
    {
        $this->setPath($path);

        return $this;
    }

    /**
     * Getter for path.
     *
     * @author Benjamin Carl <opensource@clickalicious.de>
     *
     * @return string|null The path if set, otherwise NULL
     */
    public function getPath()
    {
        return $this->path;
    }

    /**
     * Returns the filename to cached content by its Id.
     *
     * @param string $id The Id to return filename for
     *
     * @author Benjamin Carl <opensource@clickalicious.de>
     *
     * @return string The filename
     */
    protected function getFilenameById($id)
    {
        return $this->getPath().$id;
    }

    /**
     * Check for supported.
     *
     * @author Benjamin Carl <opensource@clickalicious.de>
     *
     * @return bool TRUE if supported, otherwise FALSE
     */
    public function isSupported()
    {
        return file_exists($this->getPath());
    }
}