Last active
February 5, 2020 15:45
-
-
Save kmuenkel/f1fb4d5430ea4e5c6326297d291b26af to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace App\Entities; | |
use Illuminate\Database\Eloquent\Model | |
/** | |
* Class Contact | |
* @package App\Entities | |
*/ | |
class Rule extends Model | |
{ | |
/** | |
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo | |
*/ | |
public function child1() | |
{ | |
return $this->belongsTo(Rule::class, 'child1', 'name'); | |
} | |
/** | |
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo | |
*/ | |
public function child2() | |
{ | |
return $this->belongsTo(Rule::class, 'child2', 'name'); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace App\Services; | |
use Arr; | |
use Validator; | |
use App\Entities\Rule; | |
/** | |
* Class RuleParser | |
* @package App\Services | |
*/ | |
class RuleParser | |
{ | |
/** | |
* @var array | |
*/ | |
protected $seed = []; | |
/** | |
* @var array | |
*/ | |
protected $config = []; | |
/** | |
* @var array | |
*/ | |
protected $failures = []; | |
/** | |
* RuleParser constructor. | |
* @param array $seed | |
* @param array $config | |
*/ | |
public function __construct(array $seed = [], array $config = []) | |
{ | |
$this->seed($seed); | |
$this->addConfig($config); | |
} | |
/** | |
* @param array $seed | |
* @return $this | |
*/ | |
public function seed(array $seed = []) | |
{ | |
$this->seed = Arr::dot($seed); | |
return $this; | |
} | |
/** | |
* @return array | |
*/ | |
public function getSeed() | |
{ | |
return array_tree($this->seed); | |
} | |
/** | |
* @param array $config | |
* @return $this | |
*/ | |
public function addConfig(array $config = []) | |
{ | |
$this->config = array_merge($this->config, $config); | |
return $this; | |
} | |
/** | |
* @param int $ruleId | |
* @return bool | |
*/ | |
public function evaluate($ruleId) | |
{ | |
$rule = !empty($this->config) ? $this->config[$ruleId] | |
: app(Rule::class)->where('name', $ruleId)->first()->toArray(); | |
$value1 = Arr::get($rule, 'value1'); | |
if (Arr::get($rule, 'reference1')) { | |
$value1 = []; | |
foreach ($this->seed as $field => $value) { | |
$field = str_replace("\x00", '', $field); | |
if (fnmatch(Arr::get($rule, 'reference1'), $field)) { | |
$value1[] = $value; | |
} | |
} | |
if (strpos(Arr::get($rule, 'reference1'), '*') === false) { | |
$value1 = Arr::first($value1, null); | |
} | |
} | |
if (Arr::get($rule, 'child1')) { | |
$value1 = $this->evaluate(Arr::get($rule, 'child1')); | |
} | |
$value2 = Arr::get($rule, 'value2'); | |
if (Arr::get($rule, 'reference2')) { | |
$value2 = []; | |
foreach ($this->seed as $field => $value) { | |
$field = str_replace("\x00", '', $field); | |
if (fnmatch(Arr::get($rule, 'reference2'), $field)) { | |
$value2[] = $value; | |
} | |
} | |
if (strpos(Arr::get($rule, 'reference2'), '*') === false) { | |
$value2 = Arr::first($value2, null); | |
} | |
} | |
if (Arr::get($rule, 'child2')) { | |
$value2 = $this->evaluate(Arr::get($rule, 'child2')); | |
} | |
$comparator = Arr::get($rule, 'comparator'); | |
switch ($comparator) { | |
case '==': | |
$success = $value1 == $value2; | |
break; | |
case '===': | |
$success = $value1 === $value2; | |
break; | |
case '!=': | |
$success = $value1 != $value2; | |
break; | |
case '!==': | |
$success = $value1 !== $value2; | |
break; | |
case '>': | |
$success = $value1 > $value2; | |
break; | |
case '<': | |
$success = $value1 < $value2; | |
break; | |
case 'in': | |
$success = in_array($value1, $value2); | |
break; | |
case 'not in': | |
$success = !in_array($value1, $value2); | |
break; | |
case 'and': | |
case '&&': | |
$success = $value1 && $value2; | |
break; | |
case 'or': | |
case '||': | |
$success = $value1 || $value2; | |
break; | |
case 'valid': | |
$success = Validator::make(['data' => $value1], ['data' => $value2])->passes(); | |
break; | |
default: | |
$success = false; | |
} | |
if (!$success) { | |
$this->failures[$ruleId] = [ | |
'rule' => $rule, | |
'values' => [ | |
'value1' => $value1, | |
'value2' => $value2 | |
] | |
]; | |
} | |
return $success; | |
} | |
/** | |
* @param mixed ...$fields | |
* @return array | |
*/ | |
public function getFailures(...$fields) | |
{ | |
$first = Arr::first($fields); | |
$fields = is_array($first) ? $first : $fields; | |
$failures = $this->failures; | |
if (!empty($fields)) { | |
/** @var array $failure */ | |
foreach ($failures as $index => $failure) { | |
$failures[$index] = Arr::only($failure, $fields); | |
} | |
} | |
$failures['data'] = $this->seed; | |
return $failures; | |
} | |
/** | |
* @return $this | |
*/ | |
public function reset() | |
{ | |
$this->failures = []; | |
return $this; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment