src/Generic/Params/Params.php

Summary

Maintainability
A
1 hr
Test Coverage
A
100%
<?php

declare(strict_types=1);

namespace QB\Generic\Params;

use InvalidArgumentException;
use PDO;

class Params
{
    public const ALL_STRING = 1;
    public const ALL_AUTO   = 2;
    public const ALL_MANUAL = 4;

    protected int $paramHandle;

    protected bool $useNamedParams;

    /** @var array<int,array<int,mixed>> */
    protected array $params = [];

    /** @var int Helps tracking the extensions done on the SQL originally received */
    protected int $extendedBy = 0;

    /**
     * Params constructor.
     *
     * @param array $params
     * @param int   $paramHandle
     */
    public function __construct(array $params = [], int $paramHandle = self::ALL_AUTO)
    {
        $this->useNamedParams = !array_key_exists(0, $params);

        $this->validateParamHandle($paramHandle);
        $this->validateParamKeys(array_keys($params));

        $this->paramHandle = $paramHandle;

        $this->bind($params, $paramHandle);
    }

    /**
     * @param int $paramHandle
     */
    protected function validateParamHandle(int $paramHandle): void
    {
        if (!in_array($paramHandle, [self::ALL_STRING, self::ALL_AUTO, self::ALL_MANUAL])) {
            throw new InvalidArgumentException(
                sprintf('invalid param handle received: %d.', $paramHandle)
            );
        }
    }

    /**
     * @param array $paramKeys
     */
    protected function validateParamKeys(array $paramKeys): void
    {
        if ($this->useNamedParams) {
            foreach ($paramKeys as $paramKey) {
                if (is_int($paramKey)) {
                    throw new InvalidArgumentException(
                        sprintf('string param key was expected, int received: %d.', $paramKey)
                    );
                }
            }

            return;
        }

        $next = 0;
        foreach ($paramKeys as $paramKey) {
            if ($paramKey !== $next) {
                throw new InvalidArgumentException(
                    sprintf('key was expected to be %d, received: %s.', $next, $paramKey)
                );
            }
            $next++;
        }
    }

    /**
     * @param array $params
     * @param int   $paramHandle
     */
    public function bind(array $params, int $paramHandle = self::ALL_AUTO)
    {
        foreach ($params as $origKey => $var) {
            if ($this->useNamedParams) {
                $this->params[$origKey] = $this->getFinalParam($var, $paramHandle);
            } else {
                $this->params[] = $this->getFinalParam($var, $paramHandle);
            }
        }
    }

    /**
     * @param     $var
     * @param int $paramHandle
     *
     * @return array
     */
    protected function getFinalParam($var, int $paramHandle): array
    {
        switch ($paramHandle) {
            case self::ALL_MANUAL:
                return [$var[0], $var[1]];
            case self::ALL_AUTO:
                if ($var === null) {
                    return [$var, PDO::PARAM_NULL];
                } elseif (is_bool($var)) {
                    return [$var, PDO::PARAM_BOOL];
                } elseif (is_int($var)) {
                    return [$var, PDO::PARAM_INT];
                }
        }

        return [$var, PDO::PARAM_STR];
    }

    /**
     * @return bool
     */
    public function usesNamedParams(): bool
    {
        return $this->useNamedParams;
    }

    /**
     * @return bool
     */
    public function usesUnnamedParams(): bool
    {
        return !$this->useNamedParams;
    }

    /**
     * @return array
     */
    public function getAll(): array
    {
        return $this->params;
    }
}