miércoles, 25 de junio de 2025

Implementando Filtrado Complejo con Decoradores en PHP

Implementando Filtrado Complejo con Decoradores en PHP

El patrón Decorador es una poderosa herramienta para agregar funcionalidad a objetos de forma dinámica sin modificar su estructura original. En este post, exploraremos cómo podemos utilizar este patrón para implementar un sistema de filtrado complejo y flexible en PHP. En lugar de crear una jerarquía de clases que se encarguen de todos los posibles filtros, usaremos decoradores para combinar filtros individuales según sea necesario, resultando en un código más limpio y mantenible.


<?php

// Interfaz base para el filtro
interface FilterInterface {
    public function apply(array $data): array;
}

// Clase base que implementa la interfaz
class BaseFilter implements FilterInterface {
    protected array $data;

    public function __construct(array $data) {
        $this->data = $data;
    }

    public function apply(array $data = null): array {
        return $data ?? $this->data;
    }
}

// Interfaz para los Decoradores
interface FilterDecoratorInterface extends FilterInterface {
    public function __construct(FilterInterface $filter);
}

// Decorador abstracto base
abstract class FilterDecorator implements FilterDecoratorInterface {
    protected FilterInterface $filter;

    public function __construct(FilterInterface $filter) {
        $this->filter = $filter;
    }

    public function apply(array $data): array {
        return $this->filter->apply($data);
    }
}
    

Ahora, implementaremos un decorador específico para filtrar datos por un rango de fechas. Este decorador recibirá la fecha de inicio y la fecha de fin, y filtrará el array de datos para incluir solo los elementos cuyas fechas estén dentro del rango especificado.


<?php

// Decorador para filtrar por rango de fechas
class DateRangeFilter extends FilterDecorator {
    private DateTime $startDate;
    private DateTime $endDate;
    private string $dateKey;

    public function __construct(FilterInterface $filter, DateTime $startDate, DateTime $endDate, string $dateKey = 'date') {
        parent::__construct($filter);
        $this->startDate = $startDate;
        $this->endDate = $endDate;
        $this->dateKey = $dateKey;
    }

    public function apply(array $data): array {
        $filteredData = [];
        foreach ($data as $item) {
            $itemDate = new DateTime($item[$this->dateKey]);
            if ($itemDate >= $this->startDate && $itemDate <= $this->endDate) {
                $filteredData[] = $item;
            }
        }
        return parent::apply($filteredData);
    }
}

// Ejemplo de uso
$data = [
    ['id' => 1, 'date' => '2023-10-26', 'value' => 100],
    ['id' => 2, 'date' => '2023-11-15', 'value' => 200],
    ['id' => 3, 'date' => '2023-12-01', 'value' => 300],
];

$baseFilter = new BaseFilter($data);
$startDate = new DateTime('2023-11-01');
$endDate = new DateTime('2023-11-30');

$dateRangeFilter = new DateRangeFilter($baseFilter, $startDate, $endDate);
$filteredData = $dateRangeFilter->apply($data);

print_r($filteredData);

    

Este enfoque con decoradores permite combinar filtros de manera flexible. Podemos agregar más decoradores para implementar otros tipos de filtros, como filtrar por valor, por ID, etc., sin modificar las clases existentes. Esto promueve el principio de abierto/cerrado y facilita la extensibilidad de nuestro sistema de filtrado.

No hay comentarios:

Publicar un comentario