Skip to content

FilterHelper

Class

php
<?php

namespace App\Helpers;

use Illuminate\Database\Eloquent\Builder;

class FilterHelper
{
    /**
     * Throw exception with message and param
     *
     * @param  string  $message  - Exception message
     * @param  array  $param  - Param to print
     *
     * @throws \Exception
     */
    public static function throwWithParam(string $message, array $param): void
    {
        throw new \Exception($message.': '.print_r($param, true));
    }

    /**
     * Validate closure param
     *
     * @param  array  $closureParam  - Closure param to validate
     *
     * @throws \Exception
     */
    public static function validateClosureParam(array $closureParam): void
    {
        if (! isset($closureParam['type'])) {
            FilterHelper::throwWithParam('Type key is required for closure param', $closureParam);
        }
        if ($closureParam['type'] !== 'closure') {
            FilterHelper::throwWithParam('Closure param must be of type closure', $closureParam);
        }
        if (! isset($closureParam['params'])) {
            FilterHelper::throwWithParam('Params are required for closure param', $closureParam);
        }
        foreach ($closureParam['params'] as $param) {
            if (! isset($param['type'])) {
                FilterHelper::throwWithParam('Type key is required for closure param', $param);
            }
            if ($param['type'] === 'method') {
                FilterHelper::validateMethodParam($param);
            } else {
                FilterHelper::throwWithParam('Invalid type for closure param', $param);
            }
        }
    }

    /**
     * Validate or fix value param
     *
     * @param  array  $valueParam  - Value param to validate
     *
     * @throws \Exception
     */
    public static function validateValueParam(array &$valueParam): void
    {
        if (! isset($valueParam['type'])) {
            FilterHelper::throwWithParam('Type key is required for value param', $valueParam);
        }
        if ($valueParam['type'] !== 'value') {
            FilterHelper::throwWithParam('Value param must be of type value', $valueParam);
        }
        if (! isset($valueParam['value'])) {
            // Don't throw here, we will set this to null when building method params
        }
    }

    /**
     * Validate method param
     *
     * @param  array  $methodParam  - Method param to validate
     *
     * @throws \Exception
     */
    public static function validateMethodParam(array $methodParam): void
    {
        if (! isset($methodParam['type'])) {
            FilterHelper::throwWithParam('Type key is required for method param', $methodParam);
        }
        if ($methodParam['type'] !== 'method') {
            FilterHelper::throwWithParam('Method param must be of type method', $methodParam);
        }
        if (! isset($methodParam['params'])) {
            FilterHelper::throwWithParam('Params are required for method param', $methodParam);
        }
        if (! isset($methodParam['method'])) {
            FilterHelper::throwWithParam('Method is required for method param', $methodParam);
        }
        if (! is_array($methodParam['params'])) {
            FilterHelper::throwWithParam('Params must be an array', $methodParam);
        }
        foreach ($methodParam['params'] as $param) {
            if (! isset($param['type'])) {
                FilterHelper::throwWithParam('Type key is required for method params', $param);
            }
            if ($param['type'] === 'value') {
                FilterHelper::validateValueParam($param);
            } elseif ($param['type'] === 'closure') {
                FilterHelper::validateClosureParam($param);
            } else {
                FilterHelper::throwWithParam('Invalid type for method param', $param);
            }
        }
    }

    /**
     * Validate filter spec
     *
     * @param  array  $filterSpec  - Filter spec to validate
     *
     * @throws \Exception
     */
    public static function validateFilterSpec(array $filterSpec): void
    {
        foreach ($filterSpec as $value) {
            FilterHelper::validateMethodParam($value);
        }
    }

    /**
     * Parses provided params into methods and method params
     *
     * @param  array  $params  - Params to build
     * @return array<Closure|string|number|null>
     */
    public static function buildParams(array $params): array
    {
        $output = [];
        foreach ($params as $param) {
            if ($param['type'] === 'value') {
                if (! isset($param['value'])) {
                    $param['value'] = null;
                } else {
                    $output[] = $param['value'];
                }
            } elseif ($param['type'] === 'closure') {
                $output[] = function ($query) use ($param) {
                    foreach ($param['params'] as $param) {
                        FilterHelper::applyMethod($query, $param);
                    }

                    return $query;
                };
            }
        }

        return $output;
    }

    /**
     * Apply method with params to query
     *
     * @param  Builder  $query  - Query to apply method to
     * @param  array  $methodParam  - Method param to apply
     *
     * @throws \Exception
     */
    public static function applyMethod(Builder &$query, array $methodParam): void
    {
        $methodName = $methodParam['method'];
        if (! is_callable([$query, $methodName])) {
            FilterHelper::throwWithParam('Invalid method name', $methodParam);
        }
        $params = $methodParam['params'];
        $query = $query->$methodName(...FilterHelper::buildParams($params));
    }

    /**
     * Apply filters to query
     *
     * @param  Builder  $query  - Query to apply filters to
     * @param  array  $filterSpecs  - Filter specs to apply
     *
     * @throws \Exception
     */
    public static function applyFilters(Builder &$query, $filterSpecs): void
    {
        foreach ($filterSpecs as $filterSpec) {
            FilterHelper::validateFilterSpec($filterSpec);
            $query = $query->where(function ($query) use ($filterSpec) {
                foreach ($filterSpec as $methodParam) {
                    FilterHelper::applyMethod($query, $methodParam);
                }

                return $query;
            });
        }
    }
}

Methods

applyFilters

  • Type: (Builder $query, array $filterSpecs) => void
  • Description: Applies provided filters to provided query.

See also: