From a9dfd04e9fe6379afb988a6357e2dcb021b4fe56 Mon Sep 17 00:00:00 2001 From: Xavier Date: Thu, 13 Oct 2022 15:14:53 +0200 Subject: [PATCH 01/15] refactor(admin): replace overwrite of view for admin/view in admin package Uses a container admin/view set with Mustache engine only for admin package. Resolves issues with default view from different contexts. Add custom Admin TemplateRoute extending App TemplateRoute with the overwriting view container. Overwrite model/dependencies to set the admin/view container. --- .../Admin/Action/Widget/LoadAction.php | 2 +- .../admin/src/Charcoal/Admin/AdminModule.php | 15 +++++--- .../admin/src/Charcoal/Admin/AdminWidget.php | 1 + .../Admin/Property/AbstractProperty.php | 2 +- .../Admin/Property/Display/StatusDisplay.php | 2 +- .../Charcoal/Admin/Route/TemplateRoute.php | 26 +++++++++++++ .../ServiceProvider/AdminServiceProvider.php | 38 ++++++++++++++++--- .../FormGroup/NestedWidgetFormGroup.php | 2 +- .../Charcoal/Admin/Widget/FormGroupWidget.php | 2 +- .../Admin/Widget/FormPropertyWidget.php | 1 - .../src/Charcoal/Admin/Widget/TableWidget.php | 1 - .../Charcoal/Admin/Service/ExporterTest.php | 2 +- .../Charcoal/Admin/Widget/TableWidgetTest.php | 2 +- .../Widget/FormGroup/AttachmentFormGroup.php | 2 +- .../src/Charcoal/Property/SpriteProperty.php | 3 +- 15 files changed, 79 insertions(+), 22 deletions(-) create mode 100644 packages/admin/src/Charcoal/Admin/Route/TemplateRoute.php diff --git a/packages/admin/src/Charcoal/Admin/Action/Widget/LoadAction.php b/packages/admin/src/Charcoal/Admin/Action/Widget/LoadAction.php index 8fcf6d9f9..cded785e7 100644 --- a/packages/admin/src/Charcoal/Admin/Action/Widget/LoadAction.php +++ b/packages/admin/src/Charcoal/Admin/Action/Widget/LoadAction.php @@ -319,7 +319,7 @@ protected function setDependencies(Container $container) parent::setdependencies($container); $this->setWidgetFactory($container['widget/factory']); - $this->setWidgetView($container['view']); + $this->setWidgetView($container['admin/view']); } diff --git a/packages/admin/src/Charcoal/Admin/AdminModule.php b/packages/admin/src/Charcoal/Admin/AdminModule.php index 3d32be4f8..018719a1b 100644 --- a/packages/admin/src/Charcoal/Admin/AdminModule.php +++ b/packages/admin/src/Charcoal/Admin/AdminModule.php @@ -105,6 +105,7 @@ public function setupHandlers( $container->extend('notFoundHandler', function ($handler, $container) { $appConfig = $container['config']; $adminConfig = $container['admin/config']; + $adminView = $container['admin/view']; if ($handler instanceof HandlerInterface) { $config = $handler->createConfig($appConfig['handlers.defaults']); $config->merge($adminConfig['handlers.defaults']); @@ -113,7 +114,7 @@ public function setupHandlers( $config->merge($adminConfig['handlers.notFound']); } - $handler->setConfig($config)->init(); + $handler->setView($adminView)->setConfig($config)->init(); } return $handler; @@ -128,6 +129,7 @@ public function setupHandlers( $container->extend('notAllowedHandler', function ($handler, $container) { $appConfig = $container['config']; $adminConfig = $container['admin/config']; + $adminView = $container['admin/view']; if ($handler instanceof HandlerInterface) { $config = $handler->createConfig($appConfig['handlers.defaults']); $config->merge($adminConfig['handlers.defaults']); @@ -136,7 +138,7 @@ public function setupHandlers( $config->merge($adminConfig['handlers.notAllowed']); } - $handler->setConfig($config)->init(); + $handler->setView($adminView)->setConfig($config)->init(); } return $handler; @@ -151,6 +153,7 @@ public function setupHandlers( $container->extend('phpErrorHandler', function ($handler, $container) { $appConfig = $container['config']; $adminConfig = $container['admin/config']; + $adminView = $container['admin/view']; if ($handler instanceof HandlerInterface) { $config = $handler->createConfig($appConfig['handlers.defaults']); $config->merge($adminConfig['handlers.defaults']); @@ -159,7 +162,7 @@ public function setupHandlers( $config->merge($adminConfig['handlers.phpError']); } - $handler->setConfig($config)->init(); + $handler->setView($adminView)->setConfig($config)->init(); } return $handler; @@ -174,6 +177,7 @@ public function setupHandlers( $container->extend('errorHandler', function ($handler, $container) { $appConfig = $container['config']; $adminConfig = $container['admin/config']; + $adminView = $container['admin/view']; if ($handler instanceof HandlerInterface) { $config = $handler->createConfig($appConfig['handlers.defaults']); $config->merge($adminConfig['handlers.defaults']); @@ -182,7 +186,7 @@ public function setupHandlers( $config->merge($adminConfig['handlers.error']); } - $handler->setConfig($config)->init(); + $handler->setView($adminView)->setConfig($config)->init(); } return $handler; @@ -199,6 +203,7 @@ public function setupHandlers( $container->extend('maintenanceHandler', function ($handler, $container) { $appConfig = $container['config']; $adminConfig = $container['admin/config']; + $adminView = $container['admin/view']; if ($handler instanceof HandlerInterface) { $config = $handler->createConfig($appConfig['handlers.defaults']); $config->merge($adminConfig['handlers.defaults']); @@ -207,7 +212,7 @@ public function setupHandlers( $config->merge($adminConfig['handlers.maintenance']); } - $handler->setConfig($config)->init(); + $handler->setView($adminView)->setConfig($config)->init(); } return $handler; diff --git a/packages/admin/src/Charcoal/Admin/AdminWidget.php b/packages/admin/src/Charcoal/Admin/AdminWidget.php index 02d15bef2..5fe5fd788 100644 --- a/packages/admin/src/Charcoal/Admin/AdminWidget.php +++ b/packages/admin/src/Charcoal/Admin/AdminWidget.php @@ -469,6 +469,7 @@ protected function setDependencies(Container $container) // Satisfies AdminWidget dependencies $this->setModelFactory($container['model/factory']); + $this->setView($container['admin/view']); } /** diff --git a/packages/admin/src/Charcoal/Admin/Property/AbstractProperty.php b/packages/admin/src/Charcoal/Admin/Property/AbstractProperty.php index 2b03c9f7d..20ddd1685 100644 --- a/packages/admin/src/Charcoal/Admin/Property/AbstractProperty.php +++ b/packages/admin/src/Charcoal/Admin/Property/AbstractProperty.php @@ -530,7 +530,7 @@ protected function setDependencies(Container $container) $this->setTranslator($container['translator']); // Fulfills the ViewableTrait dependencies - $this->setView($container['view']); + $this->setView($container['admin/view']); // Fulfills the DebugAwareTrait dependencies $this->setDebug($container['debug']); diff --git a/packages/admin/src/Charcoal/Admin/Property/Display/StatusDisplay.php b/packages/admin/src/Charcoal/Admin/Property/Display/StatusDisplay.php index 819f09a77..8693de897 100644 --- a/packages/admin/src/Charcoal/Admin/Property/Display/StatusDisplay.php +++ b/packages/admin/src/Charcoal/Admin/Property/Display/StatusDisplay.php @@ -70,7 +70,7 @@ protected function setDependencies(Container $container) parent::setDependencies($container); // Fulfills the ViewableTrait dependencies - $this->setView($container['view']); + $this->setView($container['admin/view']); } /** diff --git a/packages/admin/src/Charcoal/Admin/Route/TemplateRoute.php b/packages/admin/src/Charcoal/Admin/Route/TemplateRoute.php new file mode 100644 index 000000000..33b53cc13 --- /dev/null +++ b/packages/admin/src/Charcoal/Admin/Route/TemplateRoute.php @@ -0,0 +1,26 @@ +config(); + $template = $this->createTemplate($container, $request); + + return $container['admin/view']->render($config['template'], $template); + } +} diff --git a/packages/admin/src/Charcoal/Admin/ServiceProvider/AdminServiceProvider.php b/packages/admin/src/Charcoal/Admin/ServiceProvider/AdminServiceProvider.php index cc9ad9e20..648622165 100644 --- a/packages/admin/src/Charcoal/Admin/ServiceProvider/AdminServiceProvider.php +++ b/packages/admin/src/Charcoal/Admin/ServiceProvider/AdminServiceProvider.php @@ -40,6 +40,7 @@ use Charcoal\View\ViewInterface; // From 'charcoal-admin' use Charcoal\Admin\Config as AdminConfig; +use Charcoal\Admin\Route\TemplateRoute as AdminTemplateRoute; use Charcoal\Admin\Property\PropertyInputInterface; use Charcoal\Admin\Property\PropertyDisplayInterface; use Charcoal\Admin\Service\SelectizeRenderer; @@ -79,6 +80,8 @@ public function register(Container $container) $this->registerFactoryServices($container); $this->registerElfinderServices($container); $this->registerSelectizeServices($container); + $this->registerModelDependencies($container); + $this->registerRouteServices($container); $this->registerMetadataExtensions($container); $this->registerAuthExtensions($container); $this->registerViewExtensions($container); @@ -175,17 +178,17 @@ protected function registerAdminServices(Container $container) } /** - * Overwrite view instance. + * The admin view instance. * * @param GenericView $view The view instance. * @param Container $container A container instance. * @return ViewInterface */ - $container->extend('view', function (GenericView $view, Container $container): ViewInterface { + $container['admin/view'] = function (Container $container): ViewInterface { return new GenericView([ 'engine' => $container['view/engine/mustache'] ]); - }); + }; /** * Extend view/config. @@ -203,6 +206,31 @@ protected function registerAdminServices(Container $container) }); } + /** + * @param Container $container A Pimple DI container. + * @return void + */ + protected function registerModelDependencies(Container $container) + { + /** + * @param Container $container A Pimple DI container. + * @return array The model dependencies array. + */ + $container->extend('model/dependencies', function (array $modelDependencies, Container $container) { + $modelDependencies['view'] = $container['admin/view']; + return $modelDependencies; + }); + } + + /** + * @param Container $container A service container. + * @return void + */ + protected function registerRouteServices(Container $container) + { + $container['route/controller/template/class'] = AdminTemplateRoute::class; + } + /** * Registers metadata extensions. * @@ -468,7 +496,7 @@ protected function registerSelectizeServices(Container $container) 'logger' => $container['logger'], 'translator' => $container['translator'], 'template_factory' => $container['template/factory'], - 'view' => $container['view'] + 'view' => $container['admin/view'] ]); }; } @@ -539,7 +567,7 @@ protected function registerFactoryServices(Container $container) 'arguments' => [[ 'container' => $container, 'logger' => $container['logger'], - 'view' => $container['view'], + 'view' => $container['admin/view'], 'layout_builder' => $container['layout/builder'] ]], 'resolver_options' => [ diff --git a/packages/admin/src/Charcoal/Admin/Widget/FormGroup/NestedWidgetFormGroup.php b/packages/admin/src/Charcoal/Admin/Widget/FormGroup/NestedWidgetFormGroup.php index 00a71b994..64fd4ab58 100644 --- a/packages/admin/src/Charcoal/Admin/Widget/FormGroup/NestedWidgetFormGroup.php +++ b/packages/admin/src/Charcoal/Admin/Widget/FormGroup/NestedWidgetFormGroup.php @@ -161,7 +161,7 @@ protected function setDependencies(Container $container) $this->setWidgetFactory($container['widget/factory']); // Satisfies Charcoal\View\ViewableInterface dependencies - $this->setView($container['view']); + $this->setView($container['admin/view']); } /** diff --git a/packages/admin/src/Charcoal/Admin/Widget/FormGroupWidget.php b/packages/admin/src/Charcoal/Admin/Widget/FormGroupWidget.php index 22be8741b..4dcd18781 100644 --- a/packages/admin/src/Charcoal/Admin/Widget/FormGroupWidget.php +++ b/packages/admin/src/Charcoal/Admin/Widget/FormGroupWidget.php @@ -336,7 +336,7 @@ protected function setDependencies(Container $container) $this->setFormInputBuilder($container['form/input/builder']); // Satisfies ViewableInterface dependencies - $this->setView($container['view']); + $this->setView($container['admin/view']); // Satisfies LayoutAwareInterface dependencies $this->setLayoutBuilder($container['layout/builder']); diff --git a/packages/admin/src/Charcoal/Admin/Widget/FormPropertyWidget.php b/packages/admin/src/Charcoal/Admin/Widget/FormPropertyWidget.php index e690ff3f1..2ac78a75f 100644 --- a/packages/admin/src/Charcoal/Admin/Widget/FormPropertyWidget.php +++ b/packages/admin/src/Charcoal/Admin/Widget/FormPropertyWidget.php @@ -1163,7 +1163,6 @@ protected function setDependencies(Container $container) { parent::setDependencies($container); - $this->setView($container['view']); $this->setPropertyFactory($container['property/factory']); $this->setPropertyInputFactory($container['property/input/factory']); $this->setPropertyDisplayFactory($container['property/display/factory']); diff --git a/packages/admin/src/Charcoal/Admin/Widget/TableWidget.php b/packages/admin/src/Charcoal/Admin/Widget/TableWidget.php index ef0a59fcb..3e3128c9f 100644 --- a/packages/admin/src/Charcoal/Admin/Widget/TableWidget.php +++ b/packages/admin/src/Charcoal/Admin/Widget/TableWidget.php @@ -1046,7 +1046,6 @@ protected function setDependencies(Container $container) // Satisfies HttpAwareTrait dependencies $this->setHttpRequest($container['request']); - $this->setView($container['view']); $this->setCollectionLoader($container['model/collection/loader']); $this->setWidgetFactory($container['widget/factory']); $this->setPropertyFactory($container['property/factory']); diff --git a/packages/admin/tests/Charcoal/Admin/Service/ExporterTest.php b/packages/admin/tests/Charcoal/Admin/Service/ExporterTest.php index 49551abe9..b1a428920 100644 --- a/packages/admin/tests/Charcoal/Admin/Service/ExporterTest.php +++ b/packages/admin/tests/Charcoal/Admin/Service/ExporterTest.php @@ -73,7 +73,7 @@ protected function container() $containerProvider->registerModelServiceProvider($container); $containerProvider->registerTranslatorServiceProvider($container); - $container['view'] = $this->createMock('\Charcoal\View\ViewInterface'); + $container['admin/view'] = $this->createMock('\Charcoal\View\ViewInterface'); $this->container = $container; } diff --git a/packages/admin/tests/Charcoal/Admin/Widget/TableWidgetTest.php b/packages/admin/tests/Charcoal/Admin/Widget/TableWidgetTest.php index a69847d83..98987b5cf 100644 --- a/packages/admin/tests/Charcoal/Admin/Widget/TableWidgetTest.php +++ b/packages/admin/tests/Charcoal/Admin/Widget/TableWidgetTest.php @@ -130,7 +130,7 @@ protected function container() $containerProvider->registerWidgetFactory($container); $containerProvider->registerPropertyDisplayFactory($container); - $container['view'] = $this->createMock('\Charcoal\View\ViewInterface'); + $container['admin/view'] = $this->createMock('\Charcoal\View\ViewInterface'); $this->container = $container; } diff --git a/packages/attachment/src/Charcoal/Admin/Widget/FormGroup/AttachmentFormGroup.php b/packages/attachment/src/Charcoal/Admin/Widget/FormGroup/AttachmentFormGroup.php index 3f32f6cf7..b9e091448 100644 --- a/packages/attachment/src/Charcoal/Admin/Widget/FormGroup/AttachmentFormGroup.php +++ b/packages/attachment/src/Charcoal/Admin/Widget/FormGroup/AttachmentFormGroup.php @@ -179,7 +179,7 @@ protected function setDependencies(Container $container) } // Satisfies Charcoal\View\ViewableInterface dependencies - $this->setView($container['view']); + $this->setView($container['admin/view']); } /** diff --git a/packages/property/src/Charcoal/Property/SpriteProperty.php b/packages/property/src/Charcoal/Property/SpriteProperty.php index 86687c24a..9d5a6b312 100644 --- a/packages/property/src/Charcoal/Property/SpriteProperty.php +++ b/packages/property/src/Charcoal/Property/SpriteProperty.php @@ -203,7 +203,6 @@ public function buildChoicesFromSprite() public function displayVal($val, array $options = []) { $val = parent::displayVal($val, $options); - if ($val !== '') { $label = $this->translator()->trans('Selected sprite icon "%icon%"', [ '%icon%' => $val, @@ -248,7 +247,7 @@ protected function setDependencies(Container $container) { parent::setDependencies($container); - $this->view = $container['view']; + $this->view = $container['admin/view']; } /** From ee640df3560b4ab2be5f1d08dcefe3ba36bbb726 Mon Sep 17 00:00:00 2001 From: Xavier Date: Mon, 31 Oct 2022 11:19:52 -0400 Subject: [PATCH 02/15] refactor(admin): remove useless ViewInterface and ViewTrait on some property display --- .../Charcoal/Admin/Property/Display/MessageDisplay.php | 8 +------- .../Charcoal/Admin/Property/Display/StatusDisplay.php | 10 +--------- 2 files changed, 2 insertions(+), 16 deletions(-) diff --git a/packages/admin/src/Charcoal/Admin/Property/Display/MessageDisplay.php b/packages/admin/src/Charcoal/Admin/Property/Display/MessageDisplay.php index 2954d1480..1c0df73d4 100644 --- a/packages/admin/src/Charcoal/Admin/Property/Display/MessageDisplay.php +++ b/packages/admin/src/Charcoal/Admin/Property/Display/MessageDisplay.php @@ -4,9 +4,6 @@ // From Pimple use Pimple\Container; -// From 'charcoal-view' -use Charcoal\View\ViewableInterface; -use Charcoal\View\ViewableTrait; // From 'charcoal-translator' use Charcoal\Translator\Translation; // From 'charcoal-admin' @@ -32,11 +29,8 @@ * } * ``` */ -class MessageDisplay extends AbstractPropertyDisplay implements - ViewableInterface +class MessageDisplay extends AbstractPropertyDisplay { - use ViewableTrait; - /** * @var Translation|null */ diff --git a/packages/admin/src/Charcoal/Admin/Property/Display/StatusDisplay.php b/packages/admin/src/Charcoal/Admin/Property/Display/StatusDisplay.php index 8693de897..094b54f1a 100644 --- a/packages/admin/src/Charcoal/Admin/Property/Display/StatusDisplay.php +++ b/packages/admin/src/Charcoal/Admin/Property/Display/StatusDisplay.php @@ -4,9 +4,6 @@ // from 'charcoal-admin' use Charcoal\Admin\Property\AbstractPropertyDisplay; -// from 'charcoal-view' -use Charcoal\View\ViewableInterface; -use Charcoal\View\ViewableTrait; // from 'pimple' use Pimple\Container; use UnexpectedValueException; @@ -16,10 +13,8 @@ * * The default display for most properties; only output {@see AbstractProperty::displayVal()}. */ -class StatusDisplay extends AbstractPropertyDisplay implements ViewableInterface +class StatusDisplay extends AbstractPropertyDisplay { - use ViewableTrait; - public const STATE_PRIMARY = 'primary'; public const STATE_SUCCESS = 'success'; public const STATE_INFO = 'info'; @@ -68,9 +63,6 @@ class StatusDisplay extends AbstractPropertyDisplay implements ViewableInterface protected function setDependencies(Container $container) { parent::setDependencies($container); - - // Fulfills the ViewableTrait dependencies - $this->setView($container['admin/view']); } /** From dc5213c5a5bb8ca2f684e0483e7a0fc1204a6748 Mon Sep 17 00:00:00 2001 From: Xavier Date: Tue, 1 Nov 2022 09:19:43 -0400 Subject: [PATCH 03/15] refactor(admin): replace email/factory for admin module Replace email/factory for admin/email/factory in admin module in order to force using mustache view engine for emails. Offer the possibilty to keep using the default view engine (ie front) even for sending email from backend. --- .../Action/Account/LostPasswordAction.php | 2 +- .../AbstractNotificationScript.php | 2 +- .../ServiceProvider/AdminServiceProvider.php | 27 +++++++++++++++++++ 3 files changed, 29 insertions(+), 2 deletions(-) diff --git a/packages/admin/src/Charcoal/Admin/Action/Account/LostPasswordAction.php b/packages/admin/src/Charcoal/Admin/Action/Account/LostPasswordAction.php index 2b4d5dd38..fd572be72 100644 --- a/packages/admin/src/Charcoal/Admin/Action/Account/LostPasswordAction.php +++ b/packages/admin/src/Charcoal/Admin/Action/Account/LostPasswordAction.php @@ -180,7 +180,7 @@ public function results() protected function setDependencies(Container $container) { parent::setDependencies($container); - $this->setEmailFactory($container['email/factory']); + $this->setEmailFactory($container['admin/email/factory']); } /** diff --git a/packages/admin/src/Charcoal/Admin/Script/Notification/AbstractNotificationScript.php b/packages/admin/src/Charcoal/Admin/Script/Notification/AbstractNotificationScript.php index ea561f452..6ce95423b 100644 --- a/packages/admin/src/Charcoal/Admin/Script/Notification/AbstractNotificationScript.php +++ b/packages/admin/src/Charcoal/Admin/Script/Notification/AbstractNotificationScript.php @@ -106,7 +106,7 @@ protected function setDependencies(Container $container) parent::setDependencies($container); $this->setNotificationFactory($container['model/factory']); $this->setRevisionFactory($container['model/factory']); - $this->emailFactory = $container['email/factory']; + $this->emailFactory = $container['admin/email/factory']; $this->userFactory = $container['model/factory']; $this->objectFactory = $container['model/factory']; } diff --git a/packages/admin/src/Charcoal/Admin/ServiceProvider/AdminServiceProvider.php b/packages/admin/src/Charcoal/Admin/ServiceProvider/AdminServiceProvider.php index 648622165..c9a454ed9 100644 --- a/packages/admin/src/Charcoal/Admin/ServiceProvider/AdminServiceProvider.php +++ b/packages/admin/src/Charcoal/Admin/ServiceProvider/AdminServiceProvider.php @@ -20,8 +20,12 @@ // From 'charcoal-config' use Charcoal\Config\ConfigInterface; use Charcoal\Config\GenericConfig as Config; +// From email +use Charcoal\Email\Email; +use Charcoal\Email\EmailInterface; // From 'charcoal-factory' use Charcoal\Factory\FactoryInterface; +use Charcoal\Factory\GenericFactory; // From 'charcoal-core' use Charcoal\Model\Service\MetadataConfig; // From 'charcoal-ui' @@ -177,6 +181,29 @@ protected function registerAdminServices(Container $container) }; } + /** + * @param Container $container Pimple DI Container. + * @return FactoryInterface + */ + $container['admin/email/factory'] = function (Container $container): FactoryInterface { + return new GenericFactory([ + 'map' => [ + 'email' => Email::class + ], + 'base_class' => EmailInterface::class, + 'default_class' => Email::class, + 'arguments' => [[ + 'logger' => $container['logger'], + 'config' => $container['email/config'], + 'view' => $container['admin/view'], + 'template_factory' => $container['template/factory'], + 'queue_item_factory' => $container['model/factory'], + 'log_factory' => $container['model/factory'], + 'tracker' => $container['email/tracker'] + ]] + ]); + }; + /** * The admin view instance. * From 5012ecc555ec97dc64503a4e0d1013e566749796 Mon Sep 17 00:00:00 2001 From: Xavier Date: Tue, 1 Nov 2022 09:20:51 -0400 Subject: [PATCH 04/15] refactor(ui): use the admin/view engine for ui module --- packages/ui/src/Charcoal/Ui/Layout/LayoutBuilder.php | 2 +- .../Charcoal/Ui/ServiceProvider/DashboardServiceProvider.php | 2 +- .../src/Charcoal/Ui/ServiceProvider/FormServiceProvider.php | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/ui/src/Charcoal/Ui/Layout/LayoutBuilder.php b/packages/ui/src/Charcoal/Ui/Layout/LayoutBuilder.php index 5740a31a3..69d33636b 100644 --- a/packages/ui/src/Charcoal/Ui/Layout/LayoutBuilder.php +++ b/packages/ui/src/Charcoal/Ui/Layout/LayoutBuilder.php @@ -58,7 +58,7 @@ public function build($options) $obj = $this->factory->create($objType, [ 'logger' => $container['logger'], - 'view' => $container['view'] + 'view' => $container['admin/view'] ]); $obj->setData($options); diff --git a/packages/ui/src/Charcoal/Ui/ServiceProvider/DashboardServiceProvider.php b/packages/ui/src/Charcoal/Ui/ServiceProvider/DashboardServiceProvider.php index 24b9443fe..cc625b541 100644 --- a/packages/ui/src/Charcoal/Ui/ServiceProvider/DashboardServiceProvider.php +++ b/packages/ui/src/Charcoal/Ui/ServiceProvider/DashboardServiceProvider.php @@ -41,7 +41,7 @@ private function registerDashboardServices(Container $container) [ 'container' => $container, 'logger' => $container['logger'], - 'view' => $container['view'], + 'view' => $container['admin/view'], 'widget_builder' => $container['widget/builder'], 'layout_builder' => $container['layout/builder'], ], diff --git a/packages/ui/src/Charcoal/Ui/ServiceProvider/FormServiceProvider.php b/packages/ui/src/Charcoal/Ui/ServiceProvider/FormServiceProvider.php index 1498d42bf..e61c75a43 100644 --- a/packages/ui/src/Charcoal/Ui/ServiceProvider/FormServiceProvider.php +++ b/packages/ui/src/Charcoal/Ui/ServiceProvider/FormServiceProvider.php @@ -52,7 +52,7 @@ public function registerFormServices(Container $container) [ 'container' => $container, 'logger' => $container['logger'], - 'view' => $container['view'], + 'view' => $container['admin/view'], 'layout_builder' => $container['layout/builder'], 'form_group_factory' => $container['form/group/factory'], ], @@ -89,7 +89,7 @@ public function registerFormGroupServices(Container $container) [ 'container' => $container, 'logger' => $container['logger'], - 'view' => $container['view'], + 'view' => $container['admin/view'], 'layout_builder' => $container['layout/builder'], 'form_input_builder' => $container['form/input/builder'], ], From a3c7f46f75f929ba784ce1f0b86509d58bcab60b Mon Sep 17 00:00:00 2001 From: Xavier Date: Tue, 1 Nov 2022 15:26:24 -0400 Subject: [PATCH 05/15] refactor(email): add email/dependencies container Use an email/dependencies container overwritten in admin module to use specific view engine --- .../ServiceProvider/AdminServiceProvider.php | 13 ++++-------- .../ServiceProvider/EmailServiceProvider.php | 21 ++++++++++++++----- 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/packages/admin/src/Charcoal/Admin/ServiceProvider/AdminServiceProvider.php b/packages/admin/src/Charcoal/Admin/ServiceProvider/AdminServiceProvider.php index c9a454ed9..b147df1ad 100644 --- a/packages/admin/src/Charcoal/Admin/ServiceProvider/AdminServiceProvider.php +++ b/packages/admin/src/Charcoal/Admin/ServiceProvider/AdminServiceProvider.php @@ -186,21 +186,16 @@ protected function registerAdminServices(Container $container) * @return FactoryInterface */ $container['admin/email/factory'] = function (Container $container): FactoryInterface { + $dependencies = $container['email/dependencies']; + $dependencies['view'] = $container['admin/view']; + return new GenericFactory([ 'map' => [ 'email' => Email::class ], 'base_class' => EmailInterface::class, 'default_class' => Email::class, - 'arguments' => [[ - 'logger' => $container['logger'], - 'config' => $container['email/config'], - 'view' => $container['admin/view'], - 'template_factory' => $container['template/factory'], - 'queue_item_factory' => $container['model/factory'], - 'log_factory' => $container['model/factory'], - 'tracker' => $container['email/tracker'] - ]] + 'arguments' => [ $dependencies ], ]); }; diff --git a/packages/email/src/Charcoal/Email/ServiceProvider/EmailServiceProvider.php b/packages/email/src/Charcoal/Email/ServiceProvider/EmailServiceProvider.php index bbafb8c37..0db3420c5 100644 --- a/packages/email/src/Charcoal/Email/ServiceProvider/EmailServiceProvider.php +++ b/packages/email/src/Charcoal/Email/ServiceProvider/EmailServiceProvider.php @@ -66,17 +66,28 @@ public function register(Container $container): void ], 'base_class' => EmailInterface::class, 'default_class' => Email::class, - 'arguments' => [[ + 'arguments' => [ $container['email/dependencies'] ], + ]); + }; + + // The model dependencies might be already set from elsewhere; defines it if not. + if (!isset($container['email/dependencies'])) { + /** + * @param Container $container A Pimple DI container. + * @return array The model dependencies array. + */ + $container['email/dependencies'] = function (Container $container) { + return [ 'logger' => $container['logger'], 'config' => $container['email/config'], 'view' => $container['email/view'], 'template_factory' => $container['template/factory'], 'queue_item_factory' => $container['model/factory'], 'log_factory' => $container['model/factory'], - 'tracker' => $container['email/tracker'] - ]] - ]); - }; + 'tracker' => $container['email/tracker'], + ]; + }; + } /** * @return Parser From a3f6ea4a65d71076c4b3066987d7fa0b65081106 Mon Sep 17 00:00:00 2001 From: Xavier Date: Fri, 4 Nov 2022 15:10:33 -0400 Subject: [PATCH 06/15] Implementation of ViewAggregator. Remove use of admin/view, admin/email/provider and Admin Template Route. Fix the calls of render and renderTemplate in admin section --- .../Action/Account/LostPasswordAction.php | 2 +- .../Admin/Action/Widget/LoadAction.php | 4 +- .../admin/src/Charcoal/Admin/AdminModule.php | 17 ++- .../admin/src/Charcoal/Admin/AdminWidget.php | 2 +- .../Docs/Template/Object/DocTemplate.php | 2 +- .../Admin/Property/AbstractProperty.php | 2 +- .../Admin/Property/Input/ReadonlyInput.php | 2 +- .../Charcoal/Admin/Route/TemplateRoute.php | 26 ---- .../AbstractNotificationScript.php | 2 +- .../Admin/Service/SelectizeRenderer.php | 2 +- .../ServiceProvider/AdminServiceProvider.php | 63 +-------- .../Template/Object/CollectionTemplate.php | 4 +- .../Admin/Template/Object/EditTemplate.php | 2 +- .../Admin/Ui/ActionContainerTrait.php | 2 +- .../Admin/Ui/CollectionContainerTrait.php | 2 +- .../Admin/Ui/NestedWidgetContainerTrait.php | 2 +- .../Admin/Widget/CollectionMapWidget.php | 2 +- .../src/Charcoal/Admin/Widget/DocWidget.php | 4 +- .../FormGroup/NestedWidgetFormGroup.php | 15 +- .../Charcoal/Admin/Widget/FormGroupWidget.php | 15 +- .../Admin/Widget/ObjectFormWidget.php | 4 +- .../src/Charcoal/Admin/Widget/TableWidget.php | 6 +- .../Charcoal/Admin/Service/ExporterTest.php | 2 +- .../Charcoal/Admin/Widget/TableWidgetTest.php | 2 +- .../Widget/FormGroup/AttachmentFormGroup.php | 2 +- .../Traits/AttachmentContainerTrait.php | 1 - .../Traits/ConfigurableAttachmentsTrait.php | 8 +- .../src/Charcoal/Property/SpriteProperty.php | 2 +- .../src/Charcoal/Ui/Layout/LayoutBuilder.php | 2 +- .../DashboardServiceProvider.php | 2 +- .../ServiceProvider/FormServiceProvider.php | 4 +- .../view/src/Charcoal/View/AbstractEngine.php | 2 +- .../view/src/Charcoal/View/AbstractLoader.php | 32 +++-- .../view/src/Charcoal/View/AbstractView.php | 2 +- .../Charcoal/View/Mustache/MustacheLoader.php | 2 +- .../view/src/Charcoal/View/Php/PhpEngine.php | 2 +- .../view/src/Charcoal/View/Php/PhpLoader.php | 2 +- .../src/Charcoal/View/Twig/TwigEngine.php | 28 +++- .../src/Charcoal/View/Twig/TwigLoader.php | 2 +- .../view/src/Charcoal/View/ViewAggregator.php | 131 ++++++++++++++++++ .../src/Charcoal/View/ViewServiceProvider.php | 46 +++++- 41 files changed, 288 insertions(+), 168 deletions(-) delete mode 100644 packages/admin/src/Charcoal/Admin/Route/TemplateRoute.php create mode 100644 packages/view/src/Charcoal/View/ViewAggregator.php diff --git a/packages/admin/src/Charcoal/Admin/Action/Account/LostPasswordAction.php b/packages/admin/src/Charcoal/Admin/Action/Account/LostPasswordAction.php index fd572be72..2b4d5dd38 100644 --- a/packages/admin/src/Charcoal/Admin/Action/Account/LostPasswordAction.php +++ b/packages/admin/src/Charcoal/Admin/Action/Account/LostPasswordAction.php @@ -180,7 +180,7 @@ public function results() protected function setDependencies(Container $container) { parent::setDependencies($container); - $this->setEmailFactory($container['admin/email/factory']); + $this->setEmailFactory($container['email/factory']); } /** diff --git a/packages/admin/src/Charcoal/Admin/Action/Widget/LoadAction.php b/packages/admin/src/Charcoal/Admin/Action/Widget/LoadAction.php index cded785e7..707f0e160 100644 --- a/packages/admin/src/Charcoal/Admin/Action/Widget/LoadAction.php +++ b/packages/admin/src/Charcoal/Admin/Action/Widget/LoadAction.php @@ -151,7 +151,7 @@ public function run(RequestInterface $request, ResponseInterface $response) $widget->setData($widgetOptions); } - $widgetHtml = $widget->renderTemplate($widget->template()); + $widgetHtml = $widget->render($widget->template()); $sharedJs = $widget->renderTemplate('{{&jsRequirements}}'); $uniqueJs = $widget->renderTemplate('{{&js}}'); $widgetId = $widget->widgetId(); @@ -319,7 +319,7 @@ protected function setDependencies(Container $container) parent::setdependencies($container); $this->setWidgetFactory($container['widget/factory']); - $this->setWidgetView($container['admin/view']); + $this->setWidgetView($container['view']); } diff --git a/packages/admin/src/Charcoal/Admin/AdminModule.php b/packages/admin/src/Charcoal/Admin/AdminModule.php index 018719a1b..20647a98a 100644 --- a/packages/admin/src/Charcoal/Admin/AdminModule.php +++ b/packages/admin/src/Charcoal/Admin/AdminModule.php @@ -10,6 +10,7 @@ use Charcoal\App\Module\AbstractModule; // From 'charcoal-admin' use Charcoal\Admin\ServiceProvider\AdminServiceProvider; +use Charcoal\View\ViewAggregator; /** * Charcoal Administration Module @@ -46,6 +47,12 @@ public function setUp() } $container->register(new AdminServiceProvider()); + /* Last resort solution + if ($container['view'] instanceof ViewAggregator) { + $container['view']->using('mustache'); + } + */ + $module = $this; $container['charcoal/admin/module'] = function () use ($module) { return $module; @@ -105,7 +112,7 @@ public function setupHandlers( $container->extend('notFoundHandler', function ($handler, $container) { $appConfig = $container['config']; $adminConfig = $container['admin/config']; - $adminView = $container['admin/view']; + $adminView = $container['view']; if ($handler instanceof HandlerInterface) { $config = $handler->createConfig($appConfig['handlers.defaults']); $config->merge($adminConfig['handlers.defaults']); @@ -129,7 +136,7 @@ public function setupHandlers( $container->extend('notAllowedHandler', function ($handler, $container) { $appConfig = $container['config']; $adminConfig = $container['admin/config']; - $adminView = $container['admin/view']; + $adminView = $container['view']; if ($handler instanceof HandlerInterface) { $config = $handler->createConfig($appConfig['handlers.defaults']); $config->merge($adminConfig['handlers.defaults']); @@ -153,7 +160,7 @@ public function setupHandlers( $container->extend('phpErrorHandler', function ($handler, $container) { $appConfig = $container['config']; $adminConfig = $container['admin/config']; - $adminView = $container['admin/view']; + $adminView = $container['view']; if ($handler instanceof HandlerInterface) { $config = $handler->createConfig($appConfig['handlers.defaults']); $config->merge($adminConfig['handlers.defaults']); @@ -177,7 +184,7 @@ public function setupHandlers( $container->extend('errorHandler', function ($handler, $container) { $appConfig = $container['config']; $adminConfig = $container['admin/config']; - $adminView = $container['admin/view']; + $adminView = $container['view']; if ($handler instanceof HandlerInterface) { $config = $handler->createConfig($appConfig['handlers.defaults']); $config->merge($adminConfig['handlers.defaults']); @@ -203,7 +210,7 @@ public function setupHandlers( $container->extend('maintenanceHandler', function ($handler, $container) { $appConfig = $container['config']; $adminConfig = $container['admin/config']; - $adminView = $container['admin/view']; + $adminView = $container['view']; if ($handler instanceof HandlerInterface) { $config = $handler->createConfig($appConfig['handlers.defaults']); $config->merge($adminConfig['handlers.defaults']); diff --git a/packages/admin/src/Charcoal/Admin/AdminWidget.php b/packages/admin/src/Charcoal/Admin/AdminWidget.php index 5fe5fd788..8e709c4ae 100644 --- a/packages/admin/src/Charcoal/Admin/AdminWidget.php +++ b/packages/admin/src/Charcoal/Admin/AdminWidget.php @@ -469,7 +469,7 @@ protected function setDependencies(Container $container) // Satisfies AdminWidget dependencies $this->setModelFactory($container['model/factory']); - $this->setView($container['admin/view']); + $this->setView($container['view']); } /** diff --git a/packages/admin/src/Charcoal/Admin/Docs/Template/Object/DocTemplate.php b/packages/admin/src/Charcoal/Admin/Docs/Template/Object/DocTemplate.php index a3f8bdee5..a491e8ddf 100644 --- a/packages/admin/src/Charcoal/Admin/Docs/Template/Object/DocTemplate.php +++ b/packages/admin/src/Charcoal/Admin/Docs/Template/Object/DocTemplate.php @@ -114,7 +114,7 @@ public function title() } if ($this->isObjRenderable($obj)) { - $this->title = $obj->render((string)$objLabel, $obj); + $this->title = $obj->renderTemplate((string)$objLabel, $obj); } else { $this->title = (string)$objLabel; } diff --git a/packages/admin/src/Charcoal/Admin/Property/AbstractProperty.php b/packages/admin/src/Charcoal/Admin/Property/AbstractProperty.php index 20ddd1685..2b03c9f7d 100644 --- a/packages/admin/src/Charcoal/Admin/Property/AbstractProperty.php +++ b/packages/admin/src/Charcoal/Admin/Property/AbstractProperty.php @@ -530,7 +530,7 @@ protected function setDependencies(Container $container) $this->setTranslator($container['translator']); // Fulfills the ViewableTrait dependencies - $this->setView($container['admin/view']); + $this->setView($container['view']); // Fulfills the DebugAwareTrait dependencies $this->setDebug($container['debug']); diff --git a/packages/admin/src/Charcoal/Admin/Property/Input/ReadonlyInput.php b/packages/admin/src/Charcoal/Admin/Property/Input/ReadonlyInput.php index 74b8fa780..2da2d8823 100644 --- a/packages/admin/src/Charcoal/Admin/Property/Input/ReadonlyInput.php +++ b/packages/admin/src/Charcoal/Admin/Property/Input/ReadonlyInput.php @@ -106,7 +106,7 @@ public function displayVal() $display->setData($propertyData); $display->setPropertyVal($propertyValue); - return $this->view()->renderTemplate($displayType, $display); + return $this->view()->render($displayType, $display); } /** diff --git a/packages/admin/src/Charcoal/Admin/Route/TemplateRoute.php b/packages/admin/src/Charcoal/Admin/Route/TemplateRoute.php deleted file mode 100644 index 33b53cc13..000000000 --- a/packages/admin/src/Charcoal/Admin/Route/TemplateRoute.php +++ /dev/null @@ -1,26 +0,0 @@ -config(); - $template = $this->createTemplate($container, $request); - - return $container['admin/view']->render($config['template'], $template); - } -} diff --git a/packages/admin/src/Charcoal/Admin/Script/Notification/AbstractNotificationScript.php b/packages/admin/src/Charcoal/Admin/Script/Notification/AbstractNotificationScript.php index 6ce95423b..ea561f452 100644 --- a/packages/admin/src/Charcoal/Admin/Script/Notification/AbstractNotificationScript.php +++ b/packages/admin/src/Charcoal/Admin/Script/Notification/AbstractNotificationScript.php @@ -106,7 +106,7 @@ protected function setDependencies(Container $container) parent::setDependencies($container); $this->setNotificationFactory($container['model/factory']); $this->setRevisionFactory($container['model/factory']); - $this->emailFactory = $container['admin/email/factory']; + $this->emailFactory = $container['email/factory']; $this->userFactory = $container['model/factory']; $this->objectFactory = $container['model/factory']; } diff --git a/packages/admin/src/Charcoal/Admin/Service/SelectizeRenderer.php b/packages/admin/src/Charcoal/Admin/Service/SelectizeRenderer.php index 310cc51a1..24d8b15e4 100644 --- a/packages/admin/src/Charcoal/Admin/Service/SelectizeRenderer.php +++ b/packages/admin/src/Charcoal/Admin/Service/SelectizeRenderer.php @@ -123,6 +123,6 @@ public function renderTemplate($templateIdent, $context, $controllerIdent = null $template = $context; } - return $this->view->render($templateIdent, $template); + return $this->view->renderTemplate($templateIdent, $template); } } diff --git a/packages/admin/src/Charcoal/Admin/ServiceProvider/AdminServiceProvider.php b/packages/admin/src/Charcoal/Admin/ServiceProvider/AdminServiceProvider.php index b147df1ad..9b663193c 100644 --- a/packages/admin/src/Charcoal/Admin/ServiceProvider/AdminServiceProvider.php +++ b/packages/admin/src/Charcoal/Admin/ServiceProvider/AdminServiceProvider.php @@ -44,7 +44,6 @@ use Charcoal\View\ViewInterface; // From 'charcoal-admin' use Charcoal\Admin\Config as AdminConfig; -use Charcoal\Admin\Route\TemplateRoute as AdminTemplateRoute; use Charcoal\Admin\Property\PropertyInputInterface; use Charcoal\Admin\Property\PropertyDisplayInterface; use Charcoal\Admin\Service\SelectizeRenderer; @@ -84,8 +83,6 @@ public function register(Container $container) $this->registerFactoryServices($container); $this->registerElfinderServices($container); $this->registerSelectizeServices($container); - $this->registerModelDependencies($container); - $this->registerRouteServices($container); $this->registerMetadataExtensions($container); $this->registerAuthExtensions($container); $this->registerViewExtensions($container); @@ -181,37 +178,6 @@ protected function registerAdminServices(Container $container) }; } - /** - * @param Container $container Pimple DI Container. - * @return FactoryInterface - */ - $container['admin/email/factory'] = function (Container $container): FactoryInterface { - $dependencies = $container['email/dependencies']; - $dependencies['view'] = $container['admin/view']; - - return new GenericFactory([ - 'map' => [ - 'email' => Email::class - ], - 'base_class' => EmailInterface::class, - 'default_class' => Email::class, - 'arguments' => [ $dependencies ], - ]); - }; - - /** - * The admin view instance. - * - * @param GenericView $view The view instance. - * @param Container $container A container instance. - * @return ViewInterface - */ - $container['admin/view'] = function (Container $container): ViewInterface { - return new GenericView([ - 'engine' => $container['view/engine/mustache'] - ]); - }; - /** * Extend view/config. * @@ -228,31 +194,6 @@ protected function registerAdminServices(Container $container) }); } - /** - * @param Container $container A Pimple DI container. - * @return void - */ - protected function registerModelDependencies(Container $container) - { - /** - * @param Container $container A Pimple DI container. - * @return array The model dependencies array. - */ - $container->extend('model/dependencies', function (array $modelDependencies, Container $container) { - $modelDependencies['view'] = $container['admin/view']; - return $modelDependencies; - }); - } - - /** - * @param Container $container A service container. - * @return void - */ - protected function registerRouteServices(Container $container) - { - $container['route/controller/template/class'] = AdminTemplateRoute::class; - } - /** * Registers metadata extensions. * @@ -518,7 +459,7 @@ protected function registerSelectizeServices(Container $container) 'logger' => $container['logger'], 'translator' => $container['translator'], 'template_factory' => $container['template/factory'], - 'view' => $container['admin/view'] + 'view' => $container['view'] ]); }; } @@ -589,7 +530,7 @@ protected function registerFactoryServices(Container $container) 'arguments' => [[ 'container' => $container, 'logger' => $container['logger'], - 'view' => $container['admin/view'], + 'view' => $container['view'], 'layout_builder' => $container['layout/builder'] ]], 'resolver_options' => [ diff --git a/packages/admin/src/Charcoal/Admin/Template/Object/CollectionTemplate.php b/packages/admin/src/Charcoal/Admin/Template/Object/CollectionTemplate.php index d7e213814..c4bbd52a4 100644 --- a/packages/admin/src/Charcoal/Admin/Template/Object/CollectionTemplate.php +++ b/packages/admin/src/Charcoal/Admin/Template/Object/CollectionTemplate.php @@ -164,7 +164,7 @@ public function title() } if ($listIdent && $hasView) { - $listIdent = $model->render($listIdent); + $listIdent = $model->renderTemplate($listIdent); } if (isset($adminMetadata['lists'][$listIdent]['label'])) { @@ -191,7 +191,7 @@ public function title() } if ($hasView) { - $this->title = $model->render((string)$objLabel, $model); + $this->title = $model->renderTemplate((string)$objLabel); } else { $this->title = (string)$objLabel; } diff --git a/packages/admin/src/Charcoal/Admin/Template/Object/EditTemplate.php b/packages/admin/src/Charcoal/Admin/Template/Object/EditTemplate.php index 9aedc36f5..c6c2a8f03 100644 --- a/packages/admin/src/Charcoal/Admin/Template/Object/EditTemplate.php +++ b/packages/admin/src/Charcoal/Admin/Template/Object/EditTemplate.php @@ -212,7 +212,7 @@ protected function renderTitle($title) { $obj = $this->obj(); if ($this->isObjRenderable($obj)) { - return $obj->render((string)$title, $obj); + return $obj->renderTemplate((string)$title, $obj); } else { return (string)$title; } diff --git a/packages/admin/src/Charcoal/Admin/Ui/ActionContainerTrait.php b/packages/admin/src/Charcoal/Admin/Ui/ActionContainerTrait.php index b0fa09721..b6f1a9c37 100644 --- a/packages/admin/src/Charcoal/Admin/Ui/ActionContainerTrait.php +++ b/packages/admin/src/Charcoal/Admin/Ui/ActionContainerTrait.php @@ -228,7 +228,7 @@ protected function parseActionItem($action, $ident, $renderer = false) } if (isset($action['extraTemplate'])) { - $action['extraTemplate'] = $this->render($action['extraTemplate']); + $action['extraTemplate'] = $this->renderTemplate($action['extraTemplate']); } if (isset($action['dataAttributes']) && is_array($action['dataAttributes'])) { diff --git a/packages/admin/src/Charcoal/Admin/Ui/CollectionContainerTrait.php b/packages/admin/src/Charcoal/Admin/Ui/CollectionContainerTrait.php index f423d22ad..cab7773fd 100644 --- a/packages/admin/src/Charcoal/Admin/Ui/CollectionContainerTrait.php +++ b/packages/admin/src/Charcoal/Admin/Ui/CollectionContainerTrait.php @@ -830,7 +830,7 @@ public function objectRows() $displayType = $this->display->displayType(); $this->display->setPropertyVal($object->propertyValue($propertyIdent)); - $propertyValue = $this->view()->renderTemplate($displayType, $this->display); + $propertyValue = $this->view()->render($displayType, $this->display); $cell = $this->parsePropertyCell($object, $property, $propertyValue); $objectProperties[] = $cell; diff --git a/packages/admin/src/Charcoal/Admin/Ui/NestedWidgetContainerTrait.php b/packages/admin/src/Charcoal/Admin/Ui/NestedWidgetContainerTrait.php index f2b41e989..d30b670be 100644 --- a/packages/admin/src/Charcoal/Admin/Ui/NestedWidgetContainerTrait.php +++ b/packages/admin/src/Charcoal/Admin/Ui/NestedWidgetContainerTrait.php @@ -284,7 +284,7 @@ protected function renderData($data) // Make sure there's an "out" if ($obj instanceof ViewableInterface && ($obj->view() instanceof ViewInterface)) { - $data = $obj->view()->render($data, $obj->viewController()); + $data = $obj->view()->renderTemplate($data, $obj->viewController()); } else { $data = preg_replace_callback('~\{\{\s*(.*?)\s*\}\}~i', [ $this, 'parseDataToken' ], $data); } diff --git a/packages/admin/src/Charcoal/Admin/Widget/CollectionMapWidget.php b/packages/admin/src/Charcoal/Admin/Widget/CollectionMapWidget.php index a8232e52f..404a15a30 100644 --- a/packages/admin/src/Charcoal/Admin/Widget/CollectionMapWidget.php +++ b/packages/admin/src/Charcoal/Admin/Widget/CollectionMapWidget.php @@ -327,7 +327,7 @@ public function dataFromObject() } if ($collectionIdent && $this->isObjRenderable($proto)) { - $collectionIdent = $proto->render($collectionIdent); + $collectionIdent = $proto->renderTemplate($collectionIdent); } if (!$collectionIdent) { diff --git a/packages/admin/src/Charcoal/Admin/Widget/DocWidget.php b/packages/admin/src/Charcoal/Admin/Widget/DocWidget.php index 84a5aca4d..903dd6181 100644 --- a/packages/admin/src/Charcoal/Admin/Widget/DocWidget.php +++ b/packages/admin/src/Charcoal/Admin/Widget/DocWidget.php @@ -275,7 +275,7 @@ public function setNextUrl($url) $obj = $this->obj(); if ($obj && $this->isObjRenderable($obj)) { - $url = $obj->render($url); + $url = $obj->renderTemplate($url); } $this->nextUrl = $url; @@ -572,7 +572,7 @@ protected function dataFromObject() } if ($formIdent && $this->isObjRenderable($obj)) { - $formIdent = $obj->render($formIdent); + $formIdent = $obj->renderTemplate($formIdent); } if (isset($adminMetadata['forms'][$formIdent])) { diff --git a/packages/admin/src/Charcoal/Admin/Widget/FormGroup/NestedWidgetFormGroup.php b/packages/admin/src/Charcoal/Admin/Widget/FormGroup/NestedWidgetFormGroup.php index 64fd4ab58..13fd331ce 100644 --- a/packages/admin/src/Charcoal/Admin/Widget/FormGroup/NestedWidgetFormGroup.php +++ b/packages/admin/src/Charcoal/Admin/Widget/FormGroup/NestedWidgetFormGroup.php @@ -116,17 +116,16 @@ public function setWidgetId($widgetId) /** * @return Translation|string|null */ - public function description() + public function setDescription($description) { - return $this->renderTemplate((string)parent::description()); + parent::setDescription($this->renderTemplate($description)); + return $this; } - /** - * @return Translation|string|null - */ - public function notes() + public function setNotes($notes) { - return $this->renderTemplate((string)parent::notes()); + parent::setNotes($this->renderTemplate($notes)); + return $this; } /** @@ -161,7 +160,7 @@ protected function setDependencies(Container $container) $this->setWidgetFactory($container['widget/factory']); // Satisfies Charcoal\View\ViewableInterface dependencies - $this->setView($container['admin/view']); + $this->setView($container['view']); } /** diff --git a/packages/admin/src/Charcoal/Admin/Widget/FormGroupWidget.php b/packages/admin/src/Charcoal/Admin/Widget/FormGroupWidget.php index 4dcd18781..1d3065c20 100644 --- a/packages/admin/src/Charcoal/Admin/Widget/FormGroupWidget.php +++ b/packages/admin/src/Charcoal/Admin/Widget/FormGroupWidget.php @@ -291,17 +291,16 @@ public function locale() /** * @return Translation|string|null */ - public function description() + public function setDescription($description) { - return $this->renderTemplate((string)parent::description()); + parent::setDescription($this->renderTemplate($description)); + return $this; } - /** - * @return Translation|string|null - */ - public function notes() + public function setNotes($notes) { - return $this->renderTemplate((string)parent::notes()); + parent::setNotes($this->renderTemplate($notes)); + return $this; } /** @@ -336,7 +335,7 @@ protected function setDependencies(Container $container) $this->setFormInputBuilder($container['form/input/builder']); // Satisfies ViewableInterface dependencies - $this->setView($container['admin/view']); + $this->setView($container['view']); // Satisfies LayoutAwareInterface dependencies $this->setLayoutBuilder($container['layout/builder']); diff --git a/packages/admin/src/Charcoal/Admin/Widget/ObjectFormWidget.php b/packages/admin/src/Charcoal/Admin/Widget/ObjectFormWidget.php index a76dd8068..fa756d60a 100644 --- a/packages/admin/src/Charcoal/Admin/Widget/ObjectFormWidget.php +++ b/packages/admin/src/Charcoal/Admin/Widget/ObjectFormWidget.php @@ -157,7 +157,7 @@ public function setNextUrl($url) $obj = $this->obj(); if ($obj && $this->isObjRenderable($obj)) { - $url = $obj->render($url); + $url = $obj->renderTemplate($url); } $this->nextUrl = $url; @@ -506,7 +506,7 @@ protected function dataFromObject() } if ($formIdent && $this->isObjRenderable($obj)) { - $formIdent = $obj->render($formIdent); + $formIdent = $obj->renderTemplate($formIdent); } if (isset($adminMetadata['forms'][$formIdent])) { diff --git a/packages/admin/src/Charcoal/Admin/Widget/TableWidget.php b/packages/admin/src/Charcoal/Admin/Widget/TableWidget.php index 3e3128c9f..f694492dc 100644 --- a/packages/admin/src/Charcoal/Admin/Widget/TableWidget.php +++ b/packages/admin/src/Charcoal/Admin/Widget/TableWidget.php @@ -253,7 +253,7 @@ public function dataFromObject() } if ($collectionIdent && $this->isObjRenderable($proto)) { - $collectionIdent = $proto->render($collectionIdent); + $collectionIdent = $proto->renderTemplate($collectionIdent); } if (!$collectionIdent) { @@ -880,7 +880,7 @@ public function objectEditUrl() $url = 'object/edit?main_menu={{ main_menu }}&obj_type=' . $this->objType(); if ($this->isObjRenderable($model)) { - $url = $model->render((string)$url); + $url = $model->renderTemplate((string)$url); } else { $url = preg_replace('~{{\s*id\s*}}~', $this->currentObjId, $url); } @@ -901,7 +901,7 @@ public function objectCreateUrl() if (isset($action['url'])) { $model = $this->proto(); if ($this->isObjRenderable($model)) { - $action['url'] = $model->render((string)$action['url']); + $action['url'] = $model->renderTemplate((string)$action['url']); } else { $action['url'] = preg_replace('~{{\s*id\s*}}~', $this->currentObjId, $action['url']); } diff --git a/packages/admin/tests/Charcoal/Admin/Service/ExporterTest.php b/packages/admin/tests/Charcoal/Admin/Service/ExporterTest.php index b1a428920..49551abe9 100644 --- a/packages/admin/tests/Charcoal/Admin/Service/ExporterTest.php +++ b/packages/admin/tests/Charcoal/Admin/Service/ExporterTest.php @@ -73,7 +73,7 @@ protected function container() $containerProvider->registerModelServiceProvider($container); $containerProvider->registerTranslatorServiceProvider($container); - $container['admin/view'] = $this->createMock('\Charcoal\View\ViewInterface'); + $container['view'] = $this->createMock('\Charcoal\View\ViewInterface'); $this->container = $container; } diff --git a/packages/admin/tests/Charcoal/Admin/Widget/TableWidgetTest.php b/packages/admin/tests/Charcoal/Admin/Widget/TableWidgetTest.php index 98987b5cf..a69847d83 100644 --- a/packages/admin/tests/Charcoal/Admin/Widget/TableWidgetTest.php +++ b/packages/admin/tests/Charcoal/Admin/Widget/TableWidgetTest.php @@ -130,7 +130,7 @@ protected function container() $containerProvider->registerWidgetFactory($container); $containerProvider->registerPropertyDisplayFactory($container); - $container['admin/view'] = $this->createMock('\Charcoal\View\ViewInterface'); + $container['view'] = $this->createMock('\Charcoal\View\ViewInterface'); $this->container = $container; } diff --git a/packages/attachment/src/Charcoal/Admin/Widget/FormGroup/AttachmentFormGroup.php b/packages/attachment/src/Charcoal/Admin/Widget/FormGroup/AttachmentFormGroup.php index b9e091448..3f32f6cf7 100644 --- a/packages/attachment/src/Charcoal/Admin/Widget/FormGroup/AttachmentFormGroup.php +++ b/packages/attachment/src/Charcoal/Admin/Widget/FormGroup/AttachmentFormGroup.php @@ -179,7 +179,7 @@ protected function setDependencies(Container $container) } // Satisfies Charcoal\View\ViewableInterface dependencies - $this->setView($container['admin/view']); + $this->setView($container['view']); } /** diff --git a/packages/attachment/src/Charcoal/Attachment/Traits/AttachmentContainerTrait.php b/packages/attachment/src/Charcoal/Attachment/Traits/AttachmentContainerTrait.php index d3b6250c3..d0eb50070 100644 --- a/packages/attachment/src/Charcoal/Attachment/Traits/AttachmentContainerTrait.php +++ b/packages/attachment/src/Charcoal/Attachment/Traits/AttachmentContainerTrait.php @@ -117,7 +117,6 @@ public function attachmentGroup() if (!is_string($group)) { throw new UnexpectedValueException('The attachment grouping must be a string.'); } - $this->group = $group; } diff --git a/packages/attachment/src/Charcoal/Attachment/Traits/ConfigurableAttachmentsTrait.php b/packages/attachment/src/Charcoal/Attachment/Traits/ConfigurableAttachmentsTrait.php index f5455b41c..853f47fc5 100644 --- a/packages/attachment/src/Charcoal/Attachment/Traits/ConfigurableAttachmentsTrait.php +++ b/packages/attachment/src/Charcoal/Attachment/Traits/ConfigurableAttachmentsTrait.php @@ -120,10 +120,10 @@ private function mergePresetWidget(array $data) if ($this instanceof ObjectContainerInterface) { if ($this->hasObj()) { - $widgetIdent = $this->obj()->render($widgetIdent); + $widgetIdent = $this->obj()->renderTemplate($widgetIdent); } } elseif ($this instanceof ModelInterface) { - $widgetIdent = $this->render($widgetIdent); + $widgetIdent = $this->renderTemplate($widgetIdent); } $presetWidgets = $this->config('widgets'); @@ -160,10 +160,10 @@ private function mergePresetAttachableObjects($data) $groupIdent = $data; if ($this instanceof ObjectContainerInterface) { if ($this->hasObj()) { - $groupIdent = $this->obj()->render($groupIdent); + $groupIdent = $this->obj()->renderTemplate($groupIdent); } } elseif ($this instanceof ModelInterface) { - $groupIdent = $this->render($groupIdent); + $groupIdent = $this->renderTemplate($groupIdent); } $presetGroups = $this->config('groups'); diff --git a/packages/property/src/Charcoal/Property/SpriteProperty.php b/packages/property/src/Charcoal/Property/SpriteProperty.php index 9d5a6b312..2a4f50521 100644 --- a/packages/property/src/Charcoal/Property/SpriteProperty.php +++ b/packages/property/src/Charcoal/Property/SpriteProperty.php @@ -247,7 +247,7 @@ protected function setDependencies(Container $container) { parent::setDependencies($container); - $this->view = $container['admin/view']; + $this->view = $container['view']; } /** diff --git a/packages/ui/src/Charcoal/Ui/Layout/LayoutBuilder.php b/packages/ui/src/Charcoal/Ui/Layout/LayoutBuilder.php index 69d33636b..5740a31a3 100644 --- a/packages/ui/src/Charcoal/Ui/Layout/LayoutBuilder.php +++ b/packages/ui/src/Charcoal/Ui/Layout/LayoutBuilder.php @@ -58,7 +58,7 @@ public function build($options) $obj = $this->factory->create($objType, [ 'logger' => $container['logger'], - 'view' => $container['admin/view'] + 'view' => $container['view'] ]); $obj->setData($options); diff --git a/packages/ui/src/Charcoal/Ui/ServiceProvider/DashboardServiceProvider.php b/packages/ui/src/Charcoal/Ui/ServiceProvider/DashboardServiceProvider.php index cc625b541..24b9443fe 100644 --- a/packages/ui/src/Charcoal/Ui/ServiceProvider/DashboardServiceProvider.php +++ b/packages/ui/src/Charcoal/Ui/ServiceProvider/DashboardServiceProvider.php @@ -41,7 +41,7 @@ private function registerDashboardServices(Container $container) [ 'container' => $container, 'logger' => $container['logger'], - 'view' => $container['admin/view'], + 'view' => $container['view'], 'widget_builder' => $container['widget/builder'], 'layout_builder' => $container['layout/builder'], ], diff --git a/packages/ui/src/Charcoal/Ui/ServiceProvider/FormServiceProvider.php b/packages/ui/src/Charcoal/Ui/ServiceProvider/FormServiceProvider.php index e61c75a43..1498d42bf 100644 --- a/packages/ui/src/Charcoal/Ui/ServiceProvider/FormServiceProvider.php +++ b/packages/ui/src/Charcoal/Ui/ServiceProvider/FormServiceProvider.php @@ -52,7 +52,7 @@ public function registerFormServices(Container $container) [ 'container' => $container, 'logger' => $container['logger'], - 'view' => $container['admin/view'], + 'view' => $container['view'], 'layout_builder' => $container['layout/builder'], 'form_group_factory' => $container['form/group/factory'], ], @@ -89,7 +89,7 @@ public function registerFormGroupServices(Container $container) [ 'container' => $container, 'logger' => $container['logger'], - 'view' => $container['admin/view'], + 'view' => $container['view'], 'layout_builder' => $container['layout/builder'], 'form_input_builder' => $container['form/input/builder'], ], diff --git a/packages/view/src/Charcoal/View/AbstractEngine.php b/packages/view/src/Charcoal/View/AbstractEngine.php index c20bec027..8566f06a8 100644 --- a/packages/view/src/Charcoal/View/AbstractEngine.php +++ b/packages/view/src/Charcoal/View/AbstractEngine.php @@ -118,7 +118,7 @@ protected function cache() /** * @return LoaderInterface */ - protected function loader(): LoaderInterface + public function loader(): LoaderInterface { return $this->loader; } diff --git a/packages/view/src/Charcoal/View/AbstractLoader.php b/packages/view/src/Charcoal/View/AbstractLoader.php index 4e8152872..3685e3e5e 100644 --- a/packages/view/src/Charcoal/View/AbstractLoader.php +++ b/packages/view/src/Charcoal/View/AbstractLoader.php @@ -13,7 +13,7 @@ abstract class AbstractLoader implements LoaderInterface { private string $basePath = ''; private array $paths = []; - private array $dynamicTemplates = []; + private static array $dynamicTemplates = []; /** * The cache of searched template files. @@ -41,9 +41,7 @@ public function __construct(?array $data = null) public function load($ident) { // Handle dynamic template - if (substr($ident, 0, 1) === '$') { - $ident = $this->dynamicTemplate(substr($ident, 1)); - } + $ident = $this->resolveDynamicTemplate($ident); /** * Prevents the loader from passing a proper template through further @@ -61,17 +59,29 @@ public function load($ident) return file_get_contents($file); } + /** + * @param string $ident The template ident to load and render. + * @return string + */ + public function resolveDynamicTemplate($ident): string + { + if (substr($ident, 0, 1) === '$') { + return $this->dynamicTemplate(substr($ident, 1)); + } + return $ident; + } + /** * @param string $varName The name of the variable to get template ident from. * @return string */ public function dynamicTemplate(string $varName): string { - if (!isset($this->dynamicTemplates[$varName])) { + if (!isset(static::$dynamicTemplates[$varName])) { return ''; } - return $this->dynamicTemplates[$varName]; + return static::$dynamicTemplates[$varName]; } /** @@ -87,7 +97,7 @@ public function setDynamicTemplate(string $varName, ?string $templateIdent): voi return; } - $this->dynamicTemplates[$varName] = $templateIdent; + static::$dynamicTemplates[$varName] = $templateIdent; } /** @@ -96,7 +106,7 @@ public function setDynamicTemplate(string $varName, ?string $templateIdent): voi */ public function removeDynamicTemplate(string $varName): void { - unset($this->dynamicTemplates[$varName]); + unset(static::$dynamicTemplates[$varName]); } /** @@ -104,7 +114,7 @@ public function removeDynamicTemplate(string $varName): void */ public function clearDynamicTemplates(): void { - $this->dynamicTemplates = []; + static::$dynamicTemplates = []; } /** @@ -185,7 +195,7 @@ private function resolvePath(string $path): string * @return boolean Returns TRUE if the given value is most likely the template contents * as opposed to a template identifier (file path). */ - protected function isTemplateString(string $ident): bool + public function isTemplateString(string $ident): bool { return strpos($ident, PHP_EOL) !== false; } @@ -198,7 +208,7 @@ protected function isTemplateString(string $ident): bool * @param string $ident The template identifier to load.. * @return string|null The full path + filename of the found template. NULL if nothing was found. */ - protected function findTemplateFile(string $ident): ?string + public function findTemplateFile(string $ident): ?string { $key = hash('md5', $ident); diff --git a/packages/view/src/Charcoal/View/AbstractView.php b/packages/view/src/Charcoal/View/AbstractView.php index 19d9bf7b2..d67a15726 100644 --- a/packages/view/src/Charcoal/View/AbstractView.php +++ b/packages/view/src/Charcoal/View/AbstractView.php @@ -97,7 +97,7 @@ protected function engine(): EngineInterface * @param EngineInterface $engine The rendering engine. * @return void */ - private function setEngine(EngineInterface $engine): void + protected function setEngine(EngineInterface $engine): void { $this->engine = $engine; } diff --git a/packages/view/src/Charcoal/View/Mustache/MustacheLoader.php b/packages/view/src/Charcoal/View/Mustache/MustacheLoader.php index b2a4ead17..983cfad97 100644 --- a/packages/view/src/Charcoal/View/Mustache/MustacheLoader.php +++ b/packages/view/src/Charcoal/View/Mustache/MustacheLoader.php @@ -29,7 +29,7 @@ class MustacheLoader extends AbstractLoader implements * @param string $ident The template being evaluated. * @return boolean */ - protected function isTemplateString(string $ident): bool + public function isTemplateString(string $ident): bool { return strpos($ident, '{{') !== false || parent::isTemplateString($ident); } diff --git a/packages/view/src/Charcoal/View/Php/PhpEngine.php b/packages/view/src/Charcoal/View/Php/PhpEngine.php index 15fab1eb0..263a0eeea 100644 --- a/packages/view/src/Charcoal/View/Php/PhpEngine.php +++ b/packages/view/src/Charcoal/View/Php/PhpEngine.php @@ -27,7 +27,7 @@ public function type(): string */ public function renderTemplate(string $templateString, $context): string { - $arrayContext = json_decode(json_encode($context), true); + $arrayContext = json_decode(json_encode($context, JSON_THROW_ON_ERROR), true); // Prevents leaking global variable by forcing anonymous scope $render = function ($templateString, array $context) { extract($context); diff --git a/packages/view/src/Charcoal/View/Php/PhpLoader.php b/packages/view/src/Charcoal/View/Php/PhpLoader.php index 13b71a756..fe912d978 100644 --- a/packages/view/src/Charcoal/View/Php/PhpLoader.php +++ b/packages/view/src/Charcoal/View/Php/PhpLoader.php @@ -25,7 +25,7 @@ class PhpLoader extends AbstractLoader implements LoaderInterface * @param string $ident The template being evaluated. * @return boolean */ - protected function isTemplateString(string $ident): bool + public function isTemplateString(string $ident): bool { return strpos($ident, 'twig()->render($templateIdent, $arrayContext); + try { + $arrayContext = json_decode(json_encode($context, JSON_THROW_ON_ERROR), true); + return $this->twig()->render($templateIdent, $arrayContext); + } catch (JsonException $e) { + throw new Exception( + sprintf("Twig cannot render \"%s\", Error : \"%s\".", $templateIdent, $e->getMessage()), + $e->getCode(), + $e + ); + } } /** @@ -173,9 +183,17 @@ public function render(string $templateIdent, $context): string */ public function renderTemplate(string $templateString, $context): string { - $template = $this->twig()->createTemplate($templateString); - $arrayContext = json_decode(json_encode($context), true); - return $template->render($arrayContext); + try { + $template = $this->twig()->createTemplate($templateString); + $arrayContext = json_decode(json_encode($context, JSON_THROW_ON_ERROR), true); + return $template->render($arrayContext); + } catch (JsonException $e) { + throw new Exception( + sprintf("Twig cannot render template \"%s\", Error : \"%s\".", $templateString, $e->getMessage()), + $e->getCode(), + $e + ); + } } /** diff --git a/packages/view/src/Charcoal/View/Twig/TwigLoader.php b/packages/view/src/Charcoal/View/Twig/TwigLoader.php index 11d3dbb25..af0064eef 100644 --- a/packages/view/src/Charcoal/View/Twig/TwigLoader.php +++ b/packages/view/src/Charcoal/View/Twig/TwigLoader.php @@ -28,7 +28,7 @@ class TwigLoader extends AbstractLoader implements * @param string $ident The template being evaluated. * @return boolean */ - protected function isTemplateString(string $ident): bool + public function isTemplateString(string $ident): bool { return strpos($ident, '{%') !== false || parent::isTemplateString($ident); } diff --git a/packages/view/src/Charcoal/View/ViewAggregator.php b/packages/view/src/Charcoal/View/ViewAggregator.php new file mode 100644 index 000000000..e12be96d4 --- /dev/null +++ b/packages/view/src/Charcoal/View/ViewAggregator.php @@ -0,0 +1,131 @@ + + */ + protected array $engines = []; + + protected EngineInterface $engine; + + /** + * @var callable + */ + protected $renderTemplateStringDecider; + + /** + * @var callable + */ + protected $renderTemplateFileDecider; + + /** + * @param array $data + */ + public function __construct($data) + { + parent::__construct($data); + + $this->setEngines($data['engines']); + $this->renderTemplateFileDecider = $data['file_decider']; + $this->renderTemplateStringDecider = $data['string_decider']; + } + + /** + * @param array $data + * @return void + */ + private function setEngines(array $engines): void + { + foreach ($engines as $ident => $engine) { + $this->engines[$ident] = $engine; + } + } + + /** + * @return array + */ + private function getEngines(): array + { + return $this->engines; + } + + /** + * Load a template (from identifier) and render it. + * + * @param string $templateIdent The template identifier, to load and render. + * @param mixed $context The view controller (rendering context). + * @return string + */ + public function render(string $templateIdent, $context = null): string + { + $engine = call_user_func($this->renderTemplateFileDecider, $templateIdent, $context, $this->engines, $this->engine()); + return $engine->render($templateIdent, $context); + } + + /** + * Render a template (from string). + * + * @param string $templateString The full template string to render. + * @param mixed $context The view controller (rendering context). + * @return string + */ + public function renderTemplate(string $templateString, $context = null): string + { + $engine = call_user_func($this->renderTemplateStringDecider, $templateString, $context, $this->engines, $this->engine()); + return $engine->renderTemplate($templateString, $context); + } + + /** + * @return bool + */ + public function has($ident): bool + { + return isset($this->engines[$ident]); + } + + /** + * @param string $ident The view identifier. + * @throws InvalidArgumentException If identifer is not recognized. + * @return GenericView + */ + public function get(string $ident) + { + if (!$this->has($ident)) { + throw new InvalidArgumentException(sprintf( + "Engine identifer must be one of \"%s\", \"%s\" given.", + implode(', ', array_keys($this->engines)), + $ident + )); + } + + return new GenericView([ + 'engine' => $this->engines[$ident], + ]); + } + + /** + * @param string $ident The view identifier. + * @throws InvalidArgumentException If identifer is not recognized. + * @return self + */ + public function using($ident) + { + if (!$this->has($ident)) { + throw new InvalidArgumentException(sprintf( + "Engine identifer must be one of \"%s\", \"%s\" given.", + implode(', ', array_keys($this->engines)), + $ident + )); + } + + $this->setEngine($this->engines[$ident]); + return $this; + } +} diff --git a/packages/view/src/Charcoal/View/ViewServiceProvider.php b/packages/view/src/Charcoal/View/ViewServiceProvider.php index 78d4c9395..c41a6fe05 100644 --- a/packages/view/src/Charcoal/View/ViewServiceProvider.php +++ b/packages/view/src/Charcoal/View/ViewServiceProvider.php @@ -22,6 +22,7 @@ use Charcoal\View\Twig\TranslatorHelpers as TwigTranslatorHelpers; use Charcoal\View\Twig\TwigEngine; use Charcoal\View\Twig\TwigLoader; +use Charcoal\View\ViewAggregator; /** * View Service Provider @@ -194,6 +195,20 @@ protected function registerEngineServices(Container $container): void ]); }; + /** + * The view engines. + * + * @param Container $container A container instance. + * @return array + */ + $container['view/engines'] = function (Container $container): array { + return [ + 'mustache' => $container['view/engine/mustache'], + 'php' => $container['view/engine/php'], + 'twig' => $container['view/engine/twig'], + ]; + }; + /** * The default view engine. * @@ -354,8 +369,11 @@ protected function registerViewServices(Container $container) * @return ViewInterface */ $container['view'] = function (Container $container): ViewInterface { - return new GenericView([ - 'engine' => $container['view/engine'] + return new ViewAggregator([ + 'engines' => $container['view/engines'], + 'engine' => $container['view/engine'], + 'file_decider' => $container['view/engine/decider/file'], + 'string_decider' => $container['view/engine/decider/string'], ]); }; @@ -381,5 +399,29 @@ protected function registerViewServices(Container $container) $parsedown->setSafeMode(true); return $parsedown; }; + + $container['view/engine/decider/string'] = $container->protect( + function ($templateString, $context, $engines, $defaultEngine): EngineInterface { + foreach ($engines as $engine) { + $string = $engine->loader()->resolveDynamicTemplate($templateString); + if ($engine->loader()->isTemplateString($string)) { + return $engine; + } + } + return $defaultEngine; + } + ); + + $container['view/engine/decider/file'] = $container->protect( + function ($templateFile, $context, $engines, $defaultEngine): EngineInterface { + foreach ($engines as $engine) { + $file = $engine->loader()->resolveDynamicTemplate($templateFile); + if ($engine->loader()->findTemplateFile($file)) { + return $engine; + } + } + return $defaultEngine; + } + ); } } From efef702501d6c8755ef468bba8d809ef6dc57f35 Mon Sep 17 00:00:00 2001 From: Xavier Aymond Date: Mon, 7 Nov 2022 10:55:45 -0500 Subject: [PATCH 07/15] Apply suggestions from code review Co-authored-by: Chauncey McAskill --- .../src/Charcoal/View/Twig/TwigEngine.php | 15 +++-- .../view/src/Charcoal/View/ViewAggregator.php | 62 ++++++++++++------- .../src/Charcoal/View/ViewServiceProvider.php | 4 +- 3 files changed, 52 insertions(+), 29 deletions(-) diff --git a/packages/view/src/Charcoal/View/Twig/TwigEngine.php b/packages/view/src/Charcoal/View/Twig/TwigEngine.php index 2452dc804..1209f83b9 100644 --- a/packages/view/src/Charcoal/View/Twig/TwigEngine.php +++ b/packages/view/src/Charcoal/View/Twig/TwigEngine.php @@ -6,7 +6,7 @@ use Charcoal\View\AbstractEngine; use InvalidArgumentException; -use Exception; +use UnexpectedValueException; use JsonException; use RuntimeException; use Symfony\Bridge\Twig\Extension\TranslationExtension; @@ -168,8 +168,8 @@ public function render(string $templateIdent, $context): string $arrayContext = json_decode(json_encode($context, JSON_THROW_ON_ERROR), true); return $this->twig()->render($templateIdent, $arrayContext); } catch (JsonException $e) { - throw new Exception( - sprintf("Twig cannot render \"%s\", Error : \"%s\".", $templateIdent, $e->getMessage()), + throw new UnexpectedValueException( + sprintf('Twig cannot render template [%s]: %s', $templateIdent, $e->getMessage()), $e->getCode(), $e ); @@ -188,8 +188,13 @@ public function renderTemplate(string $templateString, $context): string $arrayContext = json_decode(json_encode($context, JSON_THROW_ON_ERROR), true); return $template->render($arrayContext); } catch (JsonException $e) { - throw new Exception( - sprintf("Twig cannot render template \"%s\", Error : \"%s\".", $templateString, $e->getMessage()), + if (strlen($templateString) > 30) { + // Truncate the string to avoid polluting the logs with a long template. + $templateString = substr($templateString, 0, 29) . '…'; + } + + throw new UnexpectedValueException( + sprintf('Twig cannot render template [%s]: %s', $templateString, $e->getMessage()), $e->getCode(), $e ); diff --git a/packages/view/src/Charcoal/View/ViewAggregator.php b/packages/view/src/Charcoal/View/ViewAggregator.php index e12be96d4..531a2fb13 100644 --- a/packages/view/src/Charcoal/View/ViewAggregator.php +++ b/packages/view/src/Charcoal/View/ViewAggregator.php @@ -6,6 +6,13 @@ use InvalidArgumentException; +/** + * View Aggregator + * + * The aggregator is used to register several engines to dynamically resolve + * which engine to render any given template path or contents. + * Alternatively, you can manually decide which engine to use for a given scenario. + */ class ViewAggregator extends AbstractView { /** @@ -13,15 +20,14 @@ class ViewAggregator extends AbstractView */ protected array $engines = []; - protected EngineInterface $engine; /** - * @var callable + * @var callable(string, mixed, array, EngineInterface): EngineInterface */ protected $renderTemplateStringDecider; /** - * @var callable + * @var callable(string, mixed, array, EngineInterface): EngineInterface */ protected $renderTemplateFileDecider; @@ -38,13 +44,21 @@ public function __construct($data) } /** - * @param array $data + * @param array $data * @return void */ private function setEngines(array $engines): void { foreach ($engines as $ident => $engine) { - $this->engines[$ident] = $engine; + if ($engine instanceof EngineInterface) { + $this->engines[$ident] = $engine; + } else { + throw new InvalidArgumentException(sprintf( + 'Expected an instance of %s, received %s', + EngineInterface::class, + (is_object($engine) ? get_class($engine) : gettype($engine)) + )); + } } } @@ -83,26 +97,28 @@ public function renderTemplate(string $templateString, $context = null): string } /** - * @return bool + * Determine if the given engine is registered. + * + * @param string $ident The engine identifier. */ - public function has($ident): bool + public function has(string $ident): bool { return isset($this->engines[$ident]); } /** - * @param string $ident The view identifier. - * @throws InvalidArgumentException If identifer is not recognized. - * @return GenericView + * Retrieve the given engine if registered. + * + * @param string $ident The engine identifier. + * @throws InvalidArgumentException If the identifier is not registered. + * @return ViewInterface */ - public function get(string $ident) + public function get(string $ident): ViewInterface { if (!$this->has($ident)) { - throw new InvalidArgumentException(sprintf( - "Engine identifer must be one of \"%s\", \"%s\" given.", - implode(', ', array_keys($this->engines)), - $ident - )); + throw new InvalidArgumentException( + sprintf('Engine [%s] not registered', $ident) + ); } return new GenericView([ @@ -111,17 +127,19 @@ public function get(string $ident) } /** - * @param string $ident The view identifier. - * @throws InvalidArgumentException If identifer is not recognized. + * Change the default engine. + * + * @param string $ident The engine identifier. + * @throws InvalidArgumentException If the identifier is not registered. * @return self */ - public function using($ident) + public function using(string $ident) { if (!$this->has($ident)) { throw new InvalidArgumentException(sprintf( - "Engine identifer must be one of \"%s\", \"%s\" given.", - implode(', ', array_keys($this->engines)), - $ident + 'Engine [%s] not registered, must be one of %s', + $ident, + implode(', ', array_keys($this->engines)) )); } diff --git a/packages/view/src/Charcoal/View/ViewServiceProvider.php b/packages/view/src/Charcoal/View/ViewServiceProvider.php index c41a6fe05..9061f625c 100644 --- a/packages/view/src/Charcoal/View/ViewServiceProvider.php +++ b/packages/view/src/Charcoal/View/ViewServiceProvider.php @@ -401,7 +401,7 @@ protected function registerViewServices(Container $container) }; $container['view/engine/decider/string'] = $container->protect( - function ($templateString, $context, $engines, $defaultEngine): EngineInterface { + function (string $templateString, $context, array $engines, EngineInterface $defaultEngine): EngineInterface { foreach ($engines as $engine) { $string = $engine->loader()->resolveDynamicTemplate($templateString); if ($engine->loader()->isTemplateString($string)) { @@ -413,7 +413,7 @@ function ($templateString, $context, $engines, $defaultEngine): EngineInterface ); $container['view/engine/decider/file'] = $container->protect( - function ($templateFile, $context, $engines, $defaultEngine): EngineInterface { + function (string $templateFile, $context, array $engines, EngineInterface $defaultEngine): EngineInterface { foreach ($engines as $engine) { $file = $engine->loader()->resolveDynamicTemplate($templateFile); if ($engine->loader()->findTemplateFile($file)) { From 5ae5c9290a47cb66300eb53b7479039ea62e4415 Mon Sep 17 00:00:00 2001 From: Xavier Date: Tue, 8 Nov 2022 13:56:10 -0500 Subject: [PATCH 08/15] Fix setter for NestedWidgetFormGroup --- .../FormGroup/NestedWidgetFormGroup.php | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/packages/admin/src/Charcoal/Admin/Widget/FormGroup/NestedWidgetFormGroup.php b/packages/admin/src/Charcoal/Admin/Widget/FormGroup/NestedWidgetFormGroup.php index 13fd331ce..db9a64b64 100644 --- a/packages/admin/src/Charcoal/Admin/Widget/FormGroup/NestedWidgetFormGroup.php +++ b/packages/admin/src/Charcoal/Admin/Widget/FormGroup/NestedWidgetFormGroup.php @@ -9,6 +9,8 @@ use Charcoal\Factory\FactoryInterface; // From 'charcoal-ui' use Charcoal\Ui\FormGroup\AbstractFormGroup; +// From 'charcoal-translator' +use Charcoal\Translator\Translation; // From 'charcoal-admin' use Charcoal\Admin\Ui\NestedWidgetContainerInterface; use Charcoal\Admin\Ui\NestedWidgetContainerTrait; @@ -114,18 +116,26 @@ public function setWidgetId($widgetId) } /** - * @return Translation|string|null + * @param mixed $description The description attribute. + * @return self */ public function setDescription($description) { - parent::setDescription($this->renderTemplate($description)); - return $this; + $description = $this->translator()->translate($description); + $description = $this->renderTemplate($description); + parent::setDescription($description); } + + /** + * @param mixed $notes The notes attribute. + * @return self + */ public function setNotes($notes) { - parent::setNotes($this->renderTemplate($notes)); - return $this; + $notes = $this->translator()->translate($notes); + $notes = $this->renderTemplate($notes); + parent::setNotes($notes); } /** From 6bcd2453146972aa44a2747713ad0f7b4d722829 Mon Sep 17 00:00:00 2001 From: Xavier Date: Tue, 8 Nov 2022 14:01:22 -0500 Subject: [PATCH 09/15] Remove useless setView in AdminModule. Fix the README for Selectize --- packages/admin/README.md | 24 +++++++++---------- .../admin/src/Charcoal/Admin/AdminModule.php | 15 ++++-------- 2 files changed, 17 insertions(+), 22 deletions(-) diff --git a/packages/admin/README.md b/packages/admin/README.md index 02224805a..1ccb5b5a8 100644 --- a/packages/admin/README.md +++ b/packages/admin/README.md @@ -314,12 +314,12 @@ Usage example : "pattern": "title", "choice_obj_map": { "value": "ident", - "label": "{{customLabelFunction}} - {{someAdditionalInfo }}" + "label": "{{ customLabelFunction }} - {{ someAdditionalInfo }}" }, "selectize_templates": { - "item": "project/selectize/custom-item-template", - "option": "project/selectize/custom-option-template", - "controller": "project/selectize/custom-template" + "item": "{{> project/selectize/custom-item-template }}", + "option": "{{> project/selectize/custom-option-template }}", + "controller": "{{> project/selectize/custom-template }}" }, "selectize_options": { "plugins": { @@ -339,26 +339,26 @@ Selectize templates examples :
 "selectize_templates": {
-    "item": "{{customLabelFunction}} - {{someAdditionalInfo }}",
-    "option": "{{customLabelFunction}} - {{someAdditionalInfo }}"
+    "item": "{{ customLabelFunction }} - {{ someAdditionalInfo }}",
+    "option": "{{ customLabelFunction }} - {{ someAdditionalInfo }}"
 },
 
 ---
 
-"selectize_templates": "{{customLabelFunction}} - {{someAdditionalInfo }}",
+"selectize_templates": "{{ customLabelFunction }} - {{ someAdditionalInfo }}",
 
 ---
 
-"selectize_templates": "project/selectize/custom-template",
+"selectize_templates": "{{> project/selectize/custom-template }}",
 
 ---
 
 "selectize_templates": {
-   "item": "project/selectize/custom-item-template",
-   "option": "project/selectize/custom-option-template",
-   "controller": "project/selectize/custom-template",
+   "item": "{{> project/selectize/custom-item-template }}",
+   "option": "{{> project/selectize/custom-option-template }}",
+   "controller": "{{> project/selectize/custom-template }}",
    "data": {
-        "category": "{{selectedCategory}}"
+        "category": "{{ selectedCategory }}"
    }
 },
 
diff --git a/packages/admin/src/Charcoal/Admin/AdminModule.php b/packages/admin/src/Charcoal/Admin/AdminModule.php index 20647a98a..813f028b0 100644 --- a/packages/admin/src/Charcoal/Admin/AdminModule.php +++ b/packages/admin/src/Charcoal/Admin/AdminModule.php @@ -112,7 +112,6 @@ public function setupHandlers( $container->extend('notFoundHandler', function ($handler, $container) { $appConfig = $container['config']; $adminConfig = $container['admin/config']; - $adminView = $container['view']; if ($handler instanceof HandlerInterface) { $config = $handler->createConfig($appConfig['handlers.defaults']); $config->merge($adminConfig['handlers.defaults']); @@ -121,7 +120,7 @@ public function setupHandlers( $config->merge($adminConfig['handlers.notFound']); } - $handler->setView($adminView)->setConfig($config)->init(); + $handler->setConfig($config)->init(); } return $handler; @@ -136,7 +135,6 @@ public function setupHandlers( $container->extend('notAllowedHandler', function ($handler, $container) { $appConfig = $container['config']; $adminConfig = $container['admin/config']; - $adminView = $container['view']; if ($handler instanceof HandlerInterface) { $config = $handler->createConfig($appConfig['handlers.defaults']); $config->merge($adminConfig['handlers.defaults']); @@ -145,7 +143,7 @@ public function setupHandlers( $config->merge($adminConfig['handlers.notAllowed']); } - $handler->setView($adminView)->setConfig($config)->init(); + $handler->setConfig($config)->init(); } return $handler; @@ -160,7 +158,6 @@ public function setupHandlers( $container->extend('phpErrorHandler', function ($handler, $container) { $appConfig = $container['config']; $adminConfig = $container['admin/config']; - $adminView = $container['view']; if ($handler instanceof HandlerInterface) { $config = $handler->createConfig($appConfig['handlers.defaults']); $config->merge($adminConfig['handlers.defaults']); @@ -169,7 +166,7 @@ public function setupHandlers( $config->merge($adminConfig['handlers.phpError']); } - $handler->setView($adminView)->setConfig($config)->init(); + $handler->setConfig($config)->init(); } return $handler; @@ -184,7 +181,6 @@ public function setupHandlers( $container->extend('errorHandler', function ($handler, $container) { $appConfig = $container['config']; $adminConfig = $container['admin/config']; - $adminView = $container['view']; if ($handler instanceof HandlerInterface) { $config = $handler->createConfig($appConfig['handlers.defaults']); $config->merge($adminConfig['handlers.defaults']); @@ -193,7 +189,7 @@ public function setupHandlers( $config->merge($adminConfig['handlers.error']); } - $handler->setView($adminView)->setConfig($config)->init(); + $handler->setConfig($config)->init(); } return $handler; @@ -210,7 +206,6 @@ public function setupHandlers( $container->extend('maintenanceHandler', function ($handler, $container) { $appConfig = $container['config']; $adminConfig = $container['admin/config']; - $adminView = $container['view']; if ($handler instanceof HandlerInterface) { $config = $handler->createConfig($appConfig['handlers.defaults']); $config->merge($adminConfig['handlers.defaults']); @@ -219,7 +214,7 @@ public function setupHandlers( $config->merge($adminConfig['handlers.maintenance']); } - $handler->setView($adminView)->setConfig($config)->init(); + $handler->setConfig($config)->init(); } return $handler; From 0fdacedba7fd9a2661bb095198cfc3d16bef922d Mon Sep 17 00:00:00 2001 From: Xavier Date: Tue, 8 Nov 2022 14:06:46 -0500 Subject: [PATCH 10/15] refactor(view): rename file and string decider for file engine and string engine decider Rename file decider and string decider for file engine decider and string engine decider for ViewAggregator --- packages/view/src/Charcoal/View/ViewAggregator.php | 13 ++++++------- .../view/src/Charcoal/View/ViewServiceProvider.php | 8 ++++---- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/packages/view/src/Charcoal/View/ViewAggregator.php b/packages/view/src/Charcoal/View/ViewAggregator.php index 531a2fb13..07a55b964 100644 --- a/packages/view/src/Charcoal/View/ViewAggregator.php +++ b/packages/view/src/Charcoal/View/ViewAggregator.php @@ -20,16 +20,15 @@ class ViewAggregator extends AbstractView */ protected array $engines = []; - /** * @var callable(string, mixed, array, EngineInterface): EngineInterface */ - protected $renderTemplateStringDecider; + protected $renderTemplateFileEngineDecider; /** * @var callable(string, mixed, array, EngineInterface): EngineInterface */ - protected $renderTemplateFileDecider; + protected $renderTemplateStringEngineDecider; /** * @param array $data @@ -39,8 +38,8 @@ public function __construct($data) parent::__construct($data); $this->setEngines($data['engines']); - $this->renderTemplateFileDecider = $data['file_decider']; - $this->renderTemplateStringDecider = $data['string_decider']; + $this->renderTemplateFileEngineDecider = $data['file_engine_decider']; + $this->renderTemplateStringEngineDecider = $data['string_engine_decider']; } /** @@ -79,7 +78,7 @@ private function getEngines(): array */ public function render(string $templateIdent, $context = null): string { - $engine = call_user_func($this->renderTemplateFileDecider, $templateIdent, $context, $this->engines, $this->engine()); + $engine = call_user_func($this->renderTemplateFileEngineDecider, $templateIdent, $context, $this->engines, $this->engine()); return $engine->render($templateIdent, $context); } @@ -92,7 +91,7 @@ public function render(string $templateIdent, $context = null): string */ public function renderTemplate(string $templateString, $context = null): string { - $engine = call_user_func($this->renderTemplateStringDecider, $templateString, $context, $this->engines, $this->engine()); + $engine = call_user_func($this->renderTemplateStringEngineDecider, $templateString, $context, $this->engines, $this->engine()); return $engine->renderTemplate($templateString, $context); } diff --git a/packages/view/src/Charcoal/View/ViewServiceProvider.php b/packages/view/src/Charcoal/View/ViewServiceProvider.php index 9061f625c..e6b4a0d89 100644 --- a/packages/view/src/Charcoal/View/ViewServiceProvider.php +++ b/packages/view/src/Charcoal/View/ViewServiceProvider.php @@ -370,10 +370,10 @@ protected function registerViewServices(Container $container) */ $container['view'] = function (Container $container): ViewInterface { return new ViewAggregator([ - 'engines' => $container['view/engines'], - 'engine' => $container['view/engine'], - 'file_decider' => $container['view/engine/decider/file'], - 'string_decider' => $container['view/engine/decider/string'], + 'engines' => $container['view/engines'], + 'engine' => $container['view/engine'], + 'file_engine_decider' => $container['view/engine/decider/file'], + 'string_engine_decider' => $container['view/engine/decider/string'], ]); }; From 1a31df142ca2f2cedb22e3a154954217ce882c05 Mon Sep 17 00:00:00 2001 From: Xavier Date: Tue, 8 Nov 2022 16:37:33 -0500 Subject: [PATCH 11/15] Apply suggestions from code review --- .../Widget/FormGroup/NestedWidgetFormGroup.php | 8 ++++---- .../Charcoal/Admin/Widget/FormGroupWidget.php | 18 +++++++++++++----- .../view/src/Charcoal/View/ViewAggregator.php | 2 +- 3 files changed, 18 insertions(+), 10 deletions(-) diff --git a/packages/admin/src/Charcoal/Admin/Widget/FormGroup/NestedWidgetFormGroup.php b/packages/admin/src/Charcoal/Admin/Widget/FormGroup/NestedWidgetFormGroup.php index db9a64b64..74eabf7fd 100644 --- a/packages/admin/src/Charcoal/Admin/Widget/FormGroup/NestedWidgetFormGroup.php +++ b/packages/admin/src/Charcoal/Admin/Widget/FormGroup/NestedWidgetFormGroup.php @@ -117,25 +117,25 @@ public function setWidgetId($widgetId) /** * @param mixed $description The description attribute. - * @return self + * @return FormGroupWidget Chainable */ public function setDescription($description) { $description = $this->translator()->translate($description); $description = $this->renderTemplate($description); - parent::setDescription($description); + return parent::setDescription($description); } /** * @param mixed $notes The notes attribute. - * @return self + * @return FormGroupWidget Chainable */ public function setNotes($notes) { $notes = $this->translator()->translate($notes); $notes = $this->renderTemplate($notes); - parent::setNotes($notes); + return parent::setNotes($notes); } /** diff --git a/packages/admin/src/Charcoal/Admin/Widget/FormGroupWidget.php b/packages/admin/src/Charcoal/Admin/Widget/FormGroupWidget.php index 1d3065c20..352b297ae 100644 --- a/packages/admin/src/Charcoal/Admin/Widget/FormGroupWidget.php +++ b/packages/admin/src/Charcoal/Admin/Widget/FormGroupWidget.php @@ -289,18 +289,26 @@ public function locale() } /** - * @return Translation|string|null + * @param mixed $description The description attribute. + * @return FormGroupWidget Chainable */ public function setDescription($description) { - parent::setDescription($this->renderTemplate($description)); - return $this; + $description = $this->translator()->translate($description); + $description = $this->renderTemplate($description); + return parent::setDescription($description); } + + /** + * @param mixed $notes The notes attribute. + * @return FormGroupWidget Chainable + */ public function setNotes($notes) { - parent::setNotes($this->renderTemplate($notes)); - return $this; + $notes = $this->translator()->translate($notes); + $notes = $this->renderTemplate($notes); + return parent::setNotes($notes); } /** diff --git a/packages/view/src/Charcoal/View/ViewAggregator.php b/packages/view/src/Charcoal/View/ViewAggregator.php index 07a55b964..ed9628f5d 100644 --- a/packages/view/src/Charcoal/View/ViewAggregator.php +++ b/packages/view/src/Charcoal/View/ViewAggregator.php @@ -120,7 +120,7 @@ public function get(string $ident): ViewInterface ); } - return new GenericView([ + return new GenericView([ 'engine' => $this->engines[$ident], ]); } From 5d75d30b9e594c492a07a95c57988a2587a35cb7 Mon Sep 17 00:00:00 2001 From: Chauncey McAskill Date: Wed, 9 Nov 2022 10:00:50 -0500 Subject: [PATCH 12/15] Clean-up dependencies in AdminWidget The 'view' service is provided by the parent class `AbstractWidget`. --- packages/admin/src/Charcoal/Admin/AdminWidget.php | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/admin/src/Charcoal/Admin/AdminWidget.php b/packages/admin/src/Charcoal/Admin/AdminWidget.php index 8e709c4ae..02d15bef2 100644 --- a/packages/admin/src/Charcoal/Admin/AdminWidget.php +++ b/packages/admin/src/Charcoal/Admin/AdminWidget.php @@ -469,7 +469,6 @@ protected function setDependencies(Container $container) // Satisfies AdminWidget dependencies $this->setModelFactory($container['model/factory']); - $this->setView($container['view']); } /** From b241279eb4bfa73af8d6deab7a8a1ba35a1fde0d Mon Sep 17 00:00:00 2001 From: Chauncey McAskill Date: Wed, 9 Nov 2022 10:08:29 -0500 Subject: [PATCH 13/15] Sort namespace imports in AdminServiceProvider Remove unused and duplicate imports. --- .../ServiceProvider/AdminServiceProvider.php | 59 ++++++------------- 1 file changed, 19 insertions(+), 40 deletions(-) diff --git a/packages/admin/src/Charcoal/Admin/ServiceProvider/AdminServiceProvider.php b/packages/admin/src/Charcoal/Admin/ServiceProvider/AdminServiceProvider.php index 9b663193c..12aeabaa4 100644 --- a/packages/admin/src/Charcoal/Admin/ServiceProvider/AdminServiceProvider.php +++ b/packages/admin/src/Charcoal/Admin/ServiceProvider/AdminServiceProvider.php @@ -2,55 +2,34 @@ namespace Charcoal\Admin\ServiceProvider; -// From Pimple -use Charcoal\Admin\AssetsConfig; -use Pimple\Container; -use Pimple\ServiceProviderInterface; use Assetic\Asset\AssetReference; -use Charcoal\Attachment\Object\File; -use Charcoal\Factory\GenericResolver; -// from 'kriswallsmith/assetic' use Assetic\AssetManager; -// From PSR-7 -use Psr\Http\Message\UriInterface; -// From Slim -use Slim\Http\Uri; -// From Mustache -use Mustache_LambdaHelper as LambdaHelper; -// From 'charcoal-config' +use Charcoal\Admin\AssetsConfig; +use Charcoal\Admin\Config as AdminConfig; +use Charcoal\Admin\Property\PropertyDisplayInterface; +use Charcoal\Admin\Property\PropertyInputInterface; +use Charcoal\Admin\Service\SelectizeRenderer; +use Charcoal\Admin\Ui\SecondaryMenu\GenericSecondaryMenuGroup; +use Charcoal\Admin\Ui\SecondaryMenu\SecondaryMenuGroupInterface; +use Charcoal\Admin\User; +use Charcoal\Admin\User\AuthToken; +use Charcoal\Attachment\Object\File; use Charcoal\Config\ConfigInterface; use Charcoal\Config\GenericConfig as Config; -// From email -use Charcoal\Email\Email; -use Charcoal\Email\EmailInterface; -// From 'charcoal-factory' +use Charcoal\Email\ServiceProvider\EmailServiceProvider; use Charcoal\Factory\FactoryInterface; -use Charcoal\Factory\GenericFactory; -// From 'charcoal-core' +use Charcoal\Factory\GenericFactory as Factory; +use Charcoal\Factory\GenericResolver; use Charcoal\Model\Service\MetadataConfig; -// From 'charcoal-ui' use Charcoal\Ui\ServiceProvider\UiServiceProvider; -// From 'charcoal-email' -use Charcoal\Email\ServiceProvider\EmailServiceProvider; -// From 'charcoal-factory' -use Charcoal\Factory\GenericFactory as Factory; -// From 'charcoal-user' use Charcoal\User\Authenticator; use Charcoal\User\Authorizer; -// From 'charcoal-view' -use Charcoal\View\EngineInterface; -use Charcoal\View\GenericView; use Charcoal\View\ViewConfig; -use Charcoal\View\ViewInterface; -// From 'charcoal-admin' -use Charcoal\Admin\Config as AdminConfig; -use Charcoal\Admin\Property\PropertyInputInterface; -use Charcoal\Admin\Property\PropertyDisplayInterface; -use Charcoal\Admin\Service\SelectizeRenderer; -use Charcoal\Admin\Ui\SecondaryMenu\GenericSecondaryMenuGroup; -use Charcoal\Admin\Ui\SecondaryMenu\SecondaryMenuGroupInterface; -use Charcoal\Admin\User; -use Charcoal\Admin\User\AuthToken; +use Mustache_LambdaHelper as LambdaHelper; +use Pimple\Container; +use Pimple\ServiceProviderInterface; +use Psr\Http\Message\UriInterface; +use Slim\Http\Uri; /** * Charcoal Administration Service Provider @@ -183,7 +162,7 @@ protected function registerAdminServices(Container $container) * * @param ConfigInterface $viewConfig The view config instance. * @param Container $container A container instance. - * @return ViewInterface + * @return ViewConfig */ $container->extend('view/config', function (ViewConfig $viewConfig, Container $container): ViewConfig { $adminConfig = $container['admin/config']; From eb9a7178aa64ed5709a806e21718b2669b0f6af2 Mon Sep 17 00:00:00 2001 From: Chauncey McAskill Date: Wed, 9 Nov 2022 10:33:00 -0500 Subject: [PATCH 14/15] Fix renderTitle in EditTemplate A viewable object does not have a context parameter. --- .../admin/src/Charcoal/Admin/Template/Object/EditTemplate.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/admin/src/Charcoal/Admin/Template/Object/EditTemplate.php b/packages/admin/src/Charcoal/Admin/Template/Object/EditTemplate.php index c6c2a8f03..44225b3fb 100644 --- a/packages/admin/src/Charcoal/Admin/Template/Object/EditTemplate.php +++ b/packages/admin/src/Charcoal/Admin/Template/Object/EditTemplate.php @@ -212,7 +212,7 @@ protected function renderTitle($title) { $obj = $this->obj(); if ($this->isObjRenderable($obj)) { - return $obj->renderTemplate((string)$title, $obj); + return $obj->renderTemplate((string)$title); } else { return (string)$title; } From bd19301e4667c852f43b32495239f2b5372adcc3 Mon Sep 17 00:00:00 2001 From: Chauncey McAskill Date: Wed, 9 Nov 2022 10:34:50 -0500 Subject: [PATCH 15/15] Improve contexts in PhpEngine and TwigEngine Changed: - Moved logic irrelevant to JSON serialization outside of try/catch. - Added `JsonException` handling to `PhpEngine` to match `TwigEngine`. - Sorted namespace imports. --- .../view/src/Charcoal/View/Php/PhpEngine.php | 19 +++++++++++++++++-- .../src/Charcoal/View/Twig/TwigEngine.php | 10 ++++++---- 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/packages/view/src/Charcoal/View/Php/PhpEngine.php b/packages/view/src/Charcoal/View/Php/PhpEngine.php index 263a0eeea..eaab040ae 100644 --- a/packages/view/src/Charcoal/View/Php/PhpEngine.php +++ b/packages/view/src/Charcoal/View/Php/PhpEngine.php @@ -4,8 +4,9 @@ namespace Charcoal\View\Php; -// From 'charcoal-view' use Charcoal\View\AbstractEngine; +use JsonException; +use UnexpectedValueException; /** * PHP view rendering engine @@ -27,7 +28,21 @@ public function type(): string */ public function renderTemplate(string $templateString, $context): string { - $arrayContext = json_decode(json_encode($context, JSON_THROW_ON_ERROR), true); + try { + $arrayContext = json_decode(json_encode($context, JSON_THROW_ON_ERROR), true); + } catch (JsonException $e) { + if (strlen($templateString) > 30) { + // Truncate the string to avoid polluting the logs with a long template. + $templateString = substr($templateString, 0, 29) . '…'; + } + + throw new UnexpectedValueException( + sprintf('PHP cannot render template [%s]: %s', $templateString, $e->getMessage()), + $e->getCode(), + $e + ); + } + // Prevents leaking global variable by forcing anonymous scope $render = function ($templateString, array $context) { extract($context); diff --git a/packages/view/src/Charcoal/View/Twig/TwigEngine.php b/packages/view/src/Charcoal/View/Twig/TwigEngine.php index 1209f83b9..4b3175d90 100644 --- a/packages/view/src/Charcoal/View/Twig/TwigEngine.php +++ b/packages/view/src/Charcoal/View/Twig/TwigEngine.php @@ -6,12 +6,12 @@ use Charcoal\View\AbstractEngine; use InvalidArgumentException; -use UnexpectedValueException; use JsonException; use RuntimeException; use Symfony\Bridge\Twig\Extension\TranslationExtension; use Twig\Environment as TwigEnvironment; use Twig\Loader\FilesystemLoader as TwigFilesystemLoader; +use UnexpectedValueException; /** * @@ -166,7 +166,6 @@ public function render(string $templateIdent, $context): string { try { $arrayContext = json_decode(json_encode($context, JSON_THROW_ON_ERROR), true); - return $this->twig()->render($templateIdent, $arrayContext); } catch (JsonException $e) { throw new UnexpectedValueException( sprintf('Twig cannot render template [%s]: %s', $templateIdent, $e->getMessage()), @@ -174,6 +173,8 @@ public function render(string $templateIdent, $context): string $e ); } + + return $this->twig()->render($templateIdent, $arrayContext); } /** @@ -184,9 +185,7 @@ public function render(string $templateIdent, $context): string public function renderTemplate(string $templateString, $context): string { try { - $template = $this->twig()->createTemplate($templateString); $arrayContext = json_decode(json_encode($context, JSON_THROW_ON_ERROR), true); - return $template->render($arrayContext); } catch (JsonException $e) { if (strlen($templateString) > 30) { // Truncate the string to avoid polluting the logs with a long template. @@ -199,6 +198,9 @@ public function renderTemplate(string $templateString, $context): string $e ); } + + $templateWrapper = $this->twig()->createTemplate($templateString); + return $templateWrapper->render($arrayContext); } /**