dadajuice/zephyrus

View on GitHub
src/Zephyrus/Core/Session/Handlers/DatabaseSessionHandler.php

Summary

Maintainability
A
25 mins
Test Coverage
<?php namespace Zephyrus\Core\Session\Handlers;

use SessionHandler;
use Zephyrus\Database\Core\Database;
use Zephyrus\Exceptions\Session\SessionDatabaseStructureException;
use Zephyrus\Exceptions\Session\SessionDatabaseTableException;

class DatabaseSessionHandler extends SessionHandler
{
    private Database $database;
    private string $table;

    public function __construct(Database $database, string $table = "public.session")
    {
        $this->database = $database;
        $this->table = $table;
    }

    /**
     * @throws SessionDatabaseStructureException
     * @throws SessionDatabaseTableException
     */
    public function isAvailable(): bool
    {
        list($schema, $table) = (str_contains($this->table, "."))
            ? explode('.', $this->table)
            : ['public', $this->table];
        if ($this->database->getSchemaInterrogator()->tableExists($table, $schema)) {
            $columns = ['session_id', 'access', 'data', 'expire'];
            foreach ($columns as $column) {
                if (!$this->database->getSchemaInterrogator()->columnExists($column, $table, $schema)) {
                    throw new SessionDatabaseStructureException($table, $schema);
                }
            }
            return true;
        }

        throw new SessionDatabaseTableException($table, $schema);
    }

    public function destroy(string $id): bool
    {
        $this->database->query("DELETE FROM $this->table WHERE session_id = ?", [$id]);
        return true;
    }

    public function close(): bool
    {
        return true;
    }

    public function gc(int $max_lifetime): int
    {
        $old = time() - $max_lifetime;
        $statement = $this->database->query("DELETE FROM $this->table WHERE access < ?", [$old]);
        return $statement->count();
    }

    public function open(string $path, string $name): bool
    {
        return $this->isAvailable();
    }

    public function read(string $id): string
    {
        $statement = $this->database->query("SELECT data FROM $this->table WHERE session_id = ?", [$id]);
        return $statement->next()?->data ?? "";
    }

    public function write(string $id, string $data): bool
    {
        $access = time();
        $expire = $access + ini_get('session.gc_maxlifetime');
        $sql = "INSERT INTO $this->table(session_id, access, data, expire) 
                     VALUES (?, ?, ?, ?) ON CONFLICT (session_id) DO UPDATE
                     SET access = excluded.access, 
                         data = excluded.data,
                         expire = excluded.expire";
        $this->database->query($sql, [$id, $access, $data, $expire]);
        return true;
    }
}