This commit is contained in:
Thomas Peterson 2025-07-11 16:39:35 +02:00
parent 12807410f2
commit 93e6d572f9
15 changed files with 3064 additions and 2929 deletions

File diff suppressed because it is too large Load Diff

View File

@ -183,7 +183,7 @@ class Calc
$this->engine->addDebugCalcFormel($edge->getFormel(), $formel . ' = ' . $p); $this->engine->addDebugCalcFormel($edge->getFormel(), $formel . ' = ' . $p);
$this->engine->getCalcGraph()->addCalcFormel(new Part( $this->engine->getCalcGraph()->addCalcFormel(new Part(
type: PartType::Formel, type: PartType::Formel,
name: $collection->getName(), name: sprintf('%s-%s', $option->getId(), $collection->getName()),
unParsed: $edge->getFormel(), unParsed: $edge->getFormel(),
)); ));
} catch (\Throwable $e) { } catch (\Throwable $e) {

View File

@ -324,6 +324,22 @@ class Engine
} }
} }
foreach ($this->calcVariables as $key => $variable) {
if (is_array($variable)) {
$this->calcGraph->addPart(new Part(
type: PartType::CalcValue,
name: $key,
unParsed: implode(',', $variable),
));
} elseif ($variable != null) {
$this->calcGraph->addPart(new Part(
type: PartType::CalcValue,
name: $key,
unParsed: $variable,
));
}
}
$this->dirty = false; $this->dirty = false;
return true; return true;
} }

View File

@ -11,8 +11,10 @@ class Calc
{ {
private Math $math; private Math $math;
public function __construct() public function __construct(
{ private string $params,
private string $formulas,
) {
$this->math = new Math(); $this->math = new Math();
$this->math->suppress_errors = true; $this->math->suppress_errors = true;
} }
@ -25,7 +27,10 @@ class Calc
foreach ($yield as $y) { foreach ($yield as $y) {
$this->parsePart($y); $this->parsePart($y);
$y->setResult($this->math->evaluate($y->getParsed())); eval($this->params);
eval($this->formulas);
eval('$result = ' . $y->getParsed() . ';');
$y->setResult($result);
} }
} }

View File

@ -21,12 +21,12 @@ class Graph
{ {
$this->calcFormel = new PartCollection(); $this->calcFormel = new PartCollection();
$this->parser = new Parser($formulas, $params); $this->parser = new Parser($formulas, $params);
$this->calc = new Calc(); $this->calc = new Calc($params, $formulas);
} }
public function addCalcFormel(Part $formel): void public function addCalcFormel(Part $formel): void
{ {
$this->calcFormel->append($formel); $this->calcFormel->addPart($formel);
} }
public function addPart(Part $part): void public function addPart(Part $part): void
@ -36,27 +36,28 @@ class Graph
private function build(): bool private function build(): bool
{ {
foreach ($this->calcFormel as $formel) { $this->parser->parseInternals();
foreach ($this->calcFormel->getData() as $formel) {
$this->parser->parse($formel); $this->parser->parse($formel);
} }
foreach ($this->calcFormel as $formel) { foreach ($this->calcFormel->getData() as $formel) {
$this->calc->calc($formel); $this->calc->calc($formel);
} }
return true; return true;
} }
public function getSum(): int public function getSum(): float
{ {
return array_reduce((array) $this->calcFormel, fn($sum, $item) => $sum + $item->getResult(), 0); return round(array_reduce($this->calcFormel->getData(), fn($sum, $item) => $sum + $item->getResult(), 0), 2);
} }
public function generateJsonGraph(): string public function generateJsonGraph(): string
{ {
$this->build(); $this->build();
$json = []; $json = [];
foreach ($this->calcFormel as $part) { foreach ($this->calcFormel->getData() as $part) {
$json[] = $part->toArray(); $json[] = $part->toArray();
} }

View File

@ -5,6 +5,7 @@ namespace PSC\Library\Calc\Graph;
use PhpParser\Error; use PhpParser\Error;
use PhpParser\Node; use PhpParser\Node;
use PhpParser\Node\Expr\Assign; use PhpParser\Node\Expr\Assign;
use PhpParser\Node\Stmt\If_;
use PhpParser\NodeTraverser; use PhpParser\NodeTraverser;
use PhpParser\NodeVisitorAbstract; use PhpParser\NodeVisitorAbstract;
use PhpParser\ParserFactory; use PhpParser\ParserFactory;
@ -40,11 +41,15 @@ class Parser
$this->mode = $mode; $this->mode = $mode;
} }
public function enterNode(Node $node): void public function enterNode(Node $node): null|int
{ {
if ($node instanceof If_) {
return NodeTraverser::DONT_TRAVERSE_CHILDREN;
}
if ($node instanceof Assign && $this->mode === 1) { if ($node instanceof Assign && $this->mode === 1) {
if ($node->expr->value != null && $node->var->name != null) { if ($node->expr->value != null && $node->var->name != null) {
$this->internalParts->append(new Part( $this->internalParts->addPart(new Part(
type: PartType::Formel, type: PartType::Formel,
name: $node->var->name, name: $node->var->name,
unParsed: (string) $node->expr->value, unParsed: (string) $node->expr->value,
@ -53,13 +58,14 @@ class Parser
} }
if ($node instanceof Assign && $this->mode === 2) { if ($node instanceof Assign && $this->mode === 2) {
if ($node->expr->value != null && $node->var->name != null) { if ($node->expr->value != null && $node->var->name != null) {
$this->internalParts->append(new Part( $this->internalParts->addPart(new Part(
type: PartType::Parameter, type: PartType::Parameter,
name: $node->var->name, name: $node->var->name,
unParsed: (string) $node->expr->value, unParsed: (string) $node->expr->value,
)); ));
} }
} }
return null;
} }
}; };
@ -67,7 +73,7 @@ class Parser
$parser = new ParserFactory()->createForNewestSupportedVersion(); $parser = new ParserFactory()->createForNewestSupportedVersion();
try { try {
$ast = $parser->parse('<?php' . PHP_EOL . $formulas); $ast = $parser->parse('<?php' . PHP_EOL . $this->formulas);
$traverser->traverse($ast); $traverser->traverse($ast);
} catch (Error $error) { } catch (Error $error) {
echo "Parse error: {$error->getMessage()}\n"; echo "Parse error: {$error->getMessage()}\n";
@ -77,7 +83,7 @@ class Parser
$visitor->setMode(2); $visitor->setMode(2);
try { try {
$ast = $parser->parse('<?php' . PHP_EOL . $params); $ast = $parser->parse('<?php' . PHP_EOL . $this->params);
$traverser->traverse($ast); $traverser->traverse($ast);
} catch (Error $error) { } catch (Error $error) {
echo "Parse error: {$error->getMessage()}\n"; echo "Parse error: {$error->getMessage()}\n";

View File

@ -44,6 +44,8 @@ class Part extends Node
return sprintf('$V%s$V', $this->name); return sprintf('$V%s$V', $this->name);
case PartType::CalcValue: case PartType::CalcValue:
return sprintf('$CV%s$CV', $this->name); return sprintf('$CV%s$CV', $this->name);
default:
return $this->name;
} }
} }

View File

@ -4,38 +4,22 @@ namespace PSC\Library\Calc\Model;
use PSC\Library\Calc\Model\Part; use PSC\Library\Calc\Model\Part;
class PartCollection extends \ArrayIterator class PartCollection
{ {
protected array $data = [];
public function getPartByName($string): Part|null public function getPartByName($string): Part|null
{ {
$this->rewind(); return $this->data[$string] ?? null;
while ($this->valid()) {
if ($string == $this->current()->getFullName()) {
return $this->current();
}
$this->next();
}
return null;
} }
public function addPart(Part $part): void public function addPart(Part $part): void
{ {
$foundKey = null; $this->data[$part->getFullName()] = $part;
while ($this->valid()) {
if ($part->getName() == $this->current()->getName() && $part->getType() == $this->current()->getType()) {
$foundKey = $this->key();
break;
} }
$this->next(); public function getData(): array
} {
return $this->data;
if ($foundKey) {
$this->offsetSet($foundKey, $part);
} else {
$this->append($part);
}
} }
} }

View File

@ -0,0 +1,49 @@
<?php
namespace PSC\Library\Calc\Tests\Customer\A;
use PHPUnit\Framework\TestCase;
use PSC\Library\Calc\Article;
use PSC\Library\Calc\Engine;
use PSC\Library\Calc\PaperContainer;
use PSC\Library\Calc\Tests\Mock\PaperRepostory;
class GraphTest extends TestCase
{
/** @var Engine */
protected $engine = null;
public function setUp(): void
{
$repository = new PaperRepostory();
$paperContainer = new PaperContainer();
$paperContainer->parse(simplexml_load_string(file_get_contents(__DIR__ . '/papierContainer.xml')));
$this->engine = new Engine();
$this->engine->setPaperContainer($paperContainer);
$this->engine->setPaperRepository($repository);
$this->engine->setFormulas(file_get_contents(__DIR__ . '/formels.txt'));
$this->engine->setParameters(file_get_contents(__DIR__ . '/parameters.txt'));
$this->engine->setTemplates(file_get_contents(__DIR__ . '/calcTemplates.xml'));
$this->engine->loadString(file_get_contents(__DIR__ . '/calc.xml'));
}
public function tearDown(): void
{
$this->engine = null;
}
public function testPriceAndGraph(): void
{
$this->engine->calc();
$priceFromOldEngine = $this->engine->getPrice();
$this->assertEquals(229.86, $priceFromOldEngine);
file_put_contents(
filename: __DIR__ . '/test.json',
data: $this->engine->getCalcGraph()->generateJsonGraph(),
);
self::assertSame($priceFromOldEngine, $this->engine->getCalcGraph()->getSum());
}
}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,49 @@
<?php
namespace PSC\Library\Calc\Tests\Customer\B;
use PHPUnit\Framework\TestCase;
use PSC\Library\Calc\Article;
use PSC\Library\Calc\Engine;
use PSC\Library\Calc\PaperContainer;
use PSC\Library\Calc\Tests\Mock\PaperRepostory;
class GraphTest extends TestCase
{
/** @var Engine */
protected $engine = null;
public function setUp(): void
{
$repository = new PaperRepostory();
$paperContainer = new PaperContainer();
$paperContainer->parse(simplexml_load_string(file_get_contents(__DIR__ . '/papierContainer.xml')));
$this->engine = new Engine();
$this->engine->setPaperContainer($paperContainer);
$this->engine->setPaperRepository($repository);
$this->engine->setFormulas(file_get_contents(__DIR__ . '/formels.txt'));
$this->engine->setParameters(file_get_contents(__DIR__ . '/parameters.txt'));
$this->engine->setTemplates(file_get_contents(__DIR__ . '/calcTemplates.xml'));
$this->engine->loadString(file_get_contents(__DIR__ . '/calc.xml'));
}
public function tearDown(): void
{
$this->engine = null;
}
public function testPriceAndGraph(): void
{
$this->engine->calc();
$priceFromOldEngine = $this->engine->getPrice();
$this->assertEquals(945.00, $priceFromOldEngine);
file_put_contents(
filename: __DIR__ . '/test.json',
data: $this->engine->getCalcGraph()->generateJsonGraph(),
);
self::assertSame($priceFromOldEngine, $this->engine->getCalcGraph()->getSum());
}
}

View File

@ -0,0 +1 @@
[{"name":"startkosten_1c-seitenzahl_inhalt","unParsed":"$Pstartpreis_format1_52g_128$P","parsed":"945","result":945,"parts":[{"name":"startpreis_format1_52g_128","unParsed":"945","parsed":"945","result":945,"parts":[]}]},{"name":"stueckkosten_berechnung-farbigkeit_inhalt","unParsed":"($CVstueckkosten_1c_farbigkeit_inhalt$CV)*($Vauflage$V-1000)","parsed":"(0.195)*(1000-1000)","result":0,"parts":[{"name":"stueckkosten_1c_farbigkeit_inhalt","unParsed":"0.195","parsed":"0.195","result":0.195,"parts":[]},{"name":"auflage","unParsed":"1000","parsed":"1000","result":1000,"parts":[]}]},{"name":"veredelung_umschlag_kosten-veredelung_umschlag","unParsed":"0","parsed":"0","result":0,"parts":[]},{"name":"partieller_lack_umschlag_kosten-partiell_lack_umschlag","unParsed":"0","parsed":"0","result":0,"parts":[]},{"name":"papier_umschlag_kosten-papier_umschlag","unParsed":"0","parsed":"0","result":0,"parts":[]},{"name":"farbigkeit_umschlag_kosten-farbigkeit_umschlag","unParsed":"0","parsed":"0","result":0,"parts":[]},{"name":"praegung_umschlag_kosten-praegung_umschlag","unParsed":"0","parsed":"0","result":0,"parts":[]},{"name":"verpackung_kosten-verpackung","unParsed":"0","parsed":"0","result":0,"parts":[]},{"name":"belegmusterversand_kosten-belegmusterversand","unParsed":"0","parsed":"0","result":0,"parts":[]}]

View File

@ -35,7 +35,7 @@ class GraphTest extends TestCase
$this->engine = null; $this->engine = null;
} }
public function tesPriceAndGraph(): void public function testPriceAndGraph(): void
{ {
$this->engine->calc(); $this->engine->calc();
$priceFromOldEngine = $this->engine->getPrice(); $priceFromOldEngine = $this->engine->getPrice();

File diff suppressed because one or more lines are too long

View File

@ -9,7 +9,6 @@ use PSC\Library\Calc\Model\PartType;
use function PHPUnit\Framework\assertJsonStringEqualsJsonFile; use function PHPUnit\Framework\assertJsonStringEqualsJsonFile;
use function PHPUnit\Framework\assertSame; use function PHPUnit\Framework\assertSame;
use function PHPUnit\Framework\assertTrue;
class SimpleTest extends TestCase class SimpleTest extends TestCase
{ {
@ -37,7 +36,7 @@ class SimpleTest extends TestCase
unParsed: '$Ftest5$F+$Ftest8$F', unParsed: '$Ftest5$F+$Ftest8$F',
)); ));
assertSame(6186, $this->graph->getSum());
assertJsonStringEqualsJsonFile(__DIR__ . '/test.json', $this->graph->generateJsonGraph()); assertJsonStringEqualsJsonFile(__DIR__ . '/test.json', $this->graph->generateJsonGraph());
assertSame(6186.0, $this->graph->getSum());
} }
} }