calc/src/Engine.php
2025-06-05 17:06:22 +02:00

649 lines
14 KiB
PHP

<?php
namespace PSC\Library\Calc;
use Doctrine\Persistence\ObjectRepository;
use PSC\Library\Calc\Calc\Calc;
use PSC\Library\Calc\Calc\CalcValues;
use PSC\Library\Calc\Calc\Valid;
use PSC\Library\Calc\Option\Type\Base;
use PSC\Library\Calc\Option\Type\Checkbox;
use PSC\Library\Calc\Option\Type\PaperDbSelect;
use PSC\Library\Calc\Option\Type\Select\Opt;
use PSC\Library\Calc\Option\Type\Text;
class Engine
{
/** @var \SimpleXMLElement $xml */
protected $xml;
/** @var \ArrayIterator $articles */
protected $articles;
/** @var PaperContainer $paperContainer */
protected $paperContainer;
/** @var ObjectRepository */
protected $paperRepository;
/** @var string */
protected $formulas = "";
/** @var string */
protected $parameters = "";
/** @var array */
protected $variables = array();
/** @var array */
protected $calcVariables = array();
/** @var array */
protected $ajaxVariables = array();
/** @var array */
protected $displayVariables = array();
/** @var array */
protected $debugCalcFormel = array();
/** @var array */
protected $debugCalcVariables = array();
protected $debugFlatPrice = array();
protected $preCalc = array();
protected $debugPrice = array();
/** @var float */
protected $price = 0;
protected float $weight = 0;
protected float $weightSingle = 0;
/** @var float */
protected $tax = 0;
/** @var bool */
protected $dirty = true;
public $validDirty = true;
public $validVars = [];
/** @var Article */
protected $article = null;
/** @var string */
protected $activeArticle = false;
/** @var \SimpleXMLElement $templates */
protected $templates;
protected $savedCalcValues = [];
/**
* Load XML From String
*
* @param $string XML String
*
* @return bool
*/
public function loadString($string)
{
$this->articles = new \ArrayIterator();
$this->xml = simplexml_load_string($string);
$this->activeArticle = false;
$this->calcVariables = [];
$this->variables = [];
$this->parse();
return true;
}
/**
* Parse Xml
*/
protected function parse()
{
$parser = new Parser();
$parser->setPaperContainer($this->paperContainer);
$parser->setPaperRepository($this->paperRepository);
if($this->templates) {
$parser->setTemplates($this->templates);
}
foreach ($this->xml as $article) {
$this->articles->append($parser->parse($article));
}
$this->dirty = true;
}
/**
* @return \ArrayIterator
*/
public function getArticles()
{
return $this->articles;
}
/**
* @param bool $name
* @return Article
* @throws \Exception
*/
private function getArticleByName($name = false)
{
if($name === false && $this->activeArticle === false) {
$this->activeArticle = $this->articles[0]->getName();
return $this->articles[0];
}
if($name === false && $this->activeArticle !== false) {
$name = $this->activeArticle;
}
/** @var Article $article */
foreach($this->articles as $article)
{
if($article->getName() == $name) {
return $article;
}
}
return $this->articles[0];
}
/**
* @return PaperContainer
*/
public function getPaperContainer()
{
return $this->paperContainer;
}
/**
* @param PaperContainer $paperContainer
*/
public function setPaperContainer($paperContainer)
{
$this->dirty = true;
$this->paperContainer = $paperContainer;
}
/**
* @return ObjectRepository
*/
public function getPaperRepository()
{
return $this->paperRepository;
}
/**
* @param ObjectRepository $paperRepository
*/
public function setPaperRepository($paperRepository)
{
$this->dirty = true;
$this->paperRepository = $paperRepository;
}
/**
* @return string
*/
public function getFormulas()
{
return $this->formulas;
}
/**
* @param string $formulas
*/
public function setFormulas($formulas)
{
$this->dirty = true;
$this->formulas = $formulas;
}
/**
* @return string
*/
public function getParameters()
{
return $this->parameters;
}
/**
* @param string $parameters
*/
public function setParameters($parameters)
{
$this->dirty = true;
$this->parameters = $parameters;
}
/**
* @return array
*/
public function getVariables()
{
return $this->variables;
}
/**
* @param array $variables
*/
public function setVariables($variables)
{
$this->dirty = true;
$this->variables = $variables;
}
public function calc() {
$this->debugCalcFormel = [];
$this->debugCalcVariables = [];
$this->debugFlatPrice = [];
$this->debugPrice = [];
$this->price = 0;
$tmp = [];
foreach ($this->variables as $key => $variable) {
if(!is_array($variable)) {
if($variable !== null) {
$tmp[$key] = str_replace(",", ".", $variable);
}
}else{
$tmp[$key] = $variable;
}
}
$this->variables = $tmp;
$this->article = $this->getArticleByName($this->activeArticle);
if($this->article === null) {
$this->dirty = false;
return true;
}
// Prefill with defaults
/** @var Base $option */
foreach($this->article->getOptions() as $option) {
$option->setSavedCalcValues($this->savedCalcValues);
if(!isset($this->variables[$option->getId()]) && $option->getDefault() !== null && !$option instanceof Text) {
if($option instanceof Checkbox) {
$this->variables[$option->getId()] = explode(",", $option->getDefault());
}else{
$this->variables[$option->getId()] = $option->getDefault();
}
}
if(isset($this->variables[$option->getId()])) {
$option->setRawValue($this->variables[$option->getId()]);
$option->processValue();
}
}
$this->processCalc();
$switchedOptions = $this->checkDoubleOptions();
if(count($switchedOptions) > 0) {
foreach($switchedOptions as $option) {
if($option->getDefault() !== null && !$option instanceof Text) {
if($option instanceof Checkbox) {
$this->variables[$option->getId()] = explode(",", $option->getDefault());
}else{
$this->variables[$option->getId()] = $option->getDefault();
}
}
if(isset($this->variables[$option->getId()])) {
$option->setRawValue($this->variables[$option->getId()]);
$option->processValue();
}
}
$this->processCalc();
}
$this->dirty = false;
return true;
}
/**
* @return mixed
*/
public function getPrice()
{
if($this->dirty) {
$this->calc();
}
return round($this->price,2);
}
/**
* @return mixed
*/
public function getTaxPrice()
{
if($this->dirty) {
$this->calc();
}
return round(($this->price/100*$this->tax),2);
}
/**
* @return mixed
*/
public function getCompletePrice()
{
if($this->dirty) {
$this->calc();
}
return round($this->price+($this->price/100*$this->tax),2);
}
/**
* @param mixed $price
*/
public function setPrice($price)
{
$this->price = $price;
}
public function addDebugCalcVariables($id, $orgVar, $var)
{
$this->debugCalcVariables[$id] = [$orgVar, $var];
}
public function getDebugCalcVariables()
{
return $this->debugCalcVariables;
}
public function addDebugCalcFormel($orgFormel, $formel)
{
$this->debugCalcFormel[] = [$orgFormel, $formel];
}
public function getDebugCalcFormel()
{
return $this->debugCalcFormel;
}
public function addDebugFlatPrice($key, $flatPrice)
{
if(!isset($this->debugFlatPrice[$key])) {
$this->debugFlatPrice[$key] = array();
}
$this->debugFlatPrice[$key][] = $flatPrice;
}
public function getDebugFlatPrice()
{
return $this->debugFlatPrice;
}
public function addDebugPrice($key, $price, $multiplicator, $result)
{
if(!isset($this->debugPrice[$key])) {
$this->debugPrice[$key] = array();
}
$this->debugPrice[$key][] = [
'price' => $price,
'multiplicator' => $multiplicator,
'result' => $result
];
}
public function getDebugPrice()
{
return $this->debugPrice;
}
/**
* @return array
*/
public function getCalcVariables()
{
return $this->calcVariables;
}
/**
* @param array $calcVariables
*/
public function setCalcVariables($calcVariables)
{
$this->calcVariables = $calcVariables;
}
/**
* @param $value
* @param array $stack
*/
public function setCalcVaribleStack($value, $stack = [])
{
$id = array_shift($stack);
foreach($stack as $row) {
$id = $id . '_' . $row;
if(!isset($this->calcVariables[$id]) || $this->calcVariables[$id] == 0) {
$this->calcVariables[$id] = $value;
}
}
}
public function addCalcVariable($id, $value) {
$this->calcVariables[$id] = $value;
}
public function setVariable($var, $value)
{
$this->dirty = true;
$this->variables[$var] = $value;
}
public function hasVariable($var): bool
{
return isset($this->variables[$var]);
}
/**
* @return float
*/
public function getTax()
{
return $this->tax;
}
/**
* @param float $tax
*/
public function setTax($tax)
{
$this->tax = $tax;
}
/**
* @return Article
*/
public function getArticle()
{
if($this->dirty) {
$this->calc();
}
return $this->article;
}
/**
* @param string $activeArticle
*/
public function setActiveArticle($activeArticle)
{
$this->activeArticle = $activeArticle;
$this->dirty = true;
}
public function setSymfonyFormVariables($data)
{
$tmp = [];
foreach($data as $key => $value) {
if($value instanceof Opt) {
$tmp[$key] = $value->getId();
}else{
$tmp[$key] = $value;
}
}
return $tmp;
}
public function setTemplates($templates)
{
$this->templates = simplexml_load_string($templates);
}
/**
* @return \SimpleXMLElement
*/
public function getTemplates()
{
return $this->templates;
}
public function setSavedCalcReferences($values)
{
$this->savedCalcValues = $values;
}
/**
* @return array
*/
public function getAjaxVariables()
{
return $this->ajaxVariables;
}
/**
* @param array $ajaxVariables
*/
public function setAjaxVariables($ajaxVariables)
{
$this->ajaxVariables = $ajaxVariables;
}
public function addAjaxVariable($key, $value)
{
$this->ajaxVariables[$key] = $value;
}
/**
* @return array
*/
public function getDisplayVariables()
{
return $this->displayVariables;
}
/**
* @param array $displayVariables
*/
public function setDisplayVariables($displayVariables)
{
$this->displayVariables = $displayVariables;
}
public function addDisplayVariable($key, $value)
{
$this->displayVariables[$key] = $value;
}
public function setWeight(float $var): void
{
$this->weight = $var;
}
public function getWeight(): float
{
if($this->dirty) {
$this->calc();
}
return $this->weight;
}
public function setWeightSingle(float $var): void
{
$this->weightSingle = $var;
}
public function getWeightSingle(): float
{
if($this->dirty) {
$this->calc();
}
return $this->weightSingle;
}
private function checkDoubleOptions(): array
{
$options = [];
$switchedOptions = [];
/** @var Base $option */
foreach($this->article->getOptions() as $option) {
if($option->isValid()) {
$options[] = $option;
}else{
$foundValid = array_filter($this->article->getOptions()->getArrayCopy(), function(Base $elm) use ($option) {
if($elm->getId() == $option->getId() && $elm->isValid()) {
return $elm;
}
});
if(count($foundValid) == 0) {
$options[] = $option;
}else{
$switchedOptions[] = array_shift($foundValid);
}
}
}
$this->article->setOptions($options);
return $switchedOptions;
}
private function processCalc(): void
{
$this->validDirty = true;
$count = 1;
// Check if Option is valid
while($this->validDirty && $count < 4) {
$this->validDirty = false;
$this->validVars = $this->variables;
$calcValid = new Valid($this, $this->article);
$calcValid->perform();
// CALC Values
$calcValues = new CalcValues($this, $this->article);
$calcValues->calc();
$count++;
}
$calcValid = new Valid($this, $this->article);
$calcValid->perform();
// CALC Values
$calcValues = new CalcValues($this, $this->article);
$calcValues->calc();
// Check if Option is valid
// CALC Formel
$calcFormel = new Calc($this, $this->article);
$this->price = $calcFormel->calc();
}
}