diff --git a/src/Controller/PartController.php b/src/Controller/PartController.php index 2a974949..c24c09ab 100644 --- a/src/Controller/PartController.php +++ b/src/Controller/PartController.php @@ -53,6 +53,7 @@ use App\Services\Attachments\PartPreviewGenerator; use App\Services\LogSystem\EventCommentHelper; use App\Services\LogSystem\HistoryHelper; use App\Services\LogSystem\TimeTravel; +use App\Services\Parameters\ParameterExtractor; use App\Services\PricedetailHelper; use Doctrine\ORM\EntityManagerInterface; use Omines\DataTablesBundle\DataTableFactory; @@ -92,7 +93,7 @@ class PartController extends AbstractController * @throws \Exception */ public function show(Part $part, Request $request, TimeTravel $timeTravel, HistoryHelper $historyHelper, - DataTableFactory $dataTable, ?string $timestamp = null): Response + DataTableFactory $dataTable, ParameterExtractor $parameterExtractor, ?string $timestamp = null): Response { $this->denyAccessUnlessGranted('read', $part); @@ -133,6 +134,8 @@ class PartController extends AbstractController 'pricedetail_helper' => $this->pricedetailHelper, 'pictures' => $this->partPreviewGenerator->getPreviewAttachments($part), 'timeTravel' => $timeTravel_timestamp, + 'description_params' => $parameterExtractor->extractParameters($part->getDescription()), + 'comment_params' => $parameterExtractor->extractParameters($part->getComment()) ] ); } diff --git a/src/Services/Parameters/ParameterExtractor.php b/src/Services/Parameters/ParameterExtractor.php new file mode 100644 index 00000000..a01ce327 --- /dev/null +++ b/src/Services/Parameters/ParameterExtractor.php @@ -0,0 +1,97 @@ +. + */ + +namespace App\Services\Parameters; + + +use App\Entity\Parameters\AbstractParameter; +use App\Entity\Parameters\PartParameter; + +class ParameterExtractor +{ + protected const ALLOWED_PARAM_SEPARATORS = [", ", "\n"]; + + protected const CHAR_LIMIT = 1000; + + /** + * Tries to extract parameters from the given string. + * Useful for extraction from part description and comment. + * @param string $input + * @param string $class + * @return AbstractParameter[] + */ + public function extractParameters(string $input, string $class = PartParameter::class): array + { + if (!is_a($class, AbstractParameter::class, true)) { + throw new \InvalidArgumentException('$class must be a child class of AbstractParameter!'); + } + + //Restrict search length + $input = mb_strimwidth($input,0,self::CHAR_LIMIT); + + $parameters = []; + + //Try to split the input string into different sub strings each containing a single parameter + $split = $this->splitString($input); + foreach ($split as $param_string) { + $tmp = $this->stringToParam($param_string, $class); + if ($tmp !== null) { + $parameters[] = $tmp; + } + } + + return $parameters; + } + + protected function stringToParam(string $input, string $class): ?AbstractParameter + { + $input = trim($input); + $regex = '/^(.*) *(?:=|:) *(.+)/u'; + + $matches = []; + \preg_match($regex, $input, $matches); + dump($matches); + if (!empty($matches)) { + [$raw, $name, $value] = $matches; + $value = trim($value); + + //Dont allow empty names or values (these are a sign of an invalid extracted string) + if (empty($name) || empty($value)) { + return null; + } + + /** @var AbstractParameter $parameter */ + $parameter = new $class(); + $parameter->setName(trim($name)); + $parameter->setValueText($value); + + return $parameter; + } + + return null; + } + + protected function splitString(string $input): array + { + //Allow comma as limiter (include space, to prevent splitting in german style numbers) + $input = str_replace(static::ALLOWED_PARAM_SEPARATORS, ";", $input); + return explode(";", $input); + } +} \ No newline at end of file diff --git a/templates/Parts/info/_specifications.html.twig b/templates/Parts/info/_specifications.html.twig index 26de0b49..5860bc71 100644 --- a/templates/Parts/info/_specifications.html.twig +++ b/templates/Parts/info/_specifications.html.twig @@ -4,4 +4,14 @@ {% for name, parameters in part.groupedParameters %} {% if name is not empty %}
{{ name }}
{% endif %} {{ helper.parameters_table(parameters) }} -{% endfor %} \ No newline at end of file +{% endfor %} + +{% if description_params is not empty %} +
{% trans %}parameters.extracted_from_description{% endtrans %}
+ {{ helper.parameters_table(description_params) }} +{% endif %} + +{% if comment_params is not empty %} +
{% trans %}parameters.auto_extracted_from_comment{% endtrans %}
+ {{ helper.parameters_table(comment_params) }} +{% endif %} \ No newline at end of file diff --git a/tests/Services/Parameters/ParameterExtractorTest.php b/tests/Services/Parameters/ParameterExtractorTest.php new file mode 100644 index 00000000..b88f0ab7 --- /dev/null +++ b/tests/Services/Parameters/ParameterExtractorTest.php @@ -0,0 +1,75 @@ +. + */ + +namespace App\Tests\Services\Parameters; + +use App\Entity\Parameters\AbstractParameter; +use App\Services\Parameters\ParameterExtractor; +use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; + +class ParameterExtractorTest extends WebTestCase +{ + + protected $service; + + public function setUp(): void + { + parent::setUp(); + //Get an service instance. + self::bootKernel(); + $this->service = self::$container->get(ParameterExtractor::class); + } + + public function emptyDataProvider(): array + { + return [ + [""], + [" "], + ["\t\n"], + [":;"], + ["NPN Transistor"], + ["=BC547 rewr"], + ["For good, [b]bad[/b], evil"], + ["Param:; Test"] + ]; + } + + /** + * @dataProvider emptyDataProvider + */ + public function testShouldReturnEmpty(string $input) + { + $this->assertEmpty($this->service->extractParameters($input)); + } + + public function testExtract() + { + $parameters = $this->service->extractParameters(' Operating Voltage: 10 V; Property : Value, Ström=1A (Test)'); + $this->assertContainsOnly(AbstractParameter::class, $parameters); + $this->assertCount(3, $parameters); + $this->assertSame('Operating Voltage', $parameters[0]->getName()); + $this->assertSame('10 V', $parameters[0]->getValueText()); + $this->assertSame('Property', $parameters[1]->getName()); + $this->assertSame('Value', $parameters[1]->getValueText()); + $this->assertSame('Ström', $parameters[2]->getName()); + $this->assertSame('1A (Test)', $parameters[2]->getValueText()); + + } +}