calc/src/Calc/Valid.php
2025-07-18 20:30:41 +02:00

290 lines
11 KiB
PHP

<?php
namespace PSC\Library\Calc\Calc;
use PSC\Library\Calc\Article;
use PSC\Library\Calc\Engine;
use PSC\Library\Calc\Error\Validation\Input\Max;
use PSC\Library\Calc\Error\Validation\Input\Min;
use PSC\Library\Calc\General\Type\Edge;
use PSC\Library\Calc\General\Type\EdgeCollection;
use PSC\Library\Calc\General\Type\EdgeCollectionContainer;
use PSC\Library\Calc\Option\Type\Base;
use PSC\Library\Calc\Option\Type\Checkbox;
use PSC\Library\Calc\Option\Type\ColorDBSelect;
use PSC\Library\Calc\Option\Type\Input;
use PSC\Library\Calc\Option\Type\Row;
use PSC\Library\Calc\Option\Type\Select;
use PSC\Library\Calc\Option\Type\Select\ColorOpt;
class Valid
{
/** @var Engine */
protected $engine = null;
/** @var Article */
protected $article = null;
/** @var Formel */
protected $formelCalc;
public function __construct($engine, $article)
{
$this->engine = $engine;
$this->article = $article;
$this->formelCalc = new Formel($engine, $article);
}
public function perform($withFormel = true): void
{
$this->validRec($this->article->getOptions(), $withFormel);
}
private function validRec(\ArrayIterator $options, $withFormel = true): void
{
foreach ($options as $option) {
if ($option instanceof Row) {
foreach ($option->getColumns() as $col) {
$this->validRec($col->getOptions(), $withFormel);
}
}
if ($option instanceof Input) {
if ($option->getMaxValue() && $option->getRawValue() > $option->getMaxValue()) {
$option->addValidationError(new Max(intval($option->getRawValue()), $option->getMaxValue()));
}
if ($option->getMinValue() && $option->getRawValue() < $option->getMinValue()) {
$option->addValidationError(new Min(intval($option->getRawValue()), $option->getMinValue()));
}
}
if (($option instanceof Select || $option instanceof Checkbox) && !($option instanceof ColorDBSelect)) {
$valid = false;
$nextShouldBeValid = false;
$isDefaultValid = true;
$option->clearSelected();
/** @var Select\Opt $opt */
foreach ($option->getOptions() as $opt) {
if (count($opt->getEdgesCollectionContainer()) > 0) {
$opt->setIsValid(false);
}
$groupsValid = [];
/** @var EdgeCollection $collection */
foreach ($opt->getEdgesCollectionContainer() as $collection) {
if (!$withFormel && trim($collection->getFormel()) != '')
continue;
$groupsValid[$collection->getName()] = false;
if (trim($collection->getFormel()) != '') {
$value = $this->formelCalc->parse($collection->getFormel(), true);
eval('$value = ' . $value . ';');
/** @var Edge $edge */
foreach ($collection as $edge) {
if ($this->edgeIsValidWithValue($value, $edge)) {
//$opt->setIsValid(true);
$groupsValid[$collection->getName()] = true;
}
}
} else {
/** @var Edge $edge */
foreach ($collection as $edge) {
if ($this->edgeIsValid($collection->getName(), $edge)) {
//$opt->setIsValid(true);
$groupsValid[$collection->getName()] = true;
}
}
}
}
if (!in_array(false, $groupsValid)) {
$opt->setIsValid(true);
}
if (
!$opt->isValid() &&
$opt->getId() == $option->getDefault() &&
$option->getSelectedOptions()->count() == 0
) {
$isDefaultValid = false;
}
if ($option->getDefault() === null && $opt->isValid()) {
$option->setDefault($opt->getId());
if (!$this->engine->hasVariable($option->getId())) {
$this->engine->setVariable($option->getId(), $opt->getId());
}
}
if ($option->getDefault() !== null && $opt->isValid() && !$isDefaultValid) {
$option->setDefault($opt->getId());
$this->engine->setVariable($option->getId(), $opt->getId());
if (
isset($this->engine->validVars[$option->getId()]) &&
$opt->getId() != $this->engine->validVars[$option->getId()]
) {
$this->engine->validDirty = true;
}
$isDefaultValid = true;
}
if ($option instanceof Checkbox) {
if (
isset($this->engine->getVariables()[$option->getId()]) &&
is_array($this->engine->getVariables()[$option->getId()]) &&
in_array($opt->getId(), $this->engine->getVariables()[$option->getId()])
) {
$option->addSelectedOption($opt);
}
} else {
if (
isset($this->engine->getVariables()[$option->getId()]) &&
$this->engine->getVariables()[$option->getId()] == $opt->getId()
) {
if (!$opt->isValid()) {
$nextShouldBeValid = true;
} else {
$option->addSelectedOption($opt);
}
} else {
if ($nextShouldBeValid && $opt->isValid()) {
$this->engine->getVariables()[$option->getId()] = $opt->getId();
$option->addSelectedOption($opt);
$nextShouldBeValid = false;
}
}
}
if ($opt->isValid() && !$valid) {
$valid = true;
}
}
if ($nextShouldBeValid && $option->getSelectedOptions()->count() === 0) {
foreach ($option->getOptions() as $opt) {
if ($opt->isValid()) {
$option->addSelectedOption($opt);
break;
}
}
}
$option->processValue();
$option->setIsValid($valid);
}
if ($option instanceof ColorDBSelect) {
if (isset($this->engine->getVariables()[$option->getId()])) {
$element = array_find((array) $option->getOptions(), function (ColorOpt $o1) use ($option) {
return $o1->getId() === $this->engine->getVariables()[$option->getId()];
});
if ($element) {
$option->addSelectedOption($element);
} else {
$option->addSelectedOption($option->getOptions()[0]);
}
} elseif ($option->getDefault() != null) {
$element = array_find((array) $option->getOptions(), function (ColorOpt $o1) use ($option) {
return $o1->getId() === $option->getDefault();
});
$option->addSelectedOption($element);
} else {
$option->addSelectedOption($option->getOptions()[0]);
}
}
$mainEdges = true;
foreach ($option->getEdgesCollectionContainer() as $collection) {
/** @var Edge $edge */
$collValid = false;
foreach ($collection as $edge) {
if (!$collValid && $this->edgeIsValid($collection->getName(), $edge)) {
$collValid = true;
}
}
if (!$collValid) {
$mainEdges = false;
break;
}
}
if (!$mainEdges && $option->isValid()) {
$option->setIsValid(false);
}
$this->engine->setVariables($option->parseAdditionalValues($this->engine->getVariables()));
$this->engine->addCalcVariable($option->getId() . '_valid', (int) $option->isValid());
}
}
private function edgeIsValid(mixed $section, Edge $edge): bool
{
$valid = false;
$skipTests = false;
if (!isset($this->engine->getVariables()[$section])) {
$skipTests = true;
}
if (
!$skipTests &&
!$valid &&
$edge->isRegion() &&
$edge->getFrom() <= $this->engine->getVariables()[$section] &&
$edge->getTo() >= $this->engine->getVariables()[$section]
) {
$valid = true;
}
if (
!$skipTests &&
!$valid &&
$edge->isRegion() &&
$edge->getFrom() <= $this->engine->getVariables()[$section] &&
$edge->getTo() == 0
) {
$valid = true;
}
if (
!$skipTests &&
!$valid &&
!$edge->isRegion() &&
in_array($this->engine->getVariables()[$section], $edge->getValues())
) {
$valid = true;
}
if (!$skipTests && $valid && $edge->getEdgesCollectionContainer()->count()) {
$valid = false;
/** @var EdgeCollection $collection */
foreach ($edge->getEdgesCollectionContainer() as $collection) {
foreach ($collection as $subEdge) {
if (!$valid) {
$valid = $this->edgeIsValid($collection->getName(), $subEdge);
}
}
}
}
return $valid;
}
private function edgeIsValidWithValue(mixed $value, Edge $edge): bool
{
if ($edge->isRegion() && $edge->getFrom() <= $value && $edge->getTo() >= $value) {
return true;
}
if ($edge->isRegion() && $edge->getFrom() <= $value && $edge->getTo() == 0) {
return true;
}
if (!$edge->isRegion() && in_array($value, $edge->getValues())) {
return true;
}
return false;
}
}