From d03ca925bdf0ead3b14c317bdcb8118f92fe21a9 Mon Sep 17 00:00:00 2001 From: Andy Miller Date: Tue, 27 Jun 2023 04:30:06 -0600 Subject: [PATCH 1/8] more robust multilang fix --- CHANGELOG.md | 6 ++++++ form.php | 30 ++++++++++++++++++++---------- 2 files changed, 26 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 87e9dbf..64ba584 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +# v7.2.1 +## mm/dd/2023 + +1. [](#bugfix) + * More robust fix for multi-language form caching + # v7.2.0 ## 06/21/2023 diff --git a/form.php b/form.php index 9ed14b1..d1227f2 100644 --- a/form.php +++ b/form.php @@ -66,6 +66,7 @@ class FormPlugin extends Plugin /** @var array */ protected $json_response = []; + /** * @return bool */ @@ -311,9 +312,11 @@ public function onPageInitialized(): void /** @var Forms $forms */ $forms = $this->grav['forms']; + $lang = $this->grav['language']->getLanguage(); + /** @var Route $route */ $route = $this->grav['route']; - $pageForms = $this->forms[$route->getRoute()] ?? []; + $pageForms = $this->forms[$lang][$route->getRoute()] ?? []; /** * @var string $name @@ -828,10 +831,11 @@ public function onFormValidationError(Event $event): void public function addFormDefinition(PageInterface $page, string $name, array $form): void { $route = ($page->home() ? '/' : $page->route()) ?? '/'; + $lang = $this->grav['language']->getLanguage(); - if (!isset($this->forms[$route][$name])) { + if (!isset($this->forms[$lang][$route][$name])) { $form['_page_routable'] = !$page->isModule(); - $this->forms[$route][$name] = $form; + $this->forms[$lang][$route][$name] = $form; $this->saveCachedForms(); } } @@ -849,12 +853,13 @@ public function addForm(?string $route, ?FormInterface $form): void return; } + $lang = $this->grav['language']->getLanguage(); $name = $form->getName(); - if (!isset($this->forms[$route][$name])) { + if (!isset($this->forms[$lang][$route][$name])) { $form['_page_routable'] = true; - $this->forms[$route][$name] = $form; + $this->forms[$lang][$route][$name] = $form; $this->saveCachedForms(); } } @@ -869,6 +874,7 @@ public function getForm($data = null): ?FormInterface { /** @var Pages $pages */ $pages = $this->grav['pages']; + $lang = $this->grav['language']->getLanguage(); // Handle parameters. if (is_array($data)) { @@ -914,7 +920,7 @@ public function getForm($data = null): ?FormInterface // Attempt to find the form from the page. if ('' !== $route) { - $forms = $this->forms[$route] ?? []; + $forms = $this->forms[$lang][$route] ?? []; if (!$unnamed) { // Get form by the name. @@ -1096,7 +1102,9 @@ protected function getCurrentPageRoute() protected function findFormByName(string $name): array { $list = []; - foreach ($this->forms as $route => $forms) { + $lang = $this->grav['language']->getLanguage(); + + foreach ($this->forms[$lang] as $route => $forms) { foreach ($forms as $key => $form) { if ($name === $key && !empty($form['_page_routable'])) { $list[] = [$route, $key, $form]; @@ -1261,8 +1269,9 @@ protected function saveCachedForms(): void { /** @var Cache $cache */ $cache = $this->grav['cache']; - - $cache->save($this->getFormCacheId(), [$this->forms]); + $cache_id = $this->getFormCacheId(); + $this->grav['debugger']->addMessage($this->forms); + $cache->save($cache_id, [$this->forms]); } /** @@ -1274,8 +1283,9 @@ protected function getFormCacheId(): string { /** @var Pages $pages */ $pages = $this->grav['pages']; + $form_cache_id = $pages->getPagesCacheId() . '-form-plugin'; - return $pages->getPagesCacheId() . '-form-plugin'; + return $form_cache_id; } /** From 1b07f411ac9c1781649b2f28c6b78120da4142d2 Mon Sep 17 00:00:00 2001 From: Andy Miller Date: Tue, 27 Jun 2023 04:32:18 -0600 Subject: [PATCH 2/8] remove debug --- form.php | 1 - 1 file changed, 1 deletion(-) diff --git a/form.php b/form.php index d1227f2..130374c 100644 --- a/form.php +++ b/form.php @@ -1270,7 +1270,6 @@ protected function saveCachedForms(): void /** @var Cache $cache */ $cache = $this->grav['cache']; $cache_id = $this->getFormCacheId(); - $this->grav['debugger']->addMessage($this->forms); $cache->save($cache_id, [$this->forms]); } From dbdb9ee8bdda147fe44e245992d5112013e0c086 Mon Sep 17 00:00:00 2001 From: Andy Miller Date: Tue, 27 Jun 2023 04:54:59 -0600 Subject: [PATCH 3/8] wrong cache key --- form.php | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/form.php b/form.php index 130374c..882dbd8 100644 --- a/form.php +++ b/form.php @@ -1271,6 +1271,8 @@ protected function saveCachedForms(): void $cache = $this->grav['cache']; $cache_id = $this->getFormCacheId(); $cache->save($cache_id, [$this->forms]); +// $this->grav['debugger']->addMessage("cache_id: {$cache_id}"); +// $this->grav['debugger']->addMessage($this->forms); } /** @@ -1280,11 +1282,10 @@ protected function saveCachedForms(): void */ protected function getFormCacheId(): string { - /** @var Pages $pages */ - $pages = $this->grav['pages']; - $form_cache_id = $pages->getPagesCacheId() . '-form-plugin'; - - return $form_cache_id; + /** @var \Grav\Common\Cache $cache */ + $cache = $this->grav['cache']; + $cache_id = $cache->getKey() . '-form-plugin'; + return $cache_id; } /** From b7128d86ff2eeb15411c7b8c1022e7a9efee207b Mon Sep 17 00:00:00 2001 From: Andy Miller Date: Tue, 27 Jun 2023 05:11:26 -0600 Subject: [PATCH 4/8] safety check --- form.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/form.php b/form.php index 882dbd8..3db350f 100644 --- a/form.php +++ b/form.php @@ -1103,8 +1103,9 @@ protected function findFormByName(string $name): array { $list = []; $lang = $this->grav['language']->getLanguage(); + $lang_forms = $this->forms[$lang] ?? []; - foreach ($this->forms[$lang] as $route => $forms) { + foreach ($lang_forms as $route => $forms) { foreach ($forms as $key => $form) { if ($name === $key && !empty($form['_page_routable'])) { $list[] = [$route, $key, $form]; From ef1da199b09716d795c73df1304f0a7f43ca57d0 Mon Sep 17 00:00:00 2001 From: Andy Miller Date: Tue, 27 Jun 2023 06:03:05 -0600 Subject: [PATCH 5/8] some debugging --- CHANGELOG.md | 2 ++ blueprints.yaml | 11 +++++++++++ form.php | 33 +++++++++++++++++++++++++++++++-- form.yaml | 1 + 4 files changed, 45 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 64ba584..89e7c4e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,8 @@ # v7.2.1 ## mm/dd/2023 +1. [](#improved) + * Added some optional debug output to help isolate form loading problems 1. [](#bugfix) * More robust fix for multi-language form caching diff --git a/blueprints.yaml b/blueprints.yaml index 094eaa4..adf27d5 100644 --- a/blueprints.yaml +++ b/blueprints.yaml @@ -34,6 +34,17 @@ form: title: PLUGIN_FORM.GENERAL fields: + debug: + type: toggle + label: Debug + highlight: 1 + default: 0 + options: + 1: PLUGIN_ADMIN.ENABLED + 0: PLUGIN_ADMIN.DISABLED + validate: + type: bool + built_in_css: type: toggle label: PLUGIN_FORM.USE_BUILT_IN_CSS diff --git a/form.php b/form.php index 3db350f..8696d35 100644 --- a/form.php +++ b/form.php @@ -26,6 +26,7 @@ use Grav\Plugin\Form\Forms; use Grav\Plugin\Form\TwigExtension; use Grav\Common\HTTP\Client; +use Monolog\Logger; use ReCaptcha\ReCaptcha; use ReCaptcha\RequestMethod\CurlPost; use RecursiveArrayIterator; @@ -148,6 +149,8 @@ class_alias(Form::class, 'Grav\Plugin\Form'); 'onTwigSiteVariables' => ['onTwigVariables', 0], 'onFormValidationProcessed' => ['onFormValidationProcessed', 0], ]); + + } /** @@ -225,6 +228,7 @@ public function onPageInitialized(): void /** @var PageInterface $page */ $page = $this->grav['page']; + // Force rebuild form when form has not been built and form cache expired. // This happens when form cache expires before the page cache // and then does not trigger 'onPageProcessed' event. @@ -1258,6 +1262,12 @@ protected function loadCachedForms(): void // Only update the forms if it's not empty if ($forms) { $this->forms = array_merge($this->forms, $forms); + if ($this->config()['debug']) { + /** @var Logger $logger */ + $logger = $this->grav['log']; + $logger->addDebug(sprintf("<<<< Loaded cached forms: %s\n%s", $this->getFormCacheId(), $this->arrayToString($this->forms))); + } + } } @@ -1272,8 +1282,11 @@ protected function saveCachedForms(): void $cache = $this->grav['cache']; $cache_id = $this->getFormCacheId(); $cache->save($cache_id, [$this->forms]); -// $this->grav['debugger']->addMessage("cache_id: {$cache_id}"); -// $this->grav['debugger']->addMessage($this->forms); + if ($this->config()['debug']) { + /** @var Logger $logger */ + $logger = $this->grav['log']; + $logger->addDebug(sprintf(">>>> Saved cached forms: %s\n%s", $this->getFormCacheId(), $this->arrayToString($this->forms))); + } } /** @@ -1319,4 +1332,20 @@ protected function processBasicCaptchaImage(Uri $uri) exit; } } + + protected function arrayToString($array, $level = 0) { + $result = ''; + + foreach ($array as $key => $value) { + if (is_array($value)) { + if ($level < 2) { + $result .= "$key: " . $this->arrayToString($value, $level + 1) . "\n"; + } + } else { + $result .= "$key: $value\n"; + } + } + + return $result; + } } diff --git a/form.yaml b/form.yaml index 29793ca..27124a0 100644 --- a/form.yaml +++ b/form.yaml @@ -3,6 +3,7 @@ built_in_css: true inline_css: true refresh_prevention: false client_side_validation: true +debug: false inline_errors: false files: multiple: false # To allow multiple files, default is single From 35b1012ba52ce8ccbba1fc5614f7974446803698 Mon Sep 17 00:00:00 2001 From: Andy Miller Date: Tue, 27 Jun 2023 06:44:23 -0600 Subject: [PATCH 6/8] more fixes/improvements --- form.php | 53 ++++++++++++++++++++++++++--------------------------- 1 file changed, 26 insertions(+), 27 deletions(-) diff --git a/form.php b/form.php index 8696d35..5f9e425 100644 --- a/form.php +++ b/form.php @@ -940,9 +940,7 @@ public function getForm($data = null): ?FormInterface if (null === $form) { // First check if we requested a specific form which didn't exist. if ($route_provided || $unnamed) { - /** @var Debugger $debugger */ - $debugger = $this->grav['debugger']; - $debugger->addMessage(sprintf('Form %s not found in page %s', $name ?? 'unnamed', $route), 'warning'); + $this->grav['debugger']->addMessage(sprintf('Form %s not found in page %s', $name ?? 'unnamed', $route), 'warning'); return null; } @@ -956,8 +954,7 @@ public function getForm($data = null): ?FormInterface // Check for naming conflicts. if (count($forms) > 1) { - $debugger = $this->grav['debugger']; - $debugger->addMessage(sprintf('Fetching form by its name, but there are multiple pages with the same form name %s', $name), 'warning'); + $this->grav['debugger']->addMessage(sprintf('Fetching form by its name, but there are multiple pages with the same form name %s', $name), 'warning'); } [$route, $name, $form] = $first; @@ -969,9 +966,7 @@ public function getForm($data = null): ?FormInterface if (is_array($form)) { // Form was cached as an array, try to create the object. if (null === $page) { - /** @var Debugger $debugger */ - $debugger = $this->grav['debugger']; - $debugger->addMessage(sprintf('Form %s cannot be created as page %s does not exist', $name, $route), 'warning'); + $this->grav['debugger']->addMessage(sprintf('Form %s cannot be created as page %s does not exist', $name, $route), 'warning'); return null; } @@ -1246,12 +1241,9 @@ protected function loadCachedForms(): void /** @var Cache $cache */ $cache = $this->grav['cache']; - [$forms] = $cache->fetch($this->getFormCacheId()); + $forms = $cache->fetch($this->getFormCacheId()); } catch (Exception $e) { - /** @var Debugger $debugger */ - $debugger = Grav::instance()['debugger']; - $debugger->addMessage(sprintf('Unserializing cached forms failed: %s', $e->getMessage()), 'error'); - + $this->grav['debugger']->addMessage(sprintf('Unserializing cached forms failed: %s', $e->getMessage()), 'error'); $forms = null; } @@ -1263,9 +1255,7 @@ protected function loadCachedForms(): void if ($forms) { $this->forms = array_merge($this->forms, $forms); if ($this->config()['debug']) { - /** @var Logger $logger */ - $logger = $this->grav['log']; - $logger->addDebug(sprintf("<<<< Loaded cached forms: %s\n%s", $this->getFormCacheId(), $this->arrayToString($this->forms))); + $this->grav['log']->addDebug(sprintf("<<<< Loaded cached forms: %s\n%s", $this->getFormCacheId(), $this->arrayToString($this->forms))); } } @@ -1281,11 +1271,15 @@ protected function saveCachedForms(): void /** @var Cache $cache */ $cache = $this->grav['cache']; $cache_id = $this->getFormCacheId(); - $cache->save($cache_id, [$this->forms]); + + $forms = $cache->fetch($cache_id); + if ($forms) { + $this->forms = Utils::arrayMergeRecursiveUnique($this->forms, $forms); + } + + $cache->save($cache_id, $this->forms); if ($this->config()['debug']) { - /** @var Logger $logger */ - $logger = $this->grav['log']; - $logger->addDebug(sprintf(">>>> Saved cached forms: %s\n%s", $this->getFormCacheId(), $this->arrayToString($this->forms))); + $this->grav['log']->addDebug(sprintf(">>>> Saved cached forms: %s\n%s", $this->getFormCacheId(), $this->arrayToString($this->forms))); } } @@ -1333,17 +1327,22 @@ protected function processBasicCaptchaImage(Uri $uri) } } - protected function arrayToString($array, $level = 0) { - $result = ''; + protected function arrayToString($array, $level = 2) { + $result = $this->limitArrayLevels($array, $level); + return json_encode($result, JSON_UNESCAPED_SLASHES); + } + + protected function limitArrayLevels($array, $levelsToKeep, $currentLevel = 0) { + if ($currentLevel >= $levelsToKeep) { + return '-'; + } + $result = []; foreach ($array as $key => $value) { if (is_array($value)) { - if ($level < 2) { - $result .= "$key: " . $this->arrayToString($value, $level + 1) . "\n"; - } - } else { - $result .= "$key: $value\n"; + $value = $this->limitArrayLevels($value, $levelsToKeep, $currentLevel + 1); } + $result[$key] = $value; } return $result; From 9ff372ebf59b50f29b2f88c44f2f07a8b2d20caa Mon Sep 17 00:00:00 2001 From: Andy Miller Date: Tue, 27 Jun 2023 06:50:49 -0600 Subject: [PATCH 7/8] cleanup --- form.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/form.php b/form.php index 5f9e425..02eae7a 100644 --- a/form.php +++ b/form.php @@ -229,9 +229,7 @@ public function onPageInitialized(): void $page = $this->grav['page']; - // Force rebuild form when form has not been built and form cache expired. - // This happens when form cache expires before the page cache - // and then does not trigger 'onPageProcessed' event. + // DEPRECATED: This should no longer ever happen if (!$this->forms) { $this->onPageProcessed(new Event(['page' => $page])); } @@ -1253,7 +1251,7 @@ protected function loadCachedForms(): void // Only update the forms if it's not empty if ($forms) { - $this->forms = array_merge($this->forms, $forms); + $this->forms = Utils::arrayMergeRecursiveUnique($this->forms, $forms); if ($this->config()['debug']) { $this->grav['log']->addDebug(sprintf("<<<< Loaded cached forms: %s\n%s", $this->getFormCacheId(), $this->arrayToString($this->forms))); } From 69f459af69c7a42879d3c8d6f841d99ad11318e9 Mon Sep 17 00:00:00 2001 From: Andy Miller Date: Tue, 27 Jun 2023 11:58:11 -0600 Subject: [PATCH 8/8] prepare for release --- CHANGELOG.md | 2 +- blueprints.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 89e7c4e..7c88629 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,5 @@ # v7.2.1 -## mm/dd/2023 +## 06/27/2023 1. [](#improved) * Added some optional debug output to help isolate form loading problems diff --git a/blueprints.yaml b/blueprints.yaml index adf27d5..4a7ec33 100644 --- a/blueprints.yaml +++ b/blueprints.yaml @@ -1,7 +1,7 @@ name: Form slug: form type: plugin -version: 7.2.0 +version: 7.2.1 description: Enables forms handling and processing icon: check-square author: