Your IP : 216.73.216.158


Current Path : /home/megadansyp/www/plugins/system/articlesanywhere/src/Collection/Filters/
Upload File :
Current File : /home/megadansyp/www/plugins/system/articlesanywhere/src/Collection/Filters/Filter.php

<?php
/**
 * @package         Articles Anywhere
 * @version         14.2.0
 * 
 * @author          Peter van Westen <info@regularlabs.com>
 * @link            https://regularlabs.com
 * @copyright       Copyright © 2023 Regular Labs All Rights Reserved
 * @license         GNU General Public License version 2 or later
 */

namespace RegularLabs\Plugin\System\ArticlesAnywhere\Collection\Filters;

defined('_JEXEC') or die;

use JDatabaseQuery;
use Joomla\CMS\Date\Date as JDate;
use Joomla\CMS\Factory as JFactory;
use RegularLabs\Library\ArrayHelper as RL_Array;
use RegularLabs\Library\DB as RL_DB;
use RegularLabs\Library\RegEx as RL_RegEx;
use RegularLabs\Library\StringHelper as RL_String;
use RegularLabs\Plugin\System\ArticlesAnywhere\Collection\CollectionObject;
use RegularLabs\Plugin\System\ArticlesAnywhere\Helpers\ValueHelper;

class Filter extends CollectionObject implements FilterInterface
{
    public function getConditionDefault($key, &$value, $operator)
    {
        if (strpos($value, '*') !== false)
        {
            return $this->db->quoteName($key) . RL_DB::like($operator . $value);
        }

        $where = $this->getWhereIfDateValue($key, $value, $operator);

        if ($where)
        {
            return $where;
        }

        $query = $this->db->quoteName($key) . RL_DB::in($operator . $value, true);

        if ( ! $this->isPotentialYearMonth($key, $value))
        {
            return $query;
        }

        RL_RegEx::match('^[0-9]{4}(?<month>-[0-9]{2})?$', $value, $match);

        // Special case for if value is possibly a year or year-month format
        $format = isset($match['month']) ? '%Y-%m' : '%Y';
        $regex  = '^[0-9]{4}-[0-9]{2}-[0-9]{2}( [0-9]{1,2}:[0-9]{2}:[0-9]{2})?$';
        $select = 'DATE_FORMAT(' . $this->db->quoteName($key) . ',' . $this->db->quote($format) . ')';

        $if   = ' YEAR(' . $this->db->quoteName($key) . ')'
            . ' AND ' . $this->db->quoteName($key) . ' REGEXP ' . $this->db->quote($regex);
        $then = $select . RL_DB::in($operator . $value, true);
        $else = $query;

        return '(CASE WHEN ' . $if . ' THEN ' . $then . ' ELSE ' . $else . ' END)';
    }

    public function getFromAndToDates($value)
    {
        if (strpos($value, ' to ') !== false)
        {
            $value    = explode(' to ', $value, 2);
            $value[0] = RL_RegEx::replace('^from ', '', $value[0]);

            [$from, $ignore] = $this->getFromAndToDates($value[0]);
            [$ignore, $to] = $this->getFromAndToDates($value[1]);

            return [$from, $to];
        }

        [$interval, $format] = $this->getIntervalAndFormatFromDate($value);

        $date = new JDate($value, JFactory::getConfig()->get('offset', 'UTC'));

        $from = $this->db->quote($date->format($format));
        $to   = $interval ? $this->db->quote($date->modify('1' . $interval)->format($format)) : '';

        return [$from, $to];
    }

    public function getIntervalAndFormatFromDate($value)
    {
        if ( ! RL_RegEx::match(
            '^[0-9]{4}-[0-9]{1,2}-[0-9]{1,2}(?<hours> [0-9]{1,2}(?<minutes>:[0-9]{1,2}(?<seconds>\:[0-9]{1,2})?)?)?$',
            $value, $datetime_parts)
        )
        {
            return [false, 'Y-m-d H:i:s'];
        }

        switch (true)
        {
            case (isset($datetime_parts['seconds'])):
                return ['seconds', 'Y-m-d H:i:s'];

            case (isset($datetime_parts['minutes'])):
                return ['minutes', 'Y-m-d H:i:00'];

            case (isset($datetime_parts['hours'])):
                return ['hours', 'Y-m-d H:00:00'];

            default:
                return ['days', 'Y-m-d H:00:00'];
        }
    }

    public function getWhereIfDateValue($key, &$value, $operator)
    {
        $date = ValueHelper::placeholderToDate($value);

        if ($date)
        {
            if ( ! ValueHelper::isDateValue($date))
            {
                $value = $date;

                return false;
            }

            $value = ValueHelper::placeholderToDate($value, false);
        }

        if ( ! ValueHelper::isDateValue($value))
        {
            return false;
        }

        [$from, $to] = $this->getFromAndToDates($value);

        if ( ! $to)
        {
            return $this->db->quoteName($key) . ' ' . $operator . ' ' . $from;
        }

        switch ($operator)
        {
            case '<':
                return $this->db->quoteName($key) . ' < ' . $from;

            case '>':
                return $this->db->quoteName($key) . ' >= ' . $to;

            case '<=':
                return $this->db->quoteName($key) . ' < ' . $to;

            case '>=':
                return $this->db->quoteName($key) . ' >= ' . $from;

            case '!':
            case '!=':
                return '('
                    . $this->db->quoteName($key) . ' < ' . $from
                    . ' OR ' . $this->db->quoteName($key) . ' > ' . $to
                    . ')';

            default:
                return '('
                    . $this->db->quoteName($key) . ' >= ' . $from
                    . ' AND ' . $this->db->quoteName($key) . ' < ' . $to
                    . ')';
        }
    }

    public function isPotentialYearMonth($key, $value)
    {
        // Check if value is possibly a year or year-month format
        if ( ! RL_RegEx::match('^[0-9]{4}(?:-[0-9]{2})?$', $value))
        {
            return false;
        }

        $key_parts = explode('.', $key);
        $key_name  = array_pop($key_parts);

        // not a date if it is one of these columns
        $no_date_keys = [
            'id',
            'title',
            'alias',
            'state',
            'parent',
            'ordering',
            'access',
            'language',
        ];

        if (in_array($key_name, $no_date_keys))
        {
            return false;
        }

        // not a date if the key ends in '_id'
        if (RL_RegEx::match('_id$', $key_name))
        {
            return false;
        }

        return true;
    }

    public function set(JDatabaseQuery $query)
    {
        $class = get_called_class();
        $class = substr($class, strrpos($class, '\\') + 1);

        $group   = RL_String::toUnderscoreCase($class);
        $filters = $this->config->getFilters($group);

        if (empty($filters) && is_array($filters))
        {
            $this->setConditionsWhenEmpty($query);

            return;
        }

        if (empty($filters))
        {
            return;
        }

        $this->setFilter($query, $filters);
    }

    public function setConditionsWhenEmpty(JDatabaseQuery $query)
    {
        $query->where('0');
    }

    public function setFilter(JDatabaseQuery $query, $filters = [])
    {
        return;
    }

    protected function addConditionByValue(&$conditions, $keys = [], $value = '', $keys_if_nummeric = [])
    {
        $keys             = RL_Array::toArray($keys);
        $keys_if_nummeric = RL_Array::toArray($keys_if_nummeric);

        $check_value = RL_DB::removeOperator($value);

        if (is_numeric($check_value) && ! empty($keys_if_nummeric))
        {
            $keys = $keys_if_nummeric;
        }

        foreach ($keys as $key)
        {
            $conditions[] = $this->getConditionByKey($key, $value);
        }
    }

    protected function getConditionByKey($key, $value = '')
    {
        $operator    = RL_DB::getOperator($value);
        $check_value = $operator == '!=' ? '!' . $value : $value;

        switch ($check_value)
        {
            // Should be empty or null
            case '':
                return '('
                    . $this->db->quoteName($key) . ' = ' . $this->db->quote('')
                    . ' OR '
                    . $this->db->quoteName($key) . ' IS NULL'
                    . ')';

            // Should be empty but not null
            case '!*':
            case '!+':
                return '('
                    . $this->db->quoteName($key) . ' = ' . $this->db->quote('')
                    . ' AND '
                    . $this->db->quoteName($key) . ' IS NOT NULL'
                    . ')';

            // Should not be null
            case '*':
                return $this->db->quoteName($key) . ' IS NOT NULL';

            // Should not be empty
            case '+':
            case '!':
                return '('
                    . $this->db->quoteName($key) . ' != ' . $this->db->quote('')
                    . ' AND '
                    . $this->db->quoteName($key) . ' IS NOT NULL'
                    . ')';

            // Should match the value
            default:
                // Should do a LIKE match
                $not_null = '';

                if ($operator == '!=')
                {
                    $not_null = $this->db->quoteName($key) . ' IS NULL OR ';
                }

                $where = $this->getConditionDefault($key, $value, $operator);

                return $not_null . $where;
        }
    }

    protected function getConditionsFromValues($keys, $values = [], $keys_if_nummeric = [])
    {
        $values = RL_Array::toArray($values);

        if (empty($values))
        {
            $values = [''];
        }

        $conditions = [];

        foreach ($values as $value)
        {
            $this->addConditionByValue($conditions, $keys, $value, $keys_if_nummeric);
        }

        $operator = RL_DB::getOperatorFromValue($values[0]);

        if (empty($conditions))
        {
            return $operator == '!=' ? '1' : '0';
        }

        $glue = $operator == '!=' ? ' AND ' : ' OR ';

        return '((' . implode(') ' . $glue . ' (', $conditions) . '))';
    }

    protected function setFiltersFromNames(JDatabaseQuery &$query, $table, $names = [], $use_id_if_numeric = true)
    {
        $keys = [
            $this->config->getTitle($table, false, $table),
            $this->config->getAlias($table, false, $table),
        ];

        $keys_if_nummeric = [
            $this->config->getId($table, false, $table),
        ];

        if ($use_id_if_numeric === 'also')
        {
            $keys_if_nummeric[] = $this->config->getAlias($table, false, $table);
        }

        $conditions = $this->getConditionsFromValues($keys, $names, $keys_if_nummeric);

        if (empty($conditions))
        {
            return;
        }

        $query->where($conditions);
    }
}