solspace / craft-calendar

Calendar for Craft: The most reliable and powerful event management plugin for Craft.
http://docs.solspace.com/craft/calendar/v5
Other
15 stars 14 forks source link

Events field throwing "Serialization of 'Closure' is not allowed" Exception #319

Open nikolowry opened 1 week ago

nikolowry commented 1 week ago

Describe the bug or issue you're experiencing Events field cannot be saved due to serialization issue.

Screencast of issue

https://github.com/user-attachments/assets/9109312f-1635-4f3d-86d8-c8552fcb9a16

Steps to reproduce

  1. Add an event to an Events field
  2. Draft auto-saving will throw an error
  3. Try to save entry
  4. 500 Internal Server Error thrown.

Stack trace

Exception: Serialization of 'Closure' is not allowed in /var/www/wavehill/vendor/solspace/craft-calendar/packages/plugin/src/Elements/Db/EventQuery.php:1532
Stack trace:
#0 /var/www/wavehill/vendor/solspace/craft-calendar/packages/plugin/src/Elements/Db/EventQuery.php(1532): serialize()
#1 /var/www/wavehill/vendor/solspace/craft-calendar/packages/plugin/src/Elements/Db/EventQuery.php(367): Solspace\Calendar\Elements\Db\EventQuery->getConfigStateHash()
#2 /var/www/wavehill/vendor/craftcms/cms/src/fields/BaseRelationField.php(1312): Solspace\Calendar\Elements\Db\EventQuery->all()
#3 /var/www/wavehill/vendor/craftcms/cms/src/fields/BaseRelationField.php(860): craft\fields\BaseRelationField->inputTemplateVariables()
#4 /var/www/wavehill/vendor/craftcms/cms/src/base/Field.php(681): craft\fields\BaseRelationField->inputHtml()
#5 /var/www/wavehill/vendor/craftcms/cms/src/fieldlayoutelements/CustomField.php(397): craft\base\Field->getInputHtml()
#6 /var/www/wavehill/vendor/craftcms/cms/src/fieldlayoutelements/BaseField.php(365): craft\fieldlayoutelements\CustomField->inputHtml()
#7 /var/www/wavehill/vendor/craftcms/cms/src/fieldlayoutelements/CustomField.php(348): craft\fieldlayoutelements\BaseField->formHtml()
#8 /var/www/wavehill/vendor/craftcms/cms/src/web/View.php(1739): craft\fieldlayoutelements\CustomField->craft\fieldlayoutelements\{closure}()
#9 /var/www/wavehill/vendor/craftcms/cms/src/fieldlayoutelements/CustomField.php(347): craft\web\View->namespaceInputs()
#10 /var/www/wavehill/vendor/craftcms/cms/src/models/FieldLayout.php(858): craft\fieldlayoutelements\CustomField->formHtml()
#11 /var/www/wavehill/vendor/craftcms/cms/src/web/View.php(1733): craft\models\FieldLayout->craft\models\{closure}()
#12 /var/www/wavehill/vendor/craftcms/cms/src/models/FieldLayout.php(857): craft\web\View->namespaceInputs()
#13 /var/www/wavehill/vendor/craftcms/cms/src/controllers/ElementsController.php(924): craft\models\FieldLayout->createForm()
#14 /var/www/wavehill/vendor/craftcms/cms/src/controllers/ElementsController.php(401): craft\controllers\ElementsController->_prepareEditor()
#15 [internal function]: craft\controllers\ElementsController->craft\controllers\{closure}()
#16 /var/www/wavehill/vendor/craftcms/cms/src/web/CpScreenResponseFormatter.php(125): call_user_func()
#17 /var/www/wavehill/vendor/craftcms/cms/src/web/CpScreenResponseFormatter.php(50): craft\web\CpScreenResponseFormatter->_formatTemplate()
#18 /var/www/wavehill/vendor/yiisoft/yii2/web/Response.php(1109): craft\web\CpScreenResponseFormatter->format()
#19 /var/www/wavehill/vendor/craftcms/cms/src/web/Response.php(339): yii\web\Response->prepare()
#20 /var/www/wavehill/vendor/yiisoft/yii2/web/Response.php(340): craft\web\Response->prepare()
#21 /var/www/wavehill/vendor/yiisoft/yii2/base/Application.php(390): yii\web\Response->send()
#22 /var/www/wavehill/web/index.php(47): yii\base\Application->run()
#23 /var/www/wavehill/web/index.php(56): {closure}()
#24 {main}

Craft & Plugin Info (please complete the following information):

Additional context

I was able to temporarily get around this issue locally with the following changes to https://github.com/solspace/craft-calendar/blob/v5/packages/plugin/src/Elements/Db/EventQuery.php:

diff -rupN a/packages/plugin/src/Elements/Db/EventQuery.php b/packages/plugin/src/Elements/Db/EventQuery.php
--- a/packages/plugin/src/Elements/Db/EventQuery.php    2024-09-10 14:54:54.949241583 -0400
+++ b/packages/plugin/src/Elements/Db/EventQuery.php    2024-09-10 14:58:23.735754716 -0400
@@ -364,8 +364,6 @@ class EventQuery extends ElementQuery
             return parent::all();
         }

-        $configHash = $this->getConfigStateHash();
-
         // Nasty elements index hack
         if (!\Craft::$app->request->isConsoleRequest) {
             $context = \Craft::$app->request->post('context');
@@ -374,11 +372,13 @@ class EventQuery extends ElementQuery
             }
             // If we save an event via the events edit page or via the slide out panel, dont use the cached events
             $action = \Craft::$app->request->post('action');
-            if (\in_array($action, ['elements/save', 'calendar/events/save-event'], true)) {
+            if (\in_array($action, ['elements/apply-draft', 'elements/save', 'elements/save-draft', 'calendar/events/save-event'], true)) {
                 return parent::all();
             }
         }

+        $configHash = $this->getConfigStateHash();
+
         if (null === $this->events || self::$lastCachedConfigStateHash !== $configHash) {
             $limit = $this->limit;
             $offset = $this->offset;

But our production environment was still throwing the serialization exception, the only difference is that the production instance has revisions and is on Craft v5.4.1. So I ended up writing a new patch that caught getConfigStateHash exceptions:

diff -rupN a/packages/plugin/src/Elements/Db/EventQuery.php b/packages/plugin/src/Elements/Db/EventQuery.php
--- a/packages/plugin/src/Elements/Db/EventQuery.php    2024-09-10 14:54:54.949241583 -0400
+++ b/packages/plugin/src/Elements/Db/EventQuery.php    2024-09-10 16:06:26.664878026 -0400
@@ -1529,6 +1529,19 @@ class EventQuery extends ElementQuery
             'indexBy' => $this->indexBy,
         ];

-        return sha1(serialize($data));
+        $serialized = '';
+
+        try {
+            set_error_handler(static function ($severity, $message, $file, $line) {
+                throw new \ErrorException($message, 0, $severity, $file, $line);
+            });
+            $serialized = sha1(serialize($data));
+        }
+        catch (\Throwable $e) {}
+        finally {
+            restore_error_handler();
+        }
+
+        return $serialized;
     }
 }
a-am commented 5 days ago

We are experiencing the exact same issue. I tried to implement these changes but the error continued. Craft v5.4.2 Calendar v5.0.7 Calendar Edition: Pro

I have determined this issue was introduced with Craft v 5.4.0. I have tried 5.4.2, 5.4.1, 5.4.0 and each one had the same issue.

kjmartens commented 5 days ago

Sorry for the trouble @nikolowry and @a-am.

We are investigating the issue and hope to have a resolution soon. 🙂

nikolowry commented 4 days ago

@kjmartens @seandelaney confirming #322 resolves the issue for me. Thanks for the quick fix!