Skip to content

Instantly share code, notes, and snippets.

@kmuenkel
Last active February 5, 2020 15:45
Show Gist options
  • Save kmuenkel/f1fb4d5430ea4e5c6326297d291b26af to your computer and use it in GitHub Desktop.
Save kmuenkel/f1fb4d5430ea4e5c6326297d291b26af to your computer and use it in GitHub Desktop.
<?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');
}
}
<?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