From e7e5e9436e0c1d8733ad80f66486664f62ece2d4 Mon Sep 17 00:00:00 2001 From: Maxime Bruchet Date: Tue, 28 Jul 2026 15:20:31 +0200 Subject: [PATCH 1/4] feat: add Thelia 3 bi-compat (default-twig BO, twig config, bank info renderer) --- Config/config.xml | 2 +- Config/module.xml | 2 +- Config/routing.xml | 6 ++ Constraints/BIC.php | 2 + Constraints/BICValidator.php | 11 ++- Controller/ConfigureController.php | 19 ++++- Form/ConfigurationForm.php | 4 +- Hook/Back/ConfigurationHook.php | 70 +++++++++++++++++++ Hook/HookManager.php | 35 +++++++--- Listener/SendPaymentConfirmationEmail.php | 2 + Loop/GetBankInformation.php | 10 +-- README.md | 42 ++++++++++- Service/WireTransferBankInfoRenderer.php | 65 +++++++++++++++++ Twig/WireTransferExtension.php | 38 ++++++++++ WireTransfer.php | 46 ++++++++++-- .../module-configuration.html.twig | 39 +++++++++++ 16 files changed, 364 insertions(+), 29 deletions(-) create mode 100644 Hook/Back/ConfigurationHook.php create mode 100644 Service/WireTransferBankInfoRenderer.php create mode 100644 Twig/WireTransferExtension.php create mode 100644 templates/backOffice/default-twig/WireTransfer/module-configuration.html.twig diff --git a/Config/config.xml b/Config/config.xml index 8338dea..02a4acc 100644 --- a/Config/config.xml +++ b/Config/config.xml @@ -14,7 +14,7 @@ - + diff --git a/Config/module.xml b/Config/module.xml index f985f8b..7c4729f 100644 --- a/Config/module.xml +++ b/Config/module.xml @@ -7,7 +7,7 @@ Wire transfer payment - 2.1.3 + 2.2.0 Thelia info@thelia.net diff --git a/Config/routing.xml b/Config/routing.xml index 892a99c..d9e3fed 100644 --- a/Config/routing.xml +++ b/Config/routing.xml @@ -1,4 +1,10 @@ + diff --git a/Constraints/BIC.php b/Constraints/BIC.php index b961d5e..e3dfce6 100644 --- a/Constraints/BIC.php +++ b/Constraints/BIC.php @@ -22,6 +22,8 @@ /*************************************************************************************/ +declare(strict_types=1); + namespace WireTransfer\Constraints; use Symfony\Component\Validator\Constraint; diff --git a/Constraints/BICValidator.php b/Constraints/BICValidator.php index 24a4187..a9a7c51 100644 --- a/Constraints/BICValidator.php +++ b/Constraints/BICValidator.php @@ -22,9 +22,12 @@ /*************************************************************************************/ +declare(strict_types=1); + namespace WireTransfer\Constraints; use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\ConstraintValidator; +use Symfony\Component\Validator\Exception\UnexpectedTypeException; use Thelia\Core\Translation\Translator; /** @@ -43,13 +46,19 @@ class BICValidator extends ConstraintValidator { */ public function validate($value, Constraint $constraint) { + if (!$constraint instanceof BIC) { + throw new UnexpectedTypeException($constraint, BIC::class); + } + if (null === $value || '' === $value) { return; } $teststring = preg_replace('/\s+/', '', $value); - if(!preg_match("([a-zA-Z]{4}[a-zA-Z]{2}[a-zA-Z0-9]{2}([a-zA-Z0-9]{3})?)", $teststring)) { + // A BIC is 8 or 11 characters: 6 letters + 2 alphanumerics, then an optional 3-char branch code. + // The pattern is anchored (^...$) so partial matches embedded in a longer string are rejected. + if(!preg_match('/^[a-zA-Z]{6}[a-zA-Z0-9]{2}([a-zA-Z0-9]{3})?$/', $teststring)) { $this->context->addViolation( Translator::getInstance()->trans( $constraint->message diff --git a/Controller/ConfigureController.php b/Controller/ConfigureController.php index 788ffb6..a531968 100644 --- a/Controller/ConfigureController.php +++ b/Controller/ConfigureController.php @@ -26,9 +26,12 @@ /* You should have received a copy of the GNU General Public License */ /* along with this program. If not, see . */ +declare(strict_types=1); + namespace WireTransfer\Controller; use Symfony\Component\HttpFoundation\RedirectResponse; +use Symfony\Component\HttpFoundation\Session\FlashBagAwareSessionInterface; use Thelia\Controller\Admin\BaseAdminController; use Thelia\Core\HttpFoundation\Request; use Thelia\Core\Security\AccessManager; @@ -97,8 +100,20 @@ public function configure(Request $request, Translator $translator) $ex ); - // Do not redirect at this point, or the error context will be lost. - // Just redisplay the current template. + // Thelia 3 renders the config screen through a hook (default-twig), so redirect back + // to the module configuration page. On Thelia 2, redisplay the current template inline + // to keep the form error context. + if (WireTransfer::isThelia3()) { + // The redirect drops the ParserContext form error, so surface the failure through + // the flash bag (rendered by the default-twig base template as app.flashes). + $session = $request->getSession(); + if ($session instanceof FlashBagAwareSessionInterface) { + $session->getFlashBag()->add('danger', $error_msg); + } + + return new RedirectResponse(URL::getInstance()->absoluteUrl('/admin/module/WireTransfer')); + } + return $this->render('module-configure', ['module_code' => 'WireTransfer']); } } diff --git a/Form/ConfigurationForm.php b/Form/ConfigurationForm.php index 70e34a5..fca0651 100644 --- a/Form/ConfigurationForm.php +++ b/Form/ConfigurationForm.php @@ -26,6 +26,8 @@ /* You should have received a copy of the GNU General Public License */ /* along with this program. If not, see . */ +declare(strict_types=1); + namespace WireTransfer\Form; use Symfony\Component\Form\Extension\Core\Type\TextareaType; @@ -109,7 +111,7 @@ protected function buildForm(): void /** * @return string the name of you form. This name must be unique */ - public static function getName() + public static function getName(): string { return 'configurewiretransfer'; } diff --git a/Hook/Back/ConfigurationHook.php b/Hook/Back/ConfigurationHook.php new file mode 100644 index 0000000..9017eb9 --- /dev/null +++ b/Hook/Back/ConfigurationHook.php @@ -0,0 +1,70 @@ + [ + ['type' => 'back', 'method' => 'onModuleConfiguration'], + ], + ]; + } + + public function onModuleConfiguration(HookRenderEvent $event): void + { + if ('WireTransfer' !== $event->getArgument('modulecode')) { + return; + } + + $event->add( + $this->render('WireTransfer/module-configuration.html.twig', [ + 'config_form' => $this->formFactory + ->createForm(ConfigurationForm::getName(), FormType::class) + ->createView() + ->getView(), + ]) + ); + } +} diff --git a/Hook/HookManager.php b/Hook/HookManager.php index 610dc89..a1ca9ac 100644 --- a/Hook/HookManager.php +++ b/Hook/HookManager.php @@ -10,25 +10,38 @@ /* file that was distributed with this source code. */ /*************************************************************************************/ +declare(strict_types=1); + namespace WireTransfer\Hook; use Thelia\Core\Event\Hook\HookRenderEvent; use Thelia\Core\Hook\BaseHook; +use WireTransfer\WireTransfer; /** - * Class HookManager - * - * @package Tinymce\Hook - * @author Franck Allimant + * Thelia 2 Smarty hooks. On Thelia 3 the back-office configuration is rendered by + * WireTransfer\Hook\Back\ConfigurationHook (default-twig) and the order-placed bank + * information by the theme through wiretransfer_bank_info(), so both methods no-op there. */ -class HookManager extends BaseHook { +class HookManager extends BaseHook +{ + public function onModuleConfigure(HookRenderEvent $event): void + { + if (WireTransfer::isThelia3()) { + return; + } + + $event->add($this->render('module_configuration.html')); + } - public function onAdditionalPaymentInfo(HookRenderEvent $event) + public function onAdditionalPaymentInfo(HookRenderEvent $event): void { - $content = $this->render("order-placed.additional-payment-info.html", [ - 'placed_order_id' => $event->getArgument('placed_order_id') - ]); + if (WireTransfer::isThelia3()) { + return; + } - $event->add($content); + $event->add($this->render('order-placed.additional-payment-info.html', [ + 'placed_order_id' => $event->getArgument('placed_order_id'), + ])); } -} \ No newline at end of file +} diff --git a/Listener/SendPaymentConfirmationEmail.php b/Listener/SendPaymentConfirmationEmail.php index f1f1788..ce22009 100644 --- a/Listener/SendPaymentConfirmationEmail.php +++ b/Listener/SendPaymentConfirmationEmail.php @@ -21,6 +21,8 @@ /* */ /*************************************************************************************/ +declare(strict_types=1); + namespace WireTransfer\Listener; use WireTransfer\WireTransfer; diff --git a/Loop/GetBankInformation.php b/Loop/GetBankInformation.php index 42ff5a4..400ee69 100644 --- a/Loop/GetBankInformation.php +++ b/Loop/GetBankInformation.php @@ -26,6 +26,8 @@ /* You should have received a copy of the GNU General Public License */ /* along with this program. If not, see . */ +declare(strict_types=1); + namespace WireTransfer\Loop; use Thelia\Core\Template\Element\ArraySearchLoopInterface; @@ -47,11 +49,11 @@ class GetBankInformation extends BaseLoop implements ArraySearchLoopInterface /** * @return LoopResult */ - public function parseResults(LoopResult $loopResult) + public function parseResults(LoopResult $loopResult): LoopResult { $order = OrderQuery::create()->findPk($this->getOrderId()); - if ($order !== null || $order->getPaymentModuleId() === WireTransfer::getModuleId()) { + if ($order !== null && $order->getPaymentModuleId() === WireTransfer::getModuleId()) { $loopResultRow = new LoopResultRow(); $loopResultRow @@ -67,7 +69,7 @@ public function parseResults(LoopResult $loopResult) return $loopResult; } - protected function getArgDefinitions() + protected function getArgDefinitions(): ArgumentCollection { return new ArgumentCollection( Argument::createIntTypeArgument('order_id', null, true, false) @@ -79,7 +81,7 @@ protected function getArgDefinitions() * * @return array */ - public function buildArray() + public function buildArray(): array { // Return an array containing one element, so that parseResults() will be called one time. return ['one-element']; diff --git a/README.md b/README.md index 832c4bf..faa79a9 100644 --- a/README.md +++ b/README.md @@ -129,4 +129,44 @@ The content of this e-mail could be configured in the back-office -> Le contenu ### Integration The bank account information are displayed in `order-placed.html` file of the default front office template, -using the `order-placed.additional-payment-info` hook. \ No newline at end of file +using the `order-placed.additional-payment-info` hook. + + +Thelia 3 (version 2.2.0+) +------------------------- + +À partir de la 2.2.0, le module est **bi-compatible Thelia 2.5 et Thelia 3** (branche twig, Symfony 7.4, +Flexy). L'aiguillage se fait via `WireTransfer::isThelia3()` ; le code Thelia 2 (templates Smarty, hooks) +reste en place et n'est actif que sous Thelia 2. As of 2.2.0 the module is **dual-compatible with Thelia 2.5 +and Thelia 3**; the Thelia 2 code path stays in place and is only active under Thelia 2. + +### Ce qui change en Thelia 3 / What changes on Thelia 3 + +- **Back-office** : la page de configuration est rendue en `default-twig` (Twig) via le hook + `WireTransfer\Hook\Back\ConfigurationHook` (`module.configuration`), template + `templates/backOffice/default-twig/WireTransfer/module-configuration.html.twig`. En Thelia 2, le rendu + Smarty (`templates/backOffice/default/module_configuration.html`) est conservé. +- **Front-office (Flexy)** : le hook Smarty `order-placed.additional-payment-info` n'existe plus. Les + coordonnées bancaires sont désormais fournies par une **fonction Twig** à appeler dans le thème, sur la + page de confirmation de commande : + + ```twig + {{ wiretransfer_bank_info(order_id) }} + ``` + + Elle ne rend rien si la commande n'a pas été payée par virement. En Thelia 2, l'affichage reste assuré par + le hook `order-placed.additional-payment-info` (template Smarty `order-placed.additional-payment-info.html`) + et la boucle `wiretransfer.get.info`. +- **Routes** : déclarées dans `Config/routing.xml` (chargé par Thelia 2 **et** Thelia 3), sans + attribut `#[Route]` — sinon Thelia 3 enregistrerait la route en double (chemin inchangé + `/admin/wiretransfer/configure`). +- **Compatibilité des signatures** : `pay(Order): ?Response`, `install/destroy(?ConnectionInterface)`, + `ConfigurationForm::getName(): string`, et types de retour sur la boucle — compatibles Thelia 2 et 3. +- **Classe `Database`** résolue à l'exécution (`Thelia\Install\Database` en T2, `Thelia\Core\Install\Database` + en T3). + +### Boucle `wiretransfer.get.info` + +Toujours disponible et inchangée (Thelia 2 et Thelia 3) : elle retourne `ACCOUNT_HOLDER_NAME`, `IBAN`, `BIC`, +`MESSAGE` pour un `order_id`. Sous Thelia 3 / Flexy, préférez la fonction Twig `wiretransfer_bank_info()` +ci-dessus, qui encapsule cette logique. \ No newline at end of file diff --git a/Service/WireTransferBankInfoRenderer.php b/Service/WireTransferBankInfoRenderer.php new file mode 100644 index 0000000..a6ea878 --- /dev/null +++ b/Service/WireTransferBankInfoRenderer.php @@ -0,0 +1,65 @@ +findPk((int) $orderId); + if (null === $order || $order->getPaymentModuleId() !== WireTransfer::getModuleId()) { + return ''; + } + + $name = htmlspecialchars((string) WireTransfer::getConfigValue('name'), ENT_QUOTES); + $iban = htmlspecialchars((string) WireTransfer::getConfigValue('iban'), ENT_QUOTES); + $bic = htmlspecialchars((string) WireTransfer::getConfigValue('bic'), ENT_QUOTES); + $message = (string) WireTransfer::getConfigValue('message'); + + $translator = Translator::getInstance(); + $intro = htmlspecialchars($translator->trans('You may now do a transfer to this bank account: ', [], 'wiretransfer.fo.default'), ENT_QUOTES); + $holderLabel = htmlspecialchars($translator->trans('Account holder name', [], 'wiretransfer.fo.default'), ENT_QUOTES); + $ibanLabel = htmlspecialchars($translator->trans('IBAN', [], 'wiretransfer.fo.default'), ENT_QUOTES); + $bicLabel = htmlspecialchars($translator->trans('BIC code', [], 'wiretransfer.fo.default'), ENT_QUOTES); + + // The merchant-configured message is trusted admin content (rendered raw, as in T2). + $messageBlock = '' !== $message ? '
'.$message.'
' : ''; + + return << +

{$intro}

+
+
{$holderLabel} :
{$name}
+
{$ibanLabel} :
{$iban}
+
{$bicLabel} :
{$bic}
+
+ {$messageBlock} + +HTML; + } +} diff --git a/Twig/WireTransferExtension.php b/Twig/WireTransferExtension.php new file mode 100644 index 0000000..84d0995 --- /dev/null +++ b/Twig/WireTransferExtension.php @@ -0,0 +1,38 @@ +renderer->bankInfo(...), ['is_safe' => ['html']]), + ]; + } +} diff --git a/WireTransfer.php b/WireTransfer.php index 19ce2aa..7d3fdf2 100644 --- a/WireTransfer.php +++ b/WireTransfer.php @@ -26,12 +26,14 @@ /* You should have received a copy of the GNU General Public License */ /* along with this program. If not, see . */ +declare(strict_types=1); + namespace WireTransfer; use Propel\Runtime\Connection\ConnectionInterface; use Symfony\Component\DependencyInjection\Loader\Configurator\ServicesConfigurator; +use Symfony\Component\HttpFoundation\Response; use Thelia\Core\Translation\Translator; -use Thelia\Install\Database; use Thelia\Log\Tlog; use Thelia\Model\MessageQuery; use Thelia\Model\Order; @@ -44,9 +46,10 @@ class WireTransfer extends AbstractPaymentModule { public const MESSAGE_DOMAIN = 'wiretransfer'; - public function pay(Order $order): void + public function pay(Order $order): ?Response { - // Nothing special to do. + // Nothing special to do (offline payment). + return null; } /** @@ -74,9 +77,9 @@ public function isValidPayment(): bool return $valid && $this->getCurrentOrderTotalAmount() > 0; } - public function install(ConnectionInterface $con = null): void + public function install(?ConnectionInterface $con = null): void { - $database = new Database($con->getWrappedConnection()); + $database = $this->resolveDatabase($con->getWrappedConnection()); // Insert email message $database->insertSql(null, [__DIR__.'/Config/setup.sql']); @@ -89,7 +92,7 @@ public function install(ConnectionInterface $con = null): void } } - public function destroy(ConnectionInterface $con = null, $deleteModuleData = false): void + public function destroy(?ConnectionInterface $con = null, $deleteModuleData = false): void { // Delete our message if (null !== $message = MessageQuery::create()->findOneByName('order_confirmation_wiretransfer')) { @@ -108,10 +111,39 @@ public function manageStockOnCreation(): bool return false; } + /** + * True on Thelia 3 (twig branch), false on Thelia 2. Gates the Thelia 3-only code paths + * (default-twig hook, Twig extension) so the module works on both versions. + */ + public static function isThelia3(): bool + { + return class_exists(\Thelia\Core\Install\Database::class); + } + + private function resolveDatabase(mixed $connection): object + { + // Thelia 3 moved Database from Thelia\Install to Thelia\Core\Install. + $class = self::isThelia3() + ? \Thelia\Core\Install\Database::class + : \Thelia\Install\Database::class; + + return new $class($connection); + } + public static function configureServices(ServicesConfigurator $servicesConfigurator): void { + $exclude = [__DIR__.'/I18n/*']; + + // Thelia 3-only classes depend on services absent from Thelia 2 (TheliaFormFactory, + // the theme Twig runtime): do not wire them there. + if (!self::isThelia3()) { + $exclude[] = __DIR__.'/Hook/Back/*'; + $exclude[] = __DIR__.'/Twig/*'; + $exclude[] = __DIR__.'/Service/WireTransferBankInfoRenderer.php'; + } + $servicesConfigurator->load(self::getModuleCode().'\\', __DIR__) - ->exclude([THELIA_MODULE_DIR.ucfirst(self::getModuleCode()).'/I18n/*']) + ->exclude($exclude) ->autowire(true) ->autoconfigure(true); } diff --git a/templates/backOffice/default-twig/WireTransfer/module-configuration.html.twig b/templates/backOffice/default-twig/WireTransfer/module-configuration.html.twig new file mode 100644 index 0000000..3eec8c1 --- /dev/null +++ b/templates/backOffice/default-twig/WireTransfer/module-configuration.html.twig @@ -0,0 +1,39 @@ +{# WireTransfer configuration screen (BO default-twig). Ported from the Thelia 2 Smarty template. #} +{% set d = 'wiretransfer.ai' %} +{% set f = config_form %} + +
+ + + + +
+
+ {{ 'Bank account configuration'|trans({}, d) }} +
+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
+ +
+ +
+
From 195aaf3d42bd2f305d57f9f7b596de42f17034ca Mon Sep 17 00:00:00 2001 From: Maxime Bruchet Date: Wed, 5 Aug 2026 10:23:44 +0200 Subject: [PATCH 2/4] refactor!: drop Thelia 2 support, keep Thelia 3 only Removes the Smarty templates, the HookManager hook class and the isThelia3() / resolveDatabase() indirection. Front-office labels move to the module root domain: wiretransfer.fo.default only existed because Thelia derives that domain from templates/frontOffice/*, so deleting the Smarty directory would have unregistered the catalogue the bank-info renderer reads. --- Config/config.xml | 12 ++-- Config/module.xml | 2 +- Config/routing.xml | 7 +-- Controller/ConfigureController.php | 22 +++---- Hook/Back/ConfigurationHook.php | 10 +-- Hook/HookManager.php | 47 -------------- I18n/en_US.php | 3 + I18n/fr_FR.php | 3 + I18n/frontOffice/default/en_US.php | 9 --- I18n/frontOffice/default/fr_FR.php | 9 --- README.md | 49 ++++++++------- Service/WireTransferBankInfoRenderer.php | 16 ++--- Twig/WireTransferExtension.php | 5 +- WireTransfer.php | 34 +---------- .../module-configuration.html.twig | 2 +- .../default/module_configuration.html | 61 ------------------- .../order-placed.additional-payment-info.html | 23 ------- 17 files changed, 63 insertions(+), 251 deletions(-) delete mode 100644 Hook/HookManager.php delete mode 100644 I18n/frontOffice/default/en_US.php delete mode 100644 I18n/frontOffice/default/fr_FR.php delete mode 100644 templates/backOffice/default/module_configuration.html delete mode 100644 templates/frontOffice/default/order-placed.additional-payment-info.html diff --git a/Config/config.xml b/Config/config.xml index 02a4acc..148f7c1 100644 --- a/Config/config.xml +++ b/Config/config.xml @@ -12,12 +12,12 @@
- - - - - - + diff --git a/Config/module.xml b/Config/module.xml index 7c4729f..070f78e 100644 --- a/Config/module.xml +++ b/Config/module.xml @@ -7,7 +7,7 @@ Wire transfer payment - 2.2.0 + 2.3.0 Thelia info@thelia.net diff --git a/Config/routing.xml b/Config/routing.xml index d9e3fed..7259629 100644 --- a/Config/routing.xml +++ b/Config/routing.xml @@ -1,9 +1,8 @@ getMessage(); } - // At this point, the form has errors, and should be redisplayed. We don not redirect, - // just redisplay the same template. // Setup the Form error context, to make error information available in the template. $this->setupFormErrorContext( $translator->trans('Wire transfer configuration', [], WireTransfer::MESSAGE_DOMAIN), @@ -100,20 +98,14 @@ public function configure(Request $request, Translator $translator) $ex ); - // Thelia 3 renders the config screen through a hook (default-twig), so redirect back - // to the module configuration page. On Thelia 2, redisplay the current template inline - // to keep the form error context. - if (WireTransfer::isThelia3()) { - // The redirect drops the ParserContext form error, so surface the failure through - // the flash bag (rendered by the default-twig base template as app.flashes). - $session = $request->getSession(); - if ($session instanceof FlashBagAwareSessionInterface) { - $session->getFlashBag()->add('danger', $error_msg); - } - - return new RedirectResponse(URL::getInstance()->absoluteUrl('/admin/module/WireTransfer')); + // The configuration screen is rendered through a hook, so redirect back to the module + // configuration page. That redirect drops the ParserContext form error, hence the flash + // bag (rendered by the default-twig base template as app.flashes). + $session = $request->getSession(); + if ($session instanceof FlashBagAwareSessionInterface) { + $session->getFlashBag()->add('danger', $error_msg); } - return $this->render('module-configure', ['module_code' => 'WireTransfer']); + return new RedirectResponse(URL::getInstance()->absoluteUrl('/admin/module/WireTransfer')); } } diff --git a/Hook/Back/ConfigurationHook.php b/Hook/Back/ConfigurationHook.php index 9017eb9..6f45fda 100644 --- a/Hook/Back/ConfigurationHook.php +++ b/Hook/Back/ConfigurationHook.php @@ -21,11 +21,9 @@ use Thelia\Core\Hook\BaseHook; use Thelia\Core\Template\Parser\ParserResolver; use WireTransfer\Form\ConfigurationForm; -use WireTransfer\WireTransfer; /** - * Renders the WireTransfer configuration screen in the Thelia 3 default-twig back-office. - * The Thelia 2 rendering stays in WireTransfer\Hook\HookManager (Smarty). + * Renders the WireTransfer configuration screen in the default-twig back-office. */ class ConfigurationHook extends BaseHook { @@ -39,12 +37,6 @@ public function __construct( public static function getSubscribedHooks(): array { - if (!WireTransfer::isThelia3()) { - return []; // Thelia 2 uses WireTransfer\Hook\HookManager (config.xml) instead. - } - - // Distinct method name from HookManager::onModuleConfigure so the two classes do not - // overwrite each other's module_hook row (keyed by module + hook + method). return [ 'module.configuration' => [ ['type' => 'back', 'method' => 'onModuleConfiguration'], diff --git a/Hook/HookManager.php b/Hook/HookManager.php deleted file mode 100644 index a1ca9ac..0000000 --- a/Hook/HookManager.php +++ /dev/null @@ -1,47 +0,0 @@ -add($this->render('module_configuration.html')); - } - - public function onAdditionalPaymentInfo(HookRenderEvent $event): void - { - if (WireTransfer::isThelia3()) { - return; - } - - $event->add($this->render('order-placed.additional-payment-info.html', [ - 'placed_order_id' => $event->getArgument('placed_order_id'), - ])); - } -} diff --git a/I18n/en_US.php b/I18n/en_US.php index 74b9519..bd1017b 100644 --- a/I18n/en_US.php +++ b/I18n/en_US.php @@ -3,8 +3,11 @@ return array( 'Account holder name' => 'Account holder name', 'BIC (Bank Identifier Code)' => 'BIC (Bank Identifier Code)', + 'BIC code' => 'BIC code', 'Bank information parameters have not been defined.' => 'Bank information parameters have not been defined.', + 'IBAN' => 'IBAN', 'IBAN (International Bank Account Number)' => 'IBAN (International Bank Account Number)', 'Message displayed to your customer when order is placed' => 'Message displayed to your customer when order is placed', 'Wire transfer configuration' => 'Wire transfer configuration', + 'You may now do a transfer to this bank account: ' => 'You may now do a transfer to this bank account: ', ); diff --git a/I18n/fr_FR.php b/I18n/fr_FR.php index eae24e8..d1179aa 100644 --- a/I18n/fr_FR.php +++ b/I18n/fr_FR.php @@ -3,8 +3,11 @@ return array( 'Account holder name' => 'Titulaire du compte', 'BIC (Bank Identifier Code)' => 'BIC (Bank Identifier Code)', + 'BIC code' => 'Code BIC', 'Bank information parameters have not been defined.' => 'Les paramètres bancaires n\'ont pas été définis', + 'IBAN' => 'IBAN', 'IBAN (International Bank Account Number)' => 'IBAN (International Bank Account Number)', 'Message displayed to your customer when order is placed' => 'Message affiché à vos clients une fois leur commande payée', 'Wire transfer configuration' => 'Informations de virement', + 'You may now do a transfer to this bank account: ' => 'Merci de virer le montant de votre commande sur le compte suivant :', ); diff --git a/I18n/frontOffice/default/en_US.php b/I18n/frontOffice/default/en_US.php deleted file mode 100644 index 14f7de6..0000000 --- a/I18n/frontOffice/default/en_US.php +++ /dev/null @@ -1,9 +0,0 @@ - 'Account holder name', - 'BIC code' => 'BIC code', - 'IBAN' => 'IBAN', - 'This order has not been paid using a bank transfert' => 'This order has not been paid using a bank transfert', - 'You may now do a transfer to this bank account: ' => 'You may now do a transfer to this bank account: ', -); diff --git a/I18n/frontOffice/default/fr_FR.php b/I18n/frontOffice/default/fr_FR.php deleted file mode 100644 index 3979f60..0000000 --- a/I18n/frontOffice/default/fr_FR.php +++ /dev/null @@ -1,9 +0,0 @@ - 'Titulaire du compte', - 'BIC code' => 'Code BIC', - 'IBAN' => 'IBAN', - 'This order has not been paid using a bank transfert' => 'Cette commande n\'a pas été payée par virement bancaire.', - 'You may now do a transfer to this bank account: ' => 'Merci de virer le montant de votre commande sur le compte suivant :', -); diff --git a/README.md b/README.md index faa79a9..91cd493 100644 --- a/README.md +++ b/README.md @@ -132,41 +132,40 @@ The bank account information are displayed in `order-placed.html` file of the de using the `order-placed.additional-payment-info` hook. -Thelia 3 (version 2.2.0+) +Thelia 3 (version 2.3.0+) ------------------------- -À partir de la 2.2.0, le module est **bi-compatible Thelia 2.5 et Thelia 3** (branche twig, Symfony 7.4, -Flexy). L'aiguillage se fait via `WireTransfer::isThelia3()` ; le code Thelia 2 (templates Smarty, hooks) -reste en place et n'est actif que sous Thelia 2. As of 2.2.0 the module is **dual-compatible with Thelia 2.5 -and Thelia 3**; the Thelia 2 code path stays in place and is only active under Thelia 2. +À partir de la 2.3.0, le module est **Thelia 3 uniquement** (branche twig, Symfony 7.4, PHP 8.3, Flexy). +Le support Thelia 2 a été retiré : pour Thelia 2.5, utilisez la ligne 2.1. As of 2.3.0 the module is +**Thelia 3 only**; use the 2.1 line for Thelia 2.5. -### Ce qui change en Thelia 3 / What changes on Thelia 3 +### Rendu des surfaces / Where each surface lives -- **Back-office** : la page de configuration est rendue en `default-twig` (Twig) via le hook - `WireTransfer\Hook\Back\ConfigurationHook` (`module.configuration`), template - `templates/backOffice/default-twig/WireTransfer/module-configuration.html.twig`. En Thelia 2, le rendu - Smarty (`templates/backOffice/default/module_configuration.html`) est conservé. -- **Front-office (Flexy)** : le hook Smarty `order-placed.additional-payment-info` n'existe plus. Les - coordonnées bancaires sont désormais fournies par une **fonction Twig** à appeler dans le thème, sur la - page de confirmation de commande : +- **Back-office** : la page de configuration est rendue via le hook + `WireTransfer\Hook\Back\ConfigurationHook` (`module.configuration`, déclaré par + `getSubscribedHooks()`, donc auto-découvert — `Config/config.xml` n'a plus de section ``), + template `templates/backOffice/default-twig/WireTransfer/module-configuration.html.twig`. +- **Front-office (Flexy)** : Flexy n'a pas de hook front-office. Les coordonnées bancaires sont + fournies par une **fonction Twig** à appeler dans le thème, sur la page de confirmation de + commande : ```twig {{ wiretransfer_bank_info(order_id) }} ``` - Elle ne rend rien si la commande n'a pas été payée par virement. En Thelia 2, l'affichage reste assuré par - le hook `order-placed.additional-payment-info` (template Smarty `order-placed.additional-payment-info.html`) - et la boucle `wiretransfer.get.info`. -- **Routes** : déclarées dans `Config/routing.xml` (chargé par Thelia 2 **et** Thelia 3), sans - attribut `#[Route]` — sinon Thelia 3 enregistrerait la route en double (chemin inchangé + Elle ne rend rien si la commande n'a pas été payée par virement. Le markup est construit par + `WireTransfer\Service\WireTransferBankInfoRenderer`, qui est la **seule barrière + d'échappement** — le message configuré par le marchand est volontairement rendu brut. +- **Routes** : déclarées dans `Config/routing.xml` **uniquement**, sans attribut `#[Route]` — + Thelia 3 charge les deux mécanismes et enregistrerait la route en double (chemin inchangé `/admin/wiretransfer/configure`). -- **Compatibilité des signatures** : `pay(Order): ?Response`, `install/destroy(?ConnectionInterface)`, - `ConfigurationForm::getName(): string`, et types de retour sur la boucle — compatibles Thelia 2 et 3. -- **Classe `Database`** résolue à l'exécution (`Thelia\Install\Database` en T2, `Thelia\Core\Install\Database` - en T3). +- **Traductions** : les libellés front vivent désormais dans le domaine racine du module + (`wiretransfer`, `I18n/en_US.php` et `I18n/fr_FR.php`) et non plus dans `wiretransfer.fo.default`. + Ce domaine-là n'existait que parce que Thelia le construit en scannant `templates/frontOffice/*` : + supprimer le dossier Smarty aurait désenregistré le catalogue. ### Boucle `wiretransfer.get.info` -Toujours disponible et inchangée (Thelia 2 et Thelia 3) : elle retourne `ACCOUNT_HOLDER_NAME`, `IBAN`, `BIC`, -`MESSAGE` pour un `order_id`. Sous Thelia 3 / Flexy, préférez la fonction Twig `wiretransfer_bank_info()` -ci-dessus, qui encapsule cette logique. \ No newline at end of file +Toujours disponible et inchangée : elle retourne `ACCOUNT_HOLDER_NAME`, `IBAN`, `BIC`, `MESSAGE` +pour un `order_id`. Sous Flexy, préférez la fonction Twig `wiretransfer_bank_info()` ci-dessus, qui +encapsule cette logique — la boucle n'a plus de consommateur dans le module. \ No newline at end of file diff --git a/Service/WireTransferBankInfoRenderer.php b/Service/WireTransferBankInfoRenderer.php index a6ea878..57e3a6b 100644 --- a/Service/WireTransferBankInfoRenderer.php +++ b/Service/WireTransferBankInfoRenderer.php @@ -19,9 +19,9 @@ use WireTransfer\WireTransfer; /** - * Builds the "bank account details" markup shown on the order confirmation page (Thelia 3 - * Flexy theme), replacing the Thelia 2 `order-placed.additional-payment-info` Smarty hook. - * Kept out of the Twig extension so the extension stays a thin integration layer. + * Builds the "bank account details" markup shown on the order confirmation page of the Flexy + * theme, which has no front-office hook to render them into. Kept out of the Twig extension so + * the extension stays a thin integration layer. */ final readonly class WireTransferBankInfoRenderer { @@ -42,12 +42,12 @@ public function bankInfo(int|string|null $orderId): string $message = (string) WireTransfer::getConfigValue('message'); $translator = Translator::getInstance(); - $intro = htmlspecialchars($translator->trans('You may now do a transfer to this bank account: ', [], 'wiretransfer.fo.default'), ENT_QUOTES); - $holderLabel = htmlspecialchars($translator->trans('Account holder name', [], 'wiretransfer.fo.default'), ENT_QUOTES); - $ibanLabel = htmlspecialchars($translator->trans('IBAN', [], 'wiretransfer.fo.default'), ENT_QUOTES); - $bicLabel = htmlspecialchars($translator->trans('BIC code', [], 'wiretransfer.fo.default'), ENT_QUOTES); + $intro = htmlspecialchars($translator->trans('You may now do a transfer to this bank account: ', [], WireTransfer::MESSAGE_DOMAIN), ENT_QUOTES); + $holderLabel = htmlspecialchars($translator->trans('Account holder name', [], WireTransfer::MESSAGE_DOMAIN), ENT_QUOTES); + $ibanLabel = htmlspecialchars($translator->trans('IBAN', [], WireTransfer::MESSAGE_DOMAIN), ENT_QUOTES); + $bicLabel = htmlspecialchars($translator->trans('BIC code', [], WireTransfer::MESSAGE_DOMAIN), ENT_QUOTES); - // The merchant-configured message is trusted admin content (rendered raw, as in T2). + // The merchant-configured message is trusted admin content, so it is rendered raw. $messageBlock = '' !== $message ? '
'.$message.'
' : ''; return <<resolveDatabase($con->getWrappedConnection()); + $database = new Database($con->getWrappedConnection()); // Insert email message $database->insertSql(null, [__DIR__.'/Config/setup.sql']); @@ -111,39 +112,10 @@ public function manageStockOnCreation(): bool return false; } - /** - * True on Thelia 3 (twig branch), false on Thelia 2. Gates the Thelia 3-only code paths - * (default-twig hook, Twig extension) so the module works on both versions. - */ - public static function isThelia3(): bool - { - return class_exists(\Thelia\Core\Install\Database::class); - } - - private function resolveDatabase(mixed $connection): object - { - // Thelia 3 moved Database from Thelia\Install to Thelia\Core\Install. - $class = self::isThelia3() - ? \Thelia\Core\Install\Database::class - : \Thelia\Install\Database::class; - - return new $class($connection); - } - public static function configureServices(ServicesConfigurator $servicesConfigurator): void { - $exclude = [__DIR__.'/I18n/*']; - - // Thelia 3-only classes depend on services absent from Thelia 2 (TheliaFormFactory, - // the theme Twig runtime): do not wire them there. - if (!self::isThelia3()) { - $exclude[] = __DIR__.'/Hook/Back/*'; - $exclude[] = __DIR__.'/Twig/*'; - $exclude[] = __DIR__.'/Service/WireTransferBankInfoRenderer.php'; - } - $servicesConfigurator->load(self::getModuleCode().'\\', __DIR__) - ->exclude($exclude) + ->exclude([__DIR__.'/I18n/*']) ->autowire(true) ->autoconfigure(true); } diff --git a/templates/backOffice/default-twig/WireTransfer/module-configuration.html.twig b/templates/backOffice/default-twig/WireTransfer/module-configuration.html.twig index 3eec8c1..687e40f 100644 --- a/templates/backOffice/default-twig/WireTransfer/module-configuration.html.twig +++ b/templates/backOffice/default-twig/WireTransfer/module-configuration.html.twig @@ -1,4 +1,4 @@ -{# WireTransfer configuration screen (BO default-twig). Ported from the Thelia 2 Smarty template. #} +{# WireTransfer configuration screen, rendered into the module.configuration back-office hook. #} {% set d = 'wiretransfer.ai' %} {% set f = config_form %} diff --git a/templates/backOffice/default/module_configuration.html b/templates/backOffice/default/module_configuration.html deleted file mode 100644 index f48fe0c..0000000 --- a/templates/backOffice/default/module_configuration.html +++ /dev/null @@ -1,61 +0,0 @@ -{if isset($smarty.get.errmes) && !empty($smarty.get.errmes)} -
- {$smarty.get.errmes} -
-{/if} - -
-
- -
-
- {intl d='wiretransfer.ai' l="Bank account configuration"} -
-
- -
-
-
- - {form name="transfer.configure.bic"} - - - {include - file = "includes/inner-form-toolbar.html" - hide_flags = true - - page_url = {url path="/admin/module/WireTransfer"} - close_url = {url path="/admin/modules"} - } - - {form_hidden_fields form=$form} - - {if $form_error} -
-
-
{$form_error_message}
-
-
- {/if} - - {render_form_field field="name"} - {render_form_field field="iban"} - {render_form_field field="bic"} - {render_form_field field="message" extra_class="wysiwyg"} - - {include - file = "includes/inner-form-toolbar.html" - hide_flags = true - page_bottom = true - - page_url = {url path="/admin/module/WireTransfer"} - close_url = {url path="/admin/modules"} - } - - - {/form} -
-
-
-
-
diff --git a/templates/frontOffice/default/order-placed.additional-payment-info.html b/templates/frontOffice/default/order-placed.additional-payment-info.html deleted file mode 100644 index cfce800..0000000 --- a/templates/frontOffice/default/order-placed.additional-payment-info.html +++ /dev/null @@ -1,23 +0,0 @@ -{ifloop rel="wiretransfer.infos"} -

{intl d='wiretransfer.fo.default' l="You may now do a transfer to this bank account: "}

- {loop name="wiretransfer.infos" type="wiretransfer.get.info" order_id=$placed_order_id} -
-
{intl d='wiretransfer.fo.default' l="Account holder name"} :
-
{$ACCOUNT_HOLDER_NAME}
- -
{intl d='wiretransfer.fo.default' l="IBAN"} :
-
{$IBAN}
- -
{intl d='wiretransfer.fo.default' l="BIC code"} :
-
{$BIC}
-
- {if $MESSAGE} -
{$MESSAGE nofilter}
- {/if} - {/loop} -{/ifloop} -{elseloop rel="wiretransfer.infos"} -
- {intl d='wiretransfer.fo.default' l="This order has not been paid using a bank transfert"} -
-{/elseloop} From a7ce4981299db0e34b9c7a12fae90312e2f97799 Mon Sep 17 00:00:00 2001 From: Maxime Bruchet Date: Wed, 5 Aug 2026 11:04:40 +0200 Subject: [PATCH 3/4] fix: stop sending the confirmation email twice, plus review follow-up MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SendPaymentConfirmationEmail was declared in Config/config.xml as `send.wiretransfer.mail` AND auto-discovered by configureServices(). Two service ids for one subscriber class means Symfony registers two listeners on ORDER_UPDATE_STATUS, so the customer received the wire-transfer confirmation twice on every switch to paid. Auto-discovery alone is now authoritative. Also: - Drop the listener's unused ParserInterface dependency, which autowiring resolved to the throwing ParserFallback. - install(): pass $con straight to Database, whose constructor already accepts null and unwraps a ConnectionWrapper — the manual getWrappedConnection() was duplicating that and would fatal on the null the signature allows. Drop the dead argument to isModuleImageDeployed(), which declares no parameter. - Route the form labels through the trans() helper that existed unused. - Use the inherited $this->translator instead of an injected duplicate. - Correct the claim that Thelia 3 has no front-office hooks: it has ThemeHookInterface + theme_hook(), but the active theme declares no point. --- Config/config.xml | 15 ++-- Controller/ConfigureController.php | 5 +- Form/ConfigurationForm.php | 13 ++-- Listener/SendPaymentConfirmationEmail.php | 86 +++++++++-------------- README.md | 8 ++- Service/WireTransferBankInfoRenderer.php | 8 ++- Twig/WireTransferExtension.php | 9 ++- WireTransfer.php | 8 ++- 8 files changed, 73 insertions(+), 79 deletions(-) diff --git a/Config/config.xml b/Config/config.xml index 148f7c1..b952cf3 100644 --- a/Config/config.xml +++ b/Config/config.xml @@ -19,12 +19,13 @@ Twig function. --> - - - - - - - + diff --git a/Controller/ConfigureController.php b/Controller/ConfigureController.php index 92fa58a..76a813e 100644 --- a/Controller/ConfigureController.php +++ b/Controller/ConfigureController.php @@ -36,7 +36,6 @@ use Thelia\Core\HttpFoundation\Request; use Thelia\Core\Security\AccessManager; use Thelia\Core\Security\Resource\AdminResources; -use Thelia\Core\Translation\Translator; use Thelia\Form\Exception\FormValidationException; use Thelia\Tools\URL; use WireTransfer\Form\ConfigurationForm; @@ -49,7 +48,7 @@ */ class ConfigureController extends BaseAdminController { - public function configure(Request $request, Translator $translator) + public function configure(Request $request) { if (null !== $response = $this->checkAuth(AdminResources::MODULE, 'WireTransfer', AccessManager::UPDATE)) { return $response; @@ -92,7 +91,7 @@ public function configure(Request $request, Translator $translator) // Setup the Form error context, to make error information available in the template. $this->setupFormErrorContext( - $translator->trans('Wire transfer configuration', [], WireTransfer::MESSAGE_DOMAIN), + $this->translator->trans('Wire transfer configuration', [], WireTransfer::MESSAGE_DOMAIN), $error_msg, $configurationForm, $ex diff --git a/Form/ConfigurationForm.php b/Form/ConfigurationForm.php index fca0651..3fc69bc 100644 --- a/Form/ConfigurationForm.php +++ b/Form/ConfigurationForm.php @@ -46,7 +46,10 @@ */ class ConfigurationForm extends BaseForm { - protected function trans($str, $params = []) + /** + * @param array $params + */ + protected function trans(string $str, array $params = []): string { return Translator::getInstance()->trans($str, $params, WireTransfer::MESSAGE_DOMAIN); } @@ -60,7 +63,7 @@ protected function buildForm(): void [ 'constraints' => [new NotBlank()], 'required' => true, - 'label' => Translator::getInstance()->trans('Account holder name', [], WireTransfer::MESSAGE_DOMAIN), + 'label' => $this->trans('Account holder name'), 'data' => WireTransfer::getConfigValue('name', ''), 'label_attr' => [ 'for' => 'namefield', @@ -73,7 +76,7 @@ protected function buildForm(): void [ 'constraints' => [new NotBlank(), new Iban()], 'required' => true, - 'label' => Translator::getInstance()->trans('IBAN (International Bank Account Number)', [], WireTransfer::MESSAGE_DOMAIN), + 'label' => $this->trans('IBAN (International Bank Account Number)'), 'data' => WireTransfer::getConfigValue('iban', ''), 'label_attr' => [ 'for' => 'ibanfield', @@ -86,7 +89,7 @@ protected function buildForm(): void [ 'constraints' => [new NotBlank(), new BIC()], 'required' => true, - 'label' => Translator::getInstance()->trans('BIC (Bank Identifier Code)', [], WireTransfer::MESSAGE_DOMAIN), + 'label' => $this->trans('BIC (Bank Identifier Code)'), 'data' => WireTransfer::getConfigValue('bic', ''), 'label_attr' => [ 'for' => 'bicfield', @@ -98,7 +101,7 @@ protected function buildForm(): void TextareaType::class, [ 'required' => false, - 'label' => Translator::getInstance()->trans('Message displayed to your customer when order is placed', [], WireTransfer::MESSAGE_DOMAIN), + 'label' => $this->trans('Message displayed to your customer when order is placed'), 'data' => WireTransfer::getConfigValue('message', ''), 'label_attr' => [ 'for' => 'messagefield', diff --git a/Listener/SendPaymentConfirmationEmail.php b/Listener/SendPaymentConfirmationEmail.php index ce22009..0678ae9 100644 --- a/Listener/SendPaymentConfirmationEmail.php +++ b/Listener/SendPaymentConfirmationEmail.php @@ -25,83 +25,63 @@ namespace WireTransfer\Listener; -use WireTransfer\WireTransfer; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Thelia\Action\BaseAction; use Thelia\Core\Event\Order\OrderEvent; use Thelia\Core\Event\TheliaEvents; use Thelia\Mailer\MailerFactory; -use Thelia\Core\Template\ParserInterface; use Thelia\Model\ConfigQuery; -use Thelia\Model\MessageQuery; +use WireTransfer\WireTransfer; + /** - * Class SendEMail - * @package IciRelais\Listener - * @author Thelia + * Sends the wire-transfer confirmation email once the order is marked as paid. + * + * Registered by auto-discovery only (`WireTransfer::configureServices()`). It must NOT also be + * declared in Config/config.xml: two service ids for one subscriber class means two listeners, + * and the customer gets the email twice. */ class SendPaymentConfirmationEmail extends BaseAction implements EventSubscriberInterface { - - /** - * @var MailerFactory - */ - protected $mailer; - /** - * @var ParserInterface - */ - protected $parser; - - public function __construct(ParserInterface $parser,MailerFactory $mailer) - { - $this->parser = $parser; - $this->mailer = $mailer; + public function __construct( + private readonly MailerFactory $mailer, + ) { } - /** - * @return \Thelia\Mailer\MailerFactory - */ - public function getMailer() + public function getMailer(): MailerFactory { return $this->mailer; } - /* - * @params OrderEvent $order - * - * Checks if order delivery module is icirelais and if order new status is sent, send an email to the customer. + /** + * Notifies the customer once an order paid by wire transfer reaches the paid status. */ - public function sendConfirmationEmail(OrderEvent $event) + public function sendConfirmationEmail(OrderEvent $event): void { - if ($event->getOrder()->getPaymentModuleId() === WireTransfer::getModuleId()) { - if ($event->getOrder()->isPaid()) { - $contact_email = ConfigQuery::getStoreEmail(); + $order = $event->getOrder(); - if ($contact_email) { - $order = $event->getOrder(); - $customer = $order->getCustomer(); + if ($order->getPaymentModuleId() !== WireTransfer::getModuleId() || !$order->isPaid()) { + return; + } - $this->getMailer()->sendEmailToCustomer( - 'order_confirmation_wiretransfer', - $customer, - [ - 'order_id' => $order->getId(), - 'order_ref'=> $order->getRef() - ] - ); - } - } + // No store email configured means the mailer has no sender to work with. + if (!ConfigQuery::getStoreEmail()) { + return; } + $this->getMailer()->sendEmailToCustomer( + 'order_confirmation_wiretransfer', + $order->getCustomer(), + [ + 'order_id' => $order->getId(), + 'order_ref' => $order->getRef(), + ] + ); } - /** - * @inheritdoc - */ - public static function getSubscribedEvents() + public static function getSubscribedEvents(): array { - return array( - TheliaEvents::ORDER_UPDATE_STATUS => array("sendConfirmationEmail", 128) - ); + return [ + TheliaEvents::ORDER_UPDATE_STATUS => ['sendConfirmationEmail', 128], + ]; } - } diff --git a/README.md b/README.md index 91cd493..4d52df6 100644 --- a/README.md +++ b/README.md @@ -145,9 +145,11 @@ Le support Thelia 2 a été retiré : pour Thelia 2.5, utilisez la ligne 2.1. As `WireTransfer\Hook\Back\ConfigurationHook` (`module.configuration`, déclaré par `getSubscribedHooks()`, donc auto-découvert — `Config/config.xml` n'a plus de section ``), template `templates/backOffice/default-twig/WireTransfer/module-configuration.html.twig`. -- **Front-office (Flexy)** : Flexy n'a pas de hook front-office. Les coordonnées bancaires sont - fournies par une **fonction Twig** à appeler dans le thème, sur la page de confirmation de - commande : +- **Front-office** : Thelia 3 a supprimé les hooks Smarty du front. Il fournit à la place + `Thelia\Core\Hook\Theme\ThemeHookInterface`, répondu là où un thème appelle + `theme_hook('point')` — mais le thème doit déclarer le point, ce que `vallereuil-scierie` ne + fait pas encore. En attendant, les coordonnées bancaires sont exposées par une **fonction + Twig** : ```twig {{ wiretransfer_bank_info(order_id) }} diff --git a/Service/WireTransferBankInfoRenderer.php b/Service/WireTransferBankInfoRenderer.php index 57e3a6b..10ec176 100644 --- a/Service/WireTransferBankInfoRenderer.php +++ b/Service/WireTransferBankInfoRenderer.php @@ -19,9 +19,11 @@ use WireTransfer\WireTransfer; /** - * Builds the "bank account details" markup shown on the order confirmation page of the Flexy - * theme, which has no front-office hook to render them into. Kept out of the Twig extension so - * the extension stays a thin integration layer. + * Builds the "bank account details" markup shown on the order confirmation page. + * + * Kept out of the Twig extension so the extension stays a thin integration layer, and out of a + * template because the markup has to be reachable from both a Twig function and a + * ThemeHookInterface implementation. */ final readonly class WireTransferBankInfoRenderer { diff --git a/Twig/WireTransferExtension.php b/Twig/WireTransferExtension.php index a90ff60..7cf4f8f 100644 --- a/Twig/WireTransferExtension.php +++ b/Twig/WireTransferExtension.php @@ -19,9 +19,12 @@ use WireTransfer\Service\WireTransferBankInfoRenderer; /** - * Exposes the WireTransfer bank details to the Flexy theme, which has no front-office hook to - * render them into. Call it on the order confirmation page, e.g. - * {{ wiretransfer_bank_info(order_id) }}. + * Exposes the WireTransfer bank details to the front-office theme. Call it on the order + * confirmation page, e.g. {{ wiretransfer_bank_info(order_id) }}. + * + * NOTE: a theme template must not call this directly — a module Twig function is resolved at + * compile time, so the page breaks when the module is disabled. Prefer a theme_hook() point + * answered by a ThemeHookInterface implementation. */ final class WireTransferExtension extends AbstractExtension { diff --git a/WireTransfer.php b/WireTransfer.php index fccbd88..8d56d4a 100644 --- a/WireTransfer.php +++ b/WireTransfer.php @@ -80,7 +80,11 @@ public function isValidPayment(): bool public function install(?ConnectionInterface $con = null): void { - $database = new Database($con->getWrappedConnection()); + // $con is passed straight through: Database's constructor accepts + // ConnectionInterface|PDO|null, unwraps a ConnectionWrapper itself and falls back to a + // Propel write connection when given null. Calling getWrappedConnection() here would + // duplicate that and blow up on the null the signature explicitly allows. + $database = new Database($con); // Insert email message $database->insertSql(null, [__DIR__.'/Config/setup.sql']); @@ -88,7 +92,7 @@ public function install(?ConnectionInterface $con = null): void /* insert the images from image folder if not already done */ $moduleModel = $this->getModuleModel(); - if (!$moduleModel->isModuleImageDeployed($con)) { + if (!$moduleModel->isModuleImageDeployed()) { $this->deployImageFolder($moduleModel, sprintf('%s/images', __DIR__), $con); } } From 2944e1aa4d594e11cc3ff3cc483db7efdb12c03a Mon Sep 17 00:00:00 2001 From: Maxime Bruchet Date: Wed, 5 Aug 2026 11:21:32 +0200 Subject: [PATCH 4/4] docs: correct the front-office hook rationale ThemeHookInterface exists but nothing consumes its thelia.theme_hook tag and no theme_hook() Twig function is registered, so it cannot be used to render the bank details. The Twig function stays the only mechanism available today. --- README.md | 9 ++++----- Service/WireTransferBankInfoRenderer.php | 5 ++--- Twig/WireTransferExtension.php | 4 ++-- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 4d52df6..456d4d7 100644 --- a/README.md +++ b/README.md @@ -145,11 +145,10 @@ Le support Thelia 2 a été retiré : pour Thelia 2.5, utilisez la ligne 2.1. As `WireTransfer\Hook\Back\ConfigurationHook` (`module.configuration`, déclaré par `getSubscribedHooks()`, donc auto-découvert — `Config/config.xml` n'a plus de section ``), template `templates/backOffice/default-twig/WireTransfer/module-configuration.html.twig`. -- **Front-office** : Thelia 3 a supprimé les hooks Smarty du front. Il fournit à la place - `Thelia\Core\Hook\Theme\ThemeHookInterface`, répondu là où un thème appelle - `theme_hook('point')` — mais le thème doit déclarer le point, ce que `vallereuil-scierie` ne - fait pas encore. En attendant, les coordonnées bancaires sont exposées par une **fonction - Twig** : +- **Front-office** : Thelia 3 a supprimé les hooks Smarty du front **sans remplacement + fonctionnel** — `ThemeHookInterface` et le tag `thelia.theme_hook` existent, mais rien ne + consomme le tag et aucune fonction Twig `theme_hook()` n'est enregistrée. Les coordonnées + bancaires sont donc exposées par une **fonction Twig** : ```twig {{ wiretransfer_bank_info(order_id) }} diff --git a/Service/WireTransferBankInfoRenderer.php b/Service/WireTransferBankInfoRenderer.php index 10ec176..79911da 100644 --- a/Service/WireTransferBankInfoRenderer.php +++ b/Service/WireTransferBankInfoRenderer.php @@ -21,9 +21,8 @@ /** * Builds the "bank account details" markup shown on the order confirmation page. * - * Kept out of the Twig extension so the extension stays a thin integration layer, and out of a - * template because the markup has to be reachable from both a Twig function and a - * ThemeHookInterface implementation. + * Kept out of the Twig extension so the extension stays a thin integration layer, and built in + * PHP rather than a template so it can be served from either a Twig function or a controller. */ final readonly class WireTransferBankInfoRenderer { diff --git a/Twig/WireTransferExtension.php b/Twig/WireTransferExtension.php index 7cf4f8f..de0c94f 100644 --- a/Twig/WireTransferExtension.php +++ b/Twig/WireTransferExtension.php @@ -23,8 +23,8 @@ * confirmation page, e.g. {{ wiretransfer_bank_info(order_id) }}. * * NOTE: a theme template must not call this directly — a module Twig function is resolved at - * compile time, so the page breaks when the module is disabled. Prefer a theme_hook() point - * answered by a ThemeHookInterface implementation. + * compile time, so the page breaks when the module is disabled. Thelia 3 offers no usable front + * hook either (ThemeHookInterface is not wired), so the theme should fetch a module route. */ final class WireTransferExtension extends AbstractExtension {