From ee33d743e68318c0f14523eeb2120dcd244d17e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20B=C3=B6hmer?= Date: Sun, 24 Aug 2025 23:32:58 +0200 Subject: [PATCH] Allow to associate settings forms with info providers --- composer.lock | 12 ++--- src/Controller/InfoProviderController.php | 52 ++++++++++++++++++- .../Providers/InfoProviderInterface.php | 5 +- .../Providers/ReicheltProvider.php | 3 +- .../info_providers/providers.macro.html.twig | 8 ++- .../settings/provider_settings.html.twig | 27 ++++++++++ translations/messages.en.xlf | 6 +++ 7 files changed, 100 insertions(+), 13 deletions(-) create mode 100644 templates/info_providers/settings/provider_settings.html.twig diff --git a/composer.lock b/composer.lock index 2a59f016..b394fccb 100644 --- a/composer.lock +++ b/composer.lock @@ -5090,16 +5090,16 @@ }, { "name": "jbtronics/settings-bundle", - "version": "v3.0.0", + "version": "v3.0.1", "source": { "type": "git", "url": "https://github.com/jbtronics/settings-bundle.git", - "reference": "34b9629af73c7ad8989d8284470e79f3f8d79712" + "reference": "9103bd7f78f0b223d1c7167feb824004fc2a9f07" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/jbtronics/settings-bundle/zipball/34b9629af73c7ad8989d8284470e79f3f8d79712", - "reference": "34b9629af73c7ad8989d8284470e79f3f8d79712", + "url": "https://api.github.com/repos/jbtronics/settings-bundle/zipball/9103bd7f78f0b223d1c7167feb824004fc2a9f07", + "reference": "9103bd7f78f0b223d1c7167feb824004fc2a9f07", "shasum": "" }, "require": { @@ -5160,7 +5160,7 @@ ], "support": { "issues": "https://github.com/jbtronics/settings-bundle/issues", - "source": "https://github.com/jbtronics/settings-bundle/tree/v3.0.0" + "source": "https://github.com/jbtronics/settings-bundle/tree/v3.0.1" }, "funding": [ { @@ -5172,7 +5172,7 @@ "type": "github" } ], - "time": "2025-08-24T17:17:43+00:00" + "time": "2025-08-24T21:20:15+00:00" }, { "name": "jfcherng/php-color-output", diff --git a/src/Controller/InfoProviderController.php b/src/Controller/InfoProviderController.php index a6ce3f1b..a6e886e6 100644 --- a/src/Controller/InfoProviderController.php +++ b/src/Controller/InfoProviderController.php @@ -29,10 +29,14 @@ use App\Form\InfoProviderSystem\PartSearchType; use App\Services\InfoProviderSystem\ExistingPartFinder; use App\Services\InfoProviderSystem\PartInfoRetriever; use App\Services\InfoProviderSystem\ProviderRegistry; +use App\Settings\AppSettings; use Doctrine\ORM\EntityManagerInterface; +use Jbtronics\SettingsBundle\Form\SettingsFormFactoryInterface; +use Jbtronics\SettingsBundle\Manager\SettingsManagerInterface; use Psr\Log\LoggerInterface; use Symfony\Bridge\Doctrine\Attribute\MapEntity; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; +use Symfony\Component\Form\Extension\Core\Type\SubmitType; use Symfony\Component\HttpClient\Exception\ClientException; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; @@ -46,7 +50,9 @@ class InfoProviderController extends AbstractController public function __construct(private readonly ProviderRegistry $providerRegistry, private readonly PartInfoRetriever $infoRetriever, - private readonly ExistingPartFinder $existingPartFinder + private readonly ExistingPartFinder $existingPartFinder, + private readonly SettingsManagerInterface $settingsManager, + private readonly SettingsFormFactoryInterface $settingsFormFactory ) { @@ -63,6 +69,48 @@ class InfoProviderController extends AbstractController ]); } + #[Route('/provider/{provider}/settings', name: 'info_providers_provider_settings')] + public function providerSettings(string $provider, Request $request): Response + { + $this->denyAccessUnlessGranted('@config.change_system_settings'); + $this->denyAccessUnlessGranted('@info_providers.create_parts'); + + $providerInstance = $this->providerRegistry->getProviderByKey($provider); + $settingsClass = $providerInstance->getProviderInfo()['settings_class'] ?? throw new \LogicException('Provider ' . $provider . ' does not have a settings class defined'); + + //Create a clone of the settings object + $settings = $this->settingsManager->createTemporaryCopy($settingsClass); + + //Create a form builder for the settings object + $builder = $this->settingsFormFactory->createSettingsFormBuilder($settings); + + //Add a submit button to the form + $builder->add('submit', SubmitType::class, ['label' => 'save']); + + //Create the form + $form = $builder->getForm(); + $form->handleRequest($request); + + //If the form was submitted and is valid, save the settings + if ($form->isSubmitted() && $form->isValid()) { + $this->settingsManager->mergeTemporaryCopy($settings); + $this->settingsManager->save($settings); + + $this->addFlash('success', t('settings.flash.saved')); + } + + if ($form->isSubmitted() && !$form->isValid()) { + $this->addFlash('error', t('settings.flash.invalid')); + } + + //Render the form + return $this->render('info_providers/settings/provider_settings.html.twig', [ + 'form' => $form, + 'info_provider_key' => $provider, + 'info_provider_info' => $providerInstance->getProviderInfo(), + ]); + } + #[Route('/search', name: 'info_providers_search')] #[Route('/update/{target}', name: 'info_providers_update_part_search')] public function search(Request $request, #[MapEntity(id: 'target')] ?Part $update_target, LoggerInterface $exceptionLogger): Response @@ -128,4 +176,4 @@ class InfoProviderController extends AbstractController 'update_target' => $update_target ]); } -} \ No newline at end of file +} diff --git a/src/Services/InfoProviderSystem/Providers/InfoProviderInterface.php b/src/Services/InfoProviderSystem/Providers/InfoProviderInterface.php index 30821bad..1f787559 100644 --- a/src/Services/InfoProviderSystem/Providers/InfoProviderInterface.php +++ b/src/Services/InfoProviderSystem/Providers/InfoProviderInterface.php @@ -39,8 +39,9 @@ interface InfoProviderInterface * - url?: The url of the provider (e.g. "https://www.digikey.com") * - disabled_help?: A help text which is shown when the provider is disabled, explaining how to enable it * - oauth_app_name?: The name of the OAuth app which is used for authentication (e.g. "ip_digikey_oauth"). If this is set a connect button will be shown + * - settings_class?: The class name of the settings class which contains the settings for this provider (e.g. "App\Settings\InfoProviderSettings\DigikeySettings"). If this is set a link to the settings will be shown * - * @phpstan-return array{ name: string, description?: string, logo?: string, url?: string, disabled_help?: string, oauth_app_name?: string } + * @phpstan-return array{ name: string, description?: string, logo?: string, url?: string, disabled_help?: string, oauth_app_name?: string, settings_class?: class-string } */ public function getProviderInfo(): array; @@ -78,4 +79,4 @@ interface InfoProviderInterface * @return ProviderCapabilities[] */ public function getCapabilities(): array; -} \ No newline at end of file +} diff --git a/src/Services/InfoProviderSystem/Providers/ReicheltProvider.php b/src/Services/InfoProviderSystem/Providers/ReicheltProvider.php index e836937b..5c8efbf1 100644 --- a/src/Services/InfoProviderSystem/Providers/ReicheltProvider.php +++ b/src/Services/InfoProviderSystem/Providers/ReicheltProvider.php @@ -51,7 +51,8 @@ class ReicheltProvider implements InfoProviderInterface 'name' => 'Reichelt', 'description' => 'Webscraping from reichelt.com to get part information', 'url' => 'https://www.reichelt.com/', - 'disabled_help' => 'Enable provider in provider settings.' + 'disabled_help' => 'Enable provider in provider settings.', + 'settings_class' => ReicheltSettings::class, ]; } diff --git a/templates/info_providers/providers.macro.html.twig b/templates/info_providers/providers.macro.html.twig index 7304806a..827a95fd 100644 --- a/templates/info_providers/providers.macro.html.twig +++ b/templates/info_providers/providers.macro.html.twig @@ -13,7 +13,6 @@ {% else %} {{ provider.providerInfo.name | trans }} {% endif %} -
{% if provider.providerInfo.description is defined and provider.providerInfo.description is not null %} @@ -23,6 +22,11 @@
+ {% if provider.providerInfo.settings_class is defined %} + + {% endif %} {% for capability in provider.capabilities %} {# @var capability \App\Services\InfoProviderSystem\Providers\ProviderCapabilities #} @@ -52,4 +56,4 @@ {% endfor %} -{% endmacro %} \ No newline at end of file +{% endmacro %} diff --git a/templates/info_providers/settings/provider_settings.html.twig b/templates/info_providers/settings/provider_settings.html.twig new file mode 100644 index 00000000..c702306a --- /dev/null +++ b/templates/info_providers/settings/provider_settings.html.twig @@ -0,0 +1,27 @@ +{% extends "main_card.html.twig" %} +{% macro genId(widget) %}{{ widget.vars.full_name }}{% endmacro %} + +{% form_theme form "form/settings_form.html.twig" %} + +{% block title %}{% trans %}info_providers.settings.title{% endtrans %}: {{ info_provider_info.name }}{% endblock %} + +{% block card_title %} {% trans %}info_providers.settings.title{% endtrans %}: {{ info_provider_info.name }}{% endblock %} + +{% block card_content %} +
+

+ {% if info_provider_info.url %} + {{ info_provider_info.name }} + {% else %} + {{ info_provider_info.name }} + {% endif %} +

+ {% if info_provider_info.description %} +

{{ info_provider_info.description }}

+ {% endif %} +
+ + {{ form_start(form) }} + {{ form_help(form) }} + {{ form_end(form) }} +{% endblock %} diff --git a/translations/messages.en.xlf b/translations/messages.en.xlf index 8a4f809b..d9c4b1fd 100644 --- a/translations/messages.en.xlf +++ b/translations/messages.en.xlf @@ -13045,5 +13045,11 @@ Please note, that you can not impersonate a disabled user. If you try you will g Settings are invalid. Please check your input! + + + info_providers.settings.title + Info provider settings + +