Major refactoring cleanup: - Add new controller architecture (class-controller-*.php) - Add new settings-v2 UI (views/settings-v2/) - Add new CSS architecture (agentic-sidebar.css, tokens) - Add esbuild build pipeline (scripts/build.js, package.json) - Add composer dependencies (vendor/) - Add frontend src directory (assets/js/src/index.jsx) - Add documentation files - Remove old/obsolete files (class-settings.php, old CSS) This commits all pending changes from previous refactoring efforts.
100 lines
2.9 KiB
PHP
100 lines
2.9 KiB
PHP
<?php
|
|
|
|
/**
|
|
* League.Csv (https://csv.thephpleague.com)
|
|
*
|
|
* (c) Ignace Nyamagana Butera <nyamsprod@gmail.com>
|
|
*
|
|
* For the full copyright and license information, please view the LICENSE
|
|
* file that was distributed with this source code.
|
|
*/
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace League\Csv\Query\Constraint;
|
|
|
|
use CallbackFilterIterator;
|
|
use Closure;
|
|
use Iterator;
|
|
use League\Csv\MapIterator;
|
|
use League\Csv\Query\Predicate;
|
|
use League\Csv\Query\QueryException;
|
|
use League\Csv\Query\Row;
|
|
use ReflectionException;
|
|
|
|
use function array_filter;
|
|
use function is_array;
|
|
use function is_int;
|
|
use function is_string;
|
|
|
|
use const ARRAY_FILTER_USE_BOTH;
|
|
|
|
/**
|
|
* Enable filtering a record by comparing the values of two of its column.
|
|
*
|
|
* When used with PHP's array_filter with the ARRAY_FILTER_USE_BOTH flag
|
|
* the record offset WILL NOT BE taken into account
|
|
*/
|
|
final class TwoColumns implements Predicate
|
|
{
|
|
/**
|
|
* @throws QueryException
|
|
*/
|
|
private function __construct(
|
|
public readonly string|int $first,
|
|
public readonly Comparison|Closure $operator,
|
|
public readonly array|string|int $second,
|
|
) {
|
|
!$this->operator instanceof Closure || !is_array($this->second) || throw new QueryException('The second column must be a string if the operator is a callback.');
|
|
|
|
if (is_array($this->second)) {
|
|
$res = array_filter($this->second, fn (mixed $value): bool => !is_string($value) && !is_int($value));
|
|
if ([] !== $res) {
|
|
throw new QueryException('The second column must be a string, an integer or a list of strings and/or integer when the operator is not a callback.');
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @throws QueryException
|
|
*/
|
|
public static function filterOn(
|
|
string|int $firstColumn,
|
|
Comparison|Closure|callable|string $operator,
|
|
array|string|int $secondColumn
|
|
): self {
|
|
if (is_string($operator)) {
|
|
$operator = Comparison::fromOperator($operator);
|
|
}
|
|
|
|
if (is_callable($operator)) {
|
|
return new self($firstColumn, Closure::fromCallable($operator), $secondColumn);
|
|
}
|
|
|
|
return new self($firstColumn, $operator, $secondColumn);
|
|
}
|
|
|
|
/**
|
|
* @throws QueryException
|
|
* @throws ReflectionException
|
|
*/
|
|
public function __invoke(mixed $value, int|string $key): bool
|
|
{
|
|
$val = match (true) {
|
|
is_array($this->second) => array_values(Row::from($value)->select(...$this->second)),
|
|
default => Row::from($value)->value($this->second),
|
|
};
|
|
|
|
if ($this->operator instanceof Closure) {
|
|
return ($this->operator)(Row::from($value)->value($this->first), $val);
|
|
}
|
|
|
|
return Column::filterOn($this->first, $this->operator, $val)($value, $key);
|
|
}
|
|
|
|
public function filter(iterable $value): Iterator
|
|
{
|
|
return new CallbackFilterIterator(MapIterator::toIterator($value), $this);
|
|
}
|
|
}
|