[Laravel, PHP, Проектирование и рефакторинг] Подсистема событий как способ избавиться от задач по «допилу» 
    
    
        
    
    
    
    
            
    
        
            
                
                                    
                
                                    
                
                    
                
            
        
    
    
        
            
                
                
                    
                           
                    
                        Автор 
                        Сообщение 
                    
                                        
                        
                            
                                
                                
                                                                                                            news_bot ®
                                                                        
                                                                                                                                                
                                                                            
                                                                                                                
                                            Стаж: 7 лет 8 месяцев                                        
                                                                                                                
                                            Сообщений: 27286                                        
                                                                                                                                                
                                                             
                            
                                
                             
                         
                        
                            
                                
                                    
                                        
                                        
 Знаете, как бывает, задачу надо сделать не хорошо, а быстро, т.к. на нее завязаны деньги, партнеры и много всего другого очень важного для бизнеса. В итоге где-то что-то не продумали, где-то упустили, что-то захардкодили, в общем, все ради скорости. И, вроде, все хорошо, все работает, но…
Через какое-то время оказывается, что функционал нужно расширять, а сделать это сложно, не хватает гибкости. За настройками, конечно, обращаются к разработчикам. И, конечно же, это отвлекает от других задач и не покидает ощущение, что время потрачено зря.
Вот и у меня возникла такая ситуация. Когда-то по-быстрому запилили интеграцию с системой e-mail-маркетинга, а потом посыпались задачи по типу «если пользователь сделал это, необходимо вот это записать вот сюда». Из-за отсутствия наглядности бизнес-процессов возникало их пересечение, данные затирали друг друга, записывалось не то.

Хочу рассказать, как вышли из этой ситуации.
В какой-то момент в системе что-то или кто-то генерирует событие. Например, пользователь зарегистрировался, обновил данные профиля, совершил покупку и т.п.
Это событие нужно поймать и обработать. Например, отправить письмо, передать данные в CRM или какую-то другую систему. Обработчиков может быть много и их количество будет увеличиваться со временем.
Необходимо связать событие и обработчики. Запускать их нужно как безусловно, так и по некоему условию. Например, если пользователю 20 лет, то ему отправляем письмо одного вида, а если 60, то другого.
Разработка ведется на PHP на Laravel. В этом фреймворке уже есть события и обработчики, на их основе и построена подсистема.

оригинал
Обрабатывать все возможные существующие события в системе не целесообразно, будем перехватывать только события, реализующие специальный интерфейс. Согласно ему, каждое событие должно сообщать, какие данные несёт в себе и иметь свой уникальный идентификатор.
<?php App\Interfaces\Events
use Illuminate\Contracts\Support\Arrayable;
/**
* System event
* @package App\Interfaces\Events
*/
interface SystemEvent extends Arrayable
{
    /**
     * Get event id
     *
     * @return string
     */
    public static function getId(): string;
    /**
     * Event name
     *
     * @return string
     */
    public static function getName(): string;
    /**
     * Available params
     *
     * @return array
     */
    public static function getAvailableParams(): array;
    /**
     * Get param by name
     *
     * @param string $name
     *
     * @return mixed
     */
    public function getParam(string $name);
}
Ещё есть пул доступных событий. В нем регистрируются те события, которые являются системными и имеют какое-то значение для бизнес-процессов.
<?php namespace App\Interfaces\Events;
/**
* Interface for event pool
* @package App\Interfaces\Events
*/
interface EventsPool
{
    /**
     * Register event
     *
     * @param string $event
     *
     * @return mixed
     */
    public function register(string $event): self;
    /**
     * Get events list
     *
     * @return array
     */
    public function getAvailableEvents(): array;
    /**
     * @param string $alias
     *
     * @param array  $params
     *
     * @return mixed
     */
    public function create(string $alias, array $params = []);
}
Обработчик событий это просто класс, имеющий определённый интерфейс. И он, как и событие, сообщает, какие данные может принимать, что получается на выходе, имеет название и ID.
<?php namespace App\Interfaces\Actions;
/**
* Interface for system action
* @package App\Interfaces\Actions
*/
interface Action
{
    /**
     * Get ID
     *
     * @return string
     */
    public static function getId(): string;
    /**
     * Get name
     *
     * @return string
     */
    public static function getName(): string;
    /**
     * Available input params
     *
     * @return array
     */
    public static function getAvailableInput(): array;
    /**
     * Available output params
     *
     * @return array
     */
    public static function getAvailableOutput(): array;
    /**
     * Run action
     *
     * @param array $params
     *
     * @return void
     */
    public function run(array $params): void;
}
Обработчики так же регистрируются в реестре с таким же интерфейсом как у пула событий.
Рассмотрим gui настройки связи событие-обработчик. У меня он реализован с использованием knockout.js, но это не принципиально.

Как вы видите, есть блок в котором настраиваются условия запуска обработчика. Первая колонка – параметр из события, затем идёт условие и значение, с которым будет сравнение.
В настройке обработчика так же три основных колонки. Первая – параметр из обработчика. В него нужно передать параметр из события(это вторая колонка). Параметр события можно не задавать, значение может быть константой. Например, в случае регистрации по e-mail передаётся 0, а в случае регистрации через соц.сеть передаётся 1, или какие-то человекопонятные значения.
В самом начале говорил, что все началось с интеграции с системой email- маркетинга Sendsay. В момент создания сущности в нашей системе, должна создаваться так называемая «анкета» на стороне Sendsay. При создании, в неё не передаются пользовательские данные, все статично. Это тот случай, когда нужно задать произвольные значения. Добавляем строку, вбиваем название поля в анкете, а в значение тип поля.
Связь настроили, посмотрим на главный обработчик событий.
<?php namespace App\Interfaces\Events;
/**
* Interface for event processor
* @package App\Interfaces\Events
*/
interface EventProcessor
{
    /**
     * Process system event
     *
     * @param SystemEvent $event
     * @param array       $settings
     */
    public function process(SystemEvent $event, array $settings = []): void;
}
<?php namespace App\Interfaces\Events;
/**
* Interface for event processor
* @package App\Interfaces\Events
*/
interface EventProcessor
{
    /**
     * Process system event
     *
     * @param SystemEvent $event
     * @param array       $settings
     */
    public function process(SystemEvent $event, array $settings = []): void;
}
Метод process будем вызывать в SystemEventListener.
<?php namespace App\Listeners;
use App\Interfaces\Events\SystemEvent;
use App\Interfaces\Events\EventProcessor;
use App\Models\EventSettings;
use Illuminate\Support\Collection;
class SystemEventListener
{
    /** @var EventProcessor */
    private $eventProcessor;
    public function __construct(EventProcessor $eventProcessor)
    {
        $this->setEventProcessor($eventProcessor);
    }
    public function handle(SystemEvent $event): void
    {
        EventSettings::query()->where('is_active', true)->where('event_id', $event::getId())->chunk(10, function (Collection $collection) use ($event) {
            $collection->each(function (EventSettings $model) use ($event) {
                $this->getEventProcessor()->process($event, $model->settings);
            });
        });
    }
    /**
     * @return EventProcessor
     */
    public function getEventProcessor(): EventProcessor
    {
        return $this->eventProcessor;
    }
    /**
     * @param EventProcessor $eventProcessor
     *
     * @return $this
     */
    public function setEventProcessor(EventProcessor $eventProcessor): self
    {
        $this->eventProcessor = $eventProcessor;
        return $this;
    }
}
Регистрируем в провайдере:
<?php namespace App\Providers;
use App\Interfaces\Events\SystemEvent;
use App\Listeners\SystemEventListener;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
class EventServiceProvider extends ServiceProvider
{
    /**
     * The event listener mappings for the application.
     *
     * @var array
     */
    protected $listen = [
        SystemEvent::class            => [
            SystemEventListener::class,
        ],
    ];
}
В итоге мы получили возможность настраивать события в системе через интерфейс. Включать и выключать обработчики без изменения кода. Новые модули системы без дополнительных вмешательств могут добавлять свои события и/или обработчики.
После небольшого обучения все это было передано пользователям админки, что высвободило дополнительное рабочее время.
И еще немного кода.
Проверка условий и маппинг параметров:
<?php namespace App\Interfaces\Services;
/**
* Interface for service to filter data (from HUB)
* @package App\Interfaces\Services
*/
interface Filter
{
    public const CONDITION_EQUAL = '=';
    public const CONDITION_MORE = '>';
    public const CONDITION_LESS = '<';
    public const CONDITION_NOT = '!';
    public const CONDITION_BETWEEN = 'between';
    public const CONDITION_IN = 'in';
    public const CONDITION_EMPTY = 'empty';
    /**
     * Filter data
     *
     * @param array $filter
     * @param array $data
     *
     * @return array
     */
    public function filter(array $filter, array $data): array;
    /**
     * Check conditions
     *
     * @param array $conditions
     * @param array $data
     *
     * @return bool
     */
    public function check(array $conditions, array $data): bool;
}
<?php namespace App\Services;
use Illuminate\Support\Arr;
use App\Interfaces\Services\Filter as IFilter;
/**
* Service to filter data by conditions
 * @package App\Services
*/
class Filter implements IFilter
{
    /**
     * Filter data
     *
     * @param array $filter
     * @param array $data
     *
     * @return array
     */
    public function filter(array $filter, array $data): array
    {
        if (!empty($filter)) {
            foreach ($filter as $condition) {
                $field = $condition['field'] ?? null;
                if (empty($field)) {
                    continue;
                }
                $operation = $condition['operation'] ?? null;
                $value1 = $condition['value1'] ?? null;
                $value2 = $condition['value2'] ?? null;
                $success = $condition['success'] ?? null;
                $filterResult = $condition['result'] ?? null;
                $value = Arr::get($data, $field, '');
                if ($field !== null && $this->checkCondition($value, $operation, $value1, $value2)) {
                    return $success !== null ? $this->filter($success, $data) : $filterResult;
                }
            }
        }
        return [];
    }
    /**
     * Check condition
     *
     * @param $value
     * @param $condition
     * @param $value1
     * @param $value2
     *
     * @return bool
     */
    protected function checkCondition($value, $condition, $value1, $value2): bool
    {
        $result = false;
        $value = \is_string($value) ? mb_strtolower($value) : $value;
        $value1 = \is_string($value1) ? mb_strtolower($value1) : $value1;
        if ($value2 !== null) {
            $value2 = \is_string($value2) ? mb_strtolower($value2) : $value2;
        }
        $conditions = explode('|', $condition);
        $invert = \in_array(self::CONDITION_NOT, $conditions);
        $conditions = array_filter($conditions, function ($item) {
            return $item !== self::CONDITION_NOT;
        });
        $condition = implode('|', $conditions);
        switch ($condition) {
            case self::CONDITION_EQUAL:
                $result = ($value == $value1);
                break;
            case self::CONDITION_IN:
                $result = \in_array($value, (array)$value1);
                break;
            case self::CONDITION_LESS:
                $result = ($value < $value1);
                break;
            case self::CONDITION_MORE:
                $result = ($value > $value1);
                break;
            case self::CONDITION_MORE . '|' . self::CONDITION_EQUAL:
            case self::CONDITION_EQUAL . '|' . self::CONDITION_MORE:
                $result = ($value >= $value1);
                break;
            case self::CONDITION_LESS . '|' . self::CONDITION_EQUAL:
            case self::CONDITION_EQUAL . '|' . self::CONDITION_LESS:
                $result = ($value <= $value1);
                break;
            case self::CONDITION_BETWEEN:
                $result = (($value >= $value1) && ($value <= $value2));
                break;
            case self::CONDITION_EMPTY:
                $result = empty($value);
                break;
        }
        return $invert ? !$result : $result;
    }
    /**
     * Check conditions
     *
     * @param array $conditions
     * @param array $data
     *
     * @return bool
     */
    public function check(array $conditions, array $data): bool
    {
        $result = true;
        if (!empty($conditions)) {
            foreach ($conditions as $condition) {
                $field = $condition['param'] ?? null;
                if (empty($field)) {
                    continue;
                }
                $operation = $condition['condition'] ?? null;
                $value1 = $condition['value'] ?? null;
                $value2 = $condition['value2'] ?? null;
                $value = Arr::get($data, $field, '');
                $result &= $this->checkCondition($value, $operation, $value1, $value2);
            }
        }
        return $result;
    }
}
<?php namespace App\Interfaces\Services;
/**
* Interface for service to map params
* @package App\Interfaces\Services
*/
interface FieldMapper
{
    /**
     * Map
     *
     * @param array $map
     * @param array $data
     *
     * @return array
     */
    public function map(array $map, array $data): array;
}
<?php namespace App\Services;
use Illuminate\Support\Arr;
use App\Interfaces\Services\FieldMapper as IFieldMapper;
/**
* Params/fields mapper (by HUB)
* @package App\Services
*/
class FieldMapper implements IFieldMapper
{
    /**
     * Map
     *
     * @param array $map
     * @param array $data
     *
     * @return array
     */
    public function map(array $map, array $data): array
    {
        $result = [];
        foreach ($map as $from => $to) {
            $to = (array)$to;
            if (!empty($to['param']) && ($value = Arr::get($data, $to['param'])) !== null) {
                Arr::set($result, $from, $value);
            } elseif ($to['value'] !== '') {
                Arr::set($result, $from, Arr::get($data, $to['value'], isset($to['value_as_param']) && $to['value_as_param'] ? '' : $to['value']));
            }
        }
        return $result;
    }
===========
 Источник:
habr.com
===========
Похожие новости:
- [PHP] Порядок вычисления в PHP (перевод)
 
- [Анализ и проектирование систем, Программирование, Проектирование и рефакторинг, Управление разработкой] Методика проектирования архитектурных слоев на основе анемичной модели и DDD
 
- [Flask, Python, Проектирование и рефакторинг] Flask + Dependency Injector — руководство по применению dependency injection
 
- [PHP] PHP Internals News Эпизод #38: предзагрузка и WeakMaps (перевод)
 
- [Анализ и проектирование систем, Микросервисы, Проектирование и рефакторинг, Управление разработкой] От монолита к микросервисам: ускорили банковские релизы в 15 раз
 
- [PHP, Системное администрирование] Apache & Nginx. Связаны одной цепью (2 часть)
 
- [Программирование, Проектирование и рефакторинг, Совершенный код] Поговорим о код-ревью
 
- [PHP] Hire PHP Developers: Cost & Procedure
 
- [UML Design, Анализ и проектирование систем, Программирование, Разработка веб-сайтов] UML для самых маленьких: диаграмма классов
 
- [PHP] Получение видео из Tik Tok без водяного знака
Теги для поиска: #_laravel, #_php, #_proektirovanie_i_refaktoring (Проектирование и рефакторинг), #_arhitektura_prilozhenij (архитектура приложений), #_php, #_laravel, #_laravel, #_php, #_proektirovanie_i_refaktoring (
Проектирование и рефакторинг
)
                                        
                                        
                                        
                                     
                                    
                                    
                                                                    
                                                                                             
                         
                        
                            
                                                                    
                                                             
                         
                    
                    
                
                
            
        
    
    
    
    
    
            
    
            
    
        
    
    
        
                        Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
    
    
        
        Текущее время: 31-Окт 07:17
Часовой пояс: UTC + 5 
            
    
                
| Автор | Сообщение | 
|---|---|
| news_bot ® 
                                                                            
                                                                                                                
                                            Стаж: 7 лет 8 месяцев                                         | |
| Знаете, как бывает, задачу надо сделать не хорошо, а быстро, т.к. на нее завязаны деньги, партнеры и много всего другого очень важного для бизнеса. В итоге где-то что-то не продумали, где-то упустили, что-то захардкодили, в общем, все ради скорости. И, вроде, все хорошо, все работает, но… Через какое-то время оказывается, что функционал нужно расширять, а сделать это сложно, не хватает гибкости. За настройками, конечно, обращаются к разработчикам. И, конечно же, это отвлекает от других задач и не покидает ощущение, что время потрачено зря. Вот и у меня возникла такая ситуация. Когда-то по-быстрому запилили интеграцию с системой e-mail-маркетинга, а потом посыпались задачи по типу «если пользователь сделал это, необходимо вот это записать вот сюда». Из-за отсутствия наглядности бизнес-процессов возникало их пересечение, данные затирали друг друга, записывалось не то.  Хочу рассказать, как вышли из этой ситуации. В какой-то момент в системе что-то или кто-то генерирует событие. Например, пользователь зарегистрировался, обновил данные профиля, совершил покупку и т.п. Это событие нужно поймать и обработать. Например, отправить письмо, передать данные в CRM или какую-то другую систему. Обработчиков может быть много и их количество будет увеличиваться со временем. Необходимо связать событие и обработчики. Запускать их нужно как безусловно, так и по некоему условию. Например, если пользователю 20 лет, то ему отправляем письмо одного вида, а если 60, то другого. Разработка ведется на PHP на Laravel. В этом фреймворке уже есть события и обработчики, на их основе и построена подсистема.  оригинал Обрабатывать все возможные существующие события в системе не целесообразно, будем перехватывать только события, реализующие специальный интерфейс. Согласно ему, каждое событие должно сообщать, какие данные несёт в себе и иметь свой уникальный идентификатор. <?php App\Interfaces\Events use Illuminate\Contracts\Support\Arrayable; /** * System event * @package App\Interfaces\Events */ interface SystemEvent extends Arrayable { /** * Get event id * * @return string */ public static function getId(): string; /** * Event name * * @return string */ public static function getName(): string; /** * Available params * * @return array */ public static function getAvailableParams(): array; /** * Get param by name * * @param string $name * * @return mixed */ public function getParam(string $name); } Ещё есть пул доступных событий. В нем регистрируются те события, которые являются системными и имеют какое-то значение для бизнес-процессов. <?php namespace App\Interfaces\Events; /** * Interface for event pool * @package App\Interfaces\Events */ interface EventsPool { /** * Register event * * @param string $event * * @return mixed */ public function register(string $event): self; /** * Get events list * * @return array */ public function getAvailableEvents(): array; /** * @param string $alias * * @param array $params * * @return mixed */ public function create(string $alias, array $params = []); } Обработчик событий это просто класс, имеющий определённый интерфейс. И он, как и событие, сообщает, какие данные может принимать, что получается на выходе, имеет название и ID. <?php namespace App\Interfaces\Actions; /** * Interface for system action * @package App\Interfaces\Actions */ interface Action { /** * Get ID * * @return string */ public static function getId(): string; /** * Get name * * @return string */ public static function getName(): string; /** * Available input params * * @return array */ public static function getAvailableInput(): array; /** * Available output params * * @return array */ public static function getAvailableOutput(): array; /** * Run action * * @param array $params * * @return void */ public function run(array $params): void; } Обработчики так же регистрируются в реестре с таким же интерфейсом как у пула событий. Рассмотрим gui настройки связи событие-обработчик. У меня он реализован с использованием knockout.js, но это не принципиально.  Как вы видите, есть блок в котором настраиваются условия запуска обработчика. Первая колонка – параметр из события, затем идёт условие и значение, с которым будет сравнение. В настройке обработчика так же три основных колонки. Первая – параметр из обработчика. В него нужно передать параметр из события(это вторая колонка). Параметр события можно не задавать, значение может быть константой. Например, в случае регистрации по e-mail передаётся 0, а в случае регистрации через соц.сеть передаётся 1, или какие-то человекопонятные значения. В самом начале говорил, что все началось с интеграции с системой email- маркетинга Sendsay. В момент создания сущности в нашей системе, должна создаваться так называемая «анкета» на стороне Sendsay. При создании, в неё не передаются пользовательские данные, все статично. Это тот случай, когда нужно задать произвольные значения. Добавляем строку, вбиваем название поля в анкете, а в значение тип поля. Связь настроили, посмотрим на главный обработчик событий. <?php namespace App\Interfaces\Events; /** * Interface for event processor * @package App\Interfaces\Events */ interface EventProcessor { /** * Process system event * * @param SystemEvent $event * @param array $settings */ public function process(SystemEvent $event, array $settings = []): void; } <?php namespace App\Interfaces\Events; /** * Interface for event processor * @package App\Interfaces\Events */ interface EventProcessor { /** * Process system event * * @param SystemEvent $event * @param array $settings */ public function process(SystemEvent $event, array $settings = []): void; } Метод process будем вызывать в SystemEventListener. <?php namespace App\Listeners; use App\Interfaces\Events\SystemEvent; use App\Interfaces\Events\EventProcessor; use App\Models\EventSettings; use Illuminate\Support\Collection; class SystemEventListener { /** @var EventProcessor */ private $eventProcessor; public function __construct(EventProcessor $eventProcessor) { $this->setEventProcessor($eventProcessor); } public function handle(SystemEvent $event): void { EventSettings::query()->where('is_active', true)->where('event_id', $event::getId())->chunk(10, function (Collection $collection) use ($event) { $collection->each(function (EventSettings $model) use ($event) { $this->getEventProcessor()->process($event, $model->settings); }); }); } /** * @return EventProcessor */ public function getEventProcessor(): EventProcessor { return $this->eventProcessor; } /** * @param EventProcessor $eventProcessor * * @return $this */ public function setEventProcessor(EventProcessor $eventProcessor): self { $this->eventProcessor = $eventProcessor; return $this; } } Регистрируем в провайдере: <?php namespace App\Providers; use App\Interfaces\Events\SystemEvent; use App\Listeners\SystemEventListener; use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider; class EventServiceProvider extends ServiceProvider { /** * The event listener mappings for the application. * * @var array */ protected $listen = [ SystemEvent::class => [ SystemEventListener::class, ], ]; } В итоге мы получили возможность настраивать события в системе через интерфейс. Включать и выключать обработчики без изменения кода. Новые модули системы без дополнительных вмешательств могут добавлять свои события и/или обработчики. После небольшого обучения все это было передано пользователям админки, что высвободило дополнительное рабочее время. И еще немного кода. Проверка условий и маппинг параметров: <?php namespace App\Interfaces\Services; /** * Interface for service to filter data (from HUB) * @package App\Interfaces\Services */ interface Filter { public const CONDITION_EQUAL = '='; public const CONDITION_MORE = '>'; public const CONDITION_LESS = '<'; public const CONDITION_NOT = '!'; public const CONDITION_BETWEEN = 'between'; public const CONDITION_IN = 'in'; public const CONDITION_EMPTY = 'empty'; /** * Filter data * * @param array $filter * @param array $data * * @return array */ public function filter(array $filter, array $data): array; /** * Check conditions * * @param array $conditions * @param array $data * * @return bool */ public function check(array $conditions, array $data): bool; } <?php namespace App\Services; use Illuminate\Support\Arr; use App\Interfaces\Services\Filter as IFilter; /** * Service to filter data by conditions * @package App\Services */ class Filter implements IFilter { /** * Filter data * * @param array $filter * @param array $data * * @return array */ public function filter(array $filter, array $data): array { if (!empty($filter)) { foreach ($filter as $condition) { $field = $condition['field'] ?? null; if (empty($field)) { continue; } $operation = $condition['operation'] ?? null; $value1 = $condition['value1'] ?? null; $value2 = $condition['value2'] ?? null; $success = $condition['success'] ?? null; $filterResult = $condition['result'] ?? null; $value = Arr::get($data, $field, ''); if ($field !== null && $this->checkCondition($value, $operation, $value1, $value2)) { return $success !== null ? $this->filter($success, $data) : $filterResult; } } } return []; } /** * Check condition * * @param $value * @param $condition * @param $value1 * @param $value2 * * @return bool */ protected function checkCondition($value, $condition, $value1, $value2): bool { $result = false; $value = \is_string($value) ? mb_strtolower($value) : $value; $value1 = \is_string($value1) ? mb_strtolower($value1) : $value1; if ($value2 !== null) { $value2 = \is_string($value2) ? mb_strtolower($value2) : $value2; } $conditions = explode('|', $condition); $invert = \in_array(self::CONDITION_NOT, $conditions); $conditions = array_filter($conditions, function ($item) { return $item !== self::CONDITION_NOT; }); $condition = implode('|', $conditions); switch ($condition) { case self::CONDITION_EQUAL: $result = ($value == $value1); break; case self::CONDITION_IN: $result = \in_array($value, (array)$value1); break; case self::CONDITION_LESS: $result = ($value < $value1); break; case self::CONDITION_MORE: $result = ($value > $value1); break; case self::CONDITION_MORE . '|' . self::CONDITION_EQUAL: case self::CONDITION_EQUAL . '|' . self::CONDITION_MORE: $result = ($value >= $value1); break; case self::CONDITION_LESS . '|' . self::CONDITION_EQUAL: case self::CONDITION_EQUAL . '|' . self::CONDITION_LESS: $result = ($value <= $value1); break; case self::CONDITION_BETWEEN: $result = (($value >= $value1) && ($value <= $value2)); break; case self::CONDITION_EMPTY: $result = empty($value); break; } return $invert ? !$result : $result; } /** * Check conditions * * @param array $conditions * @param array $data * * @return bool */ public function check(array $conditions, array $data): bool { $result = true; if (!empty($conditions)) { foreach ($conditions as $condition) { $field = $condition['param'] ?? null; if (empty($field)) { continue; } $operation = $condition['condition'] ?? null; $value1 = $condition['value'] ?? null; $value2 = $condition['value2'] ?? null; $value = Arr::get($data, $field, ''); $result &= $this->checkCondition($value, $operation, $value1, $value2); } } return $result; } } <?php namespace App\Interfaces\Services; /** * Interface for service to map params * @package App\Interfaces\Services */ interface FieldMapper { /** * Map * * @param array $map * @param array $data * * @return array */ public function map(array $map, array $data): array; } <?php namespace App\Services; use Illuminate\Support\Arr; use App\Interfaces\Services\FieldMapper as IFieldMapper; /** * Params/fields mapper (by HUB) * @package App\Services */ class FieldMapper implements IFieldMapper { /** * Map * * @param array $map * @param array $data * * @return array */ public function map(array $map, array $data): array { $result = []; foreach ($map as $from => $to) { $to = (array)$to; if (!empty($to['param']) && ($value = Arr::get($data, $to['param'])) !== null) { Arr::set($result, $from, $value); } elseif ($to['value'] !== '') { Arr::set($result, $from, Arr::get($data, $to['value'], isset($to['value_as_param']) && $to['value_as_param'] ? '' : $to['value'])); } } return $result; } =========== Источник: habr.com =========== Похожие новости: 
 Проектирование и рефакторинг ) | |
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
    Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 31-Окт 07:17
Часовой пояс: UTC + 5 
