gdbots/query-parser-php

View on GitHub
src/Node/Date.php

Summary

Maintainability
A
50 mins
Test Coverage
<?php
declare(strict_types=1);

namespace Gdbots\QueryParser\Node;

use Gdbots\QueryParser\Builder\QueryBuilder;
use Gdbots\QueryParser\Enum\BoolOperator;
use Gdbots\QueryParser\Enum\ComparisonOperator;

final class Date extends Node
{
    const NODE_TYPE = 'date';

    // todo: enable "fuzzy" aka "proximity" for date fields?  technically a range accomplishes this already.
    /*
    const SUPPORTS_FUZZY = true;
    const MAX_FUZZY = 5;
    */

    private static ?\DateTimeZone $utc = null;
    private ComparisonOperator $comparisonOperator;

    public function __construct(
        string $value,
        ?BoolOperator $boolOperator = null,
        bool $useBoost = false,
        float $boost = self::DEFAULT_BOOST,
        bool $useFuzzy = false,
        int $fuzzy = self::DEFAULT_FUZZY,
        ?ComparisonOperator $comparisonOperator = null
    ) {
        parent::__construct($value, $boolOperator, $useBoost, $boost, $useFuzzy, $fuzzy);
        $this->comparisonOperator = $comparisonOperator ?: ComparisonOperator::EQ;
    }

    public static function fromArray(array $data = []): self
    {
        $value = $data['value'] ?? '';
        $useBoost = (bool)($data['use_boost'] ?? false);
        $boost = (float)($data['boost'] ?? self::DEFAULT_BOOST);
        $useFuzzy = (bool)($data['use_fuzzy'] ?? false);
        $fuzzy = (int)($data['fuzzy'] ?? self::DEFAULT_FUZZY);

        try {
            $boolOperator = isset($data['bool_operator']) ? BoolOperator::from($data['bool_operator']) : null;
        } catch (\Throwable $e) {
            $boolOperator = null;
        }

        try {
            $comparisonOperator = isset($data['comparison_operator']) ? ComparisonOperator::from($data['comparison_operator']) : null;
        } catch (\Throwable $e) {
            $comparisonOperator = null;
        }

        return new self($value, $boolOperator, $useBoost, $boost, $useFuzzy, $fuzzy, $comparisonOperator);
    }

    public function toArray(): array
    {
        $array = parent::toArray();
        if ($this->comparisonOperator === ComparisonOperator::EQ) {
            return $array;
        }

        $array['comparison_operator'] = $this->comparisonOperator->value;
        return $array;
    }

    public function useComparisonOperator(): bool
    {
        return $this->comparisonOperator !== ComparisonOperator::EQ;
    }

    public function getComparisonOperator(): ComparisonOperator
    {
        return $this->comparisonOperator;
    }

    /**
     * Always returns a DateTime in UTC.  Use the time zone option to inform this class
     * that the value it holds is localized and should be converted to UTC.
     *
     * @param \DateTimeZone $timeZone
     *
     * @return \DateTimeInterface
     */
    public function toDateTime(?\DateTimeZone $timeZone = null): \DateTimeInterface
    {
        if (null === self::$utc) {
            self::$utc = new \DateTimeZone('UTC');
        }

        $date = \DateTime::createFromFormat('!Y-m-d', $this->getValue(), $timeZone ?: self::$utc);
        if (!$date instanceof \DateTimeInterface) {
            $date = \DateTime::createFromFormat('!Y-m-d', (new \DateTime())->format('Y-m-d'), $timeZone ?: self::$utc);
        }

        if ($date->getOffset() !== 0) {
            $date->setTimezone(self::$utc);
        }

        return $date;
    }

    public function acceptBuilder(QueryBuilder $builder): void
    {
        $builder->addDate($this);
    }
}