imponeer/smarty-db-resource

View on GitHub
src/DBResource.php

Summary

Maintainability
A
1 hr
Test Coverage
<?php

namespace Imponeer\Smarty\Extensions\DBResource;

use Exception;
use Imponeer\Contracts\Smarty\Extension\SmartyResourceInterface;
use PDO;
use Smarty_Resource_Custom;

/**
 * Smarty resource type to fetch template from database
 *
 * @package Imponeer\Smarty\Extensions\DBResource
 */
class DBResource extends Smarty_Resource_Custom implements SmartyResourceInterface
{
    /**
     * @var PDO
     */
    private $pdo;
    /**
     * @var string
     */
    private $templatesTableName;
    /**
     * @var string
     */
    private $templateSourceColumnName;
    /**
     * @var string
     */
    private $templateModificationColumnName;
    /**
     * @var string
     */
    private $tplSetName;
    /**
     * @var string
     */
    private $tplSetColumnName;
    /**
     * @var string
     */
    private $templateNameColumnName;
    /**
     * @var string
     */
    private $defaultTplSetName;

    /**
     * @var callable
     */
    private $templatePathGetter;

    /**
     * Constructor.
     *
     * @param PDO $pdo PDO compatible database connection instance
     * @param string $tplSetName Current template set name
     * @param string $templatesTableName Table name where all template data are located
     * @param string $templateSourceColumnName Column name that is used to store template source code
     * @param string $templateModificationColumnName Column name that is used to store template modification Unix timestamp
     * @param string $tplSetColumnName Column name that identifies template related teplate set for core
     * @param string $templateNameColumnName Column name that identifies template file name
     * @param callable $templatePathGetter Callable that is used to convert from database fetched data into real template path
     * @param string $defaultTplSetName Default template set name
     */
    public function __construct(
        PDO      $pdo,
        string   $tplSetName,
        string   $templatesTableName,
        string   $templateSourceColumnName,
        string   $templateModificationColumnName,
        string   $tplSetColumnName,
        string   $templateNameColumnName,
        callable $templatePathGetter,
        string   $defaultTplSetName = 'default'
    )
    {
        $this->pdo = $pdo;
        $this->templatesTableName = $templatesTableName;
        $this->templateSourceColumnName = $templateSourceColumnName;
        $this->templateModificationColumnName = $templateModificationColumnName;
        $this->tplSetName = $tplSetName;
        $this->tplSetColumnName = $tplSetColumnName;
        $this->templateNameColumnName = $templateNameColumnName;
        $this->defaultTplSetName = $defaultTplSetName;
        $this->templatePathGetter = $templatePathGetter;
    }

    /**
     * @inheritDoc
     */
    public function getName(): string
    {
        return 'db';
    }

    /**
     * @inheritDoc
     */
    protected function fetch($name, &$source, &$mtime)
    {
        [$source, $mtime] = $this->getInfo($name);
    }

    /**
     * Gets info for template
     *
     * @param string $template Template file name
     *
     * @return array|null
     *
     * @throws Exception
     */
    private function getInfo(string $template): ?array
    {
        $data = $this->fetchTemplateDataFromDatabase($template);

        if ($data === null) {
            $content = $this->getCacheArrayForNotFoundItem();
        } elseif ($data[$this->tplSetColumnName] !== $this->defaultTplSetName) {
            $content = $this->getCacheArrayForDatabaseRow($data);
        } else {
            $ret = call_user_func($this->templatePathGetter, $data);
            if ($ret === null) {
                return null;
            }

            $content = $this->getCacheArrayForFile($ret);
        }

        return $content;
    }

    /**
     * Gets array that will be cached for empty item
     *
     * @return array
     */
    protected function getCacheArrayForNotFoundItem(): array
    {
        return [null, null];
    }

    /**
     * Gets array that will be cached for database item
     *
     * @param array $data Array row data (assoc)
     *
     * @return array
     */
    protected function getCacheArrayForDatabaseRow(array $data): array
    {
        return [
            $data[$this->templateSourceColumnName],
            $data[$this->templateModificationColumnName],
        ];
    }

    /**
     * Gets array that will be cached for real file
     *
     * @param string $file File for what to create this array
     *
     * @return array
     */
    protected function getCacheArrayForFile(string $file): array
    {
        return [
            file_get_contents($file),
            filemtime($file),
        ];
    }

    /**
     * Gets select query for the driver
     *
     * @return string
     */
    private function getSelectQuery(): string
    {
        switch ($this->pdo->getAttribute(PDO::ATTR_DRIVER_NAME)) {
            case 'sqlite':
            case 'sqlite3':
                return 'SELECT *, CASE WHEN `%3$s` IS NOT NULL THEN 1 ELSE 0 END ___order  FROM `%1$s` WHERE `%2$s` = :template AND `%3$s` IN (:tplset, :defaultTplSet) ORDER BY ___order ASC LIMIT 1';
            default:
                return 'SELECT * FROM `%1$s` WHERE `%2$s` = :template AND `%3$s` IN (:tplset, :defaultTplSet) ORDER BY IF(`%3$s` = :defaultTplSet, 1, 0) ASC LIMIT 1';
        }

    }

    /**
     * Fetches template modify date info
     *
     * @param string $template Template to find in DB
     *
     * @return array|null
     *
     * @throws Exception
     */
    private function fetchTemplateDataFromDatabase(string $template): ?array
    {
        $stm = $this->pdo->prepare(
            sprintf(
                $this->getSelectQuery(),
                $this->templatesTableName,
                $this->templateNameColumnName,
                $this->tplSetColumnName
            )
        );
        $stm->bindValue('template', $template, PDO::PARAM_STR);
        $stm->bindValue('tplset', $this->tplSetName, PDO::PARAM_STR);
        $stm->bindValue('defaultTplSet', $this->defaultTplSetName, PDO::PARAM_STR);
        $stm->execute();

        $row = $stm->fetch(PDO::FETCH_ASSOC);
        if (!$row) {
            return null;
        }

        return $row;
    }
}