Follow-up to #2920841: Fix serialization of help topics
After serialization of help topic changed click on "Add another item" adds to logs a notice
Notice: serialize(): __sleep should return an array only containing the names of instance-variables to serialize. in Drupal\Component\Serialization\PhpSerialize::encode() (line 14 of /srv/core/lib/Drupal/Component/Serialization/PhpSerialize.php) #0 /srv/core/includes/bootstrap.inc(548): _drupal_error_handler_real(8, 'serialize(): __...', '/srv/core/lib/D...', 14, Array) #1 [internal function]: _drupal_error_handler(8, 'serialize(): __...', '/srv/core/lib/D...', 14, Array) #2 /srv/core/lib/Drupal/Component/Serialization/PhpSerialize.php(14): serialize(Array) #3 /srv/core/lib/Drupal/Core/KeyValueStore/DatabaseStorageExpirable.php(81): Drupal\Component\Serialization\PhpSerialize::encode(Array) #4 /srv/core/lib/Drupal/Core/Form/FormCache.php(197): Drupal\Core\KeyValueStore\DatabaseStorageExpirable->setWithExpire('form-RDcHNg4iFS...', Array, 21600) #5 /srv/core/lib/Drupal/Core/Form/FormBuilder.php(441): Drupal\Core\Form\FormCache->setCache('form-RDcHNg4iFS...', Array, Object(Drupal\Core\Form\FormState)) #6 /srv/core/lib/Drupal/Core/Form/FormBuilder.php(419): Drupal\Core\Form\FormBuilder->setCache('form-RDcHNg4iFS...', Array, Object(Drupal\Core\Form\FormState)) #7 /srv/core/lib/Drupal/Core/Form/FormBuilder.php(621): Drupal\Core\Form\FormBuilder->rebuildForm('help_topic_edit...', Object(Drupal\Core\Form\FormState), Array) #8 /srv/core/lib/Drupal/Core/Form/FormBuilder.php(314): Drupal\Core\Form\FormBuilder->processForm('help_topic_edit...', Array, Object(Drupal\Core\Form\FormState)) #9 /srv/core/lib/Drupal/Core/Controller/FormController.php(74): Drupal\Core\Form\FormBuilder->buildForm('help_topic_edit...', Object(Drupal\Core\Form\FormState)) #10 [internal function]: Drupal\Core\Controller\FormController->getContentResult(Object(Symfony\Component\HttpFoundation\Request), Object(Drupal\Core\Routing\RouteMatch)) #11 /srv/core/lib/Drupal/Core/EventSubscriber/EarlyRenderingControllerWrapperSubscriber.php(123): call_user_func_array(Array, Array) #12 /srv/core/lib/Drupal/Core/Render/Renderer.php(576): Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}() #13 /srv/core/lib/Drupal/Core/EventSubscriber/EarlyRenderingControllerWrapperSubscriber.php(124): Drupal\Core\Render\Renderer->executeInRenderContext(Object(Drupal\Core\Render\RenderContext), Object(Closure)) #14 /srv/core/lib/Drupal/Core/EventSubscriber/EarlyRenderingControllerWrapperSubscriber.php(97): Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->wrapControllerExecutionInRenderContext(Array, Array) #15 [internal function]: Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}() #16 /srv/vendor/symfony/http-kernel/HttpKernel.php(153): call_user_func_array(Object(Closure), Array) #17 /srv/vendor/symfony/http-kernel/HttpKernel.php(68): Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object(Symfony\Component\HttpFoundation\Request), 1) #18 /srv/core/lib/Drupal/Core/StackMiddleware/Session.php(57): Symfony\Component\HttpKernel\HttpKernel->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true) #19 /srv/core/lib/Drupal/Core/StackMiddleware/KernelPreHandle.php(47): Drupal\Core\StackMiddleware\Session->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true) #20 /srv/core/modules/page_cache/src/StackMiddleware/PageCache.php(99): Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true) #21 /srv/core/modules/page_cache/src/StackMiddleware/PageCache.php(78): Drupal\page_cache\StackMiddleware\PageCache->pass(Object(Symfony\Component\HttpFoundation\Request), 1, true) #22 /srv/core/lib/Drupal/Core/StackMiddleware/ReverseProxyMiddleware.php(47): Drupal\page_cache\StackMiddleware\PageCache->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true) #23 /srv/core/lib/Drupal/Core/StackMiddleware/NegotiationMiddleware.php(50): Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true) #24 /srv/vendor/stack/builder/src/Stack/StackedHttpKernel.php(23): Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true) #25 /srv/core/lib/Drupal/Core/DrupalKernel.php(657): Stack\StackedHttpKernel->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true) #26 /srv/index.php(19): Drupal\Core\DrupalKernel->handle(Object(Symfony\Component\HttpFoundation\Request)) #27 /srv/.ht.router.php(49): require('/srv/index.php') #28 {main}.
| Comment | File | Size | Author |
|---|---|---|---|
| #21 | interdiff-20-21.txt | 2.96 KB | jhodgdon |
| #21 | 2922758-fix-collection-21.patch | 31.37 KB | jhodgdon |
Comments
Comment #2
jhodgdonUgh. I guess maybe we need to put the serialization back in?
Comment #3
andypostNo, it just needs fix ajax implementation which causes this
Comment #4
jhodgdonOK... I don't think we're intentionally trying to serialize, is this a Core bug? I think running into this was why I put serialization into the class in the first place? Anyway, if you know how to fix it, great!
Comment #5
andypostI will debug that after finishing tests for autocomplete
Comment #6
andypostDebugged and can't find the reason(
Patch removes useless property that may cause circular dependencies
Comment #7
andypostOTOH it may use configuration & original constructor to pass "body" & ID - it needs someone more familiar with plugin collections
Comment #8
jhodgdonOK. let's step back a second...
Before #2920841: Fix serialization of help topics, we had a test that instantiated, then serialized/unserialized a HelpTopic entity. And the HelpTopic entity implemented Serializable, and had serialize/unserialize methods.
In working on that issue, I removed the interface and methods. The test failed with an error very similar to the above, but we decided on that other issue that we didn't need HelpTopic to be serializable, so I removed the test and we committed that patch.
The original reason for adding serialization was because somewhere in the Form API, during the Ajax "Add item" stuff, the entity got serialized and it didn't work; it failed with an error very similar to the above. I thought that the need for serialization had gone away because even after #2920841: Fix serialization of help topics the Add Item button works now.
But maybe we need to reverse the patch from #2920841: Fix serialization of help topics? HelpTopic entities definitely don't serialize as they are now.
Thoughts?
Comment #9
jhodgdonSee also #2688730: Add new item button is not working due to serialization problem, which was the original issue when the Add Item button stopped working due to some change in Drupal Core.
Comment #10
jhodgdonI have the same PHP notice showing up in my dblog, when I hit the "Add new" button on the form.
When I look at the stack trace... it seems to come from FormCache::setCache(), which calls DatabaseStorageExpirable::setWithExpire(), passing in $form, and that ends up calling serialize($form).
So it looks like if you have a config entity form that uses Ajax, it is going to get run through the form cache, and the form will get serialized, including the config entity. So, I think the HelpTopic config entity does actually need to be serializable, and we should just reverse what we did on #2920841: Fix serialization of help topics and make it serializable again.
Thoughts?
Comment #11
jhodgdonHere is a patch that puts the serialization stuff back in HelpTopic, plus the serialization test. this also includes the patch in #6, which seems sensible to do in any case. I didn't make an interdiff, as all but the few lines in #6 is new patch.
When applied locally, the PHP notices about serialize/sleep are no longer getting into my dblog. I'm running the tests locally... any thoughts?
Comment #12
jhodgdonSerialize test failed. I forgot a use statement at the top of HelpTopicTest.
That's the interdiff. Tests all pass locally with this patch.
Comment #13
amateescu commentedI'll take a look tomorrow at this :)
Comment #14
andypostNotice goes exactly from serialize()
Btw patch from #6 needs separate issue
Comment #15
amateescu commentedSo the problem here was our usage of plugin collections in
\Drupal\config_help\Entity\HelpTopic. The point ofEntityWithPluginCollectionInterfaceis to be used when a config entity type actually stores some plugin configuration in one of its properties, but our entity type does not store any configuration for the\Drupal\config_help\Plugin\HelpSection\ConfigHelpSectionplugin, so we simply need to remove the dead code from\Drupal\config_help\Entity\HelpTopic.With this patch I don't see serialization notices in watchdog when clicking the "Add new" button anymore ;)
Edit: and all tests pass locally.
Comment #16
jhodgdonUm... The plugin collection that is referenced is for TextSection plugins, not HelpPageSection plugins.
The reason we have the plugin collection is that the body field on HelpTopic is a collection of TextSections. So I think we do actually need the HelpTopic to be an EntityWithPluginCollectionInterface, and I don't think it is correct to remove it. Having the interface there should take care of the proper cache tags that are needed on the HelpTopic entity because of its dependence on TextSection plugins, right?
This is very similar to what other Core config entities that implement EntityWithPluginCollectionInterfacee do. Here's a list of classes that implement the interface:
https://api.drupal.org/api/drupal/core%21lib%21Drupal%21Core%21Entity%21...
Examples:
ImageStyle's effects field is a collection of Effects
FilterFormat's filters field is a collection of Filters
Block's settings and visibility fields are both plugin collections
etc.
---
Regarding #6, OK we can make a separate issue for that.
Comment #17
amateescu commentedAhh, that's right. Not sure why I got confused with the other plugin provided by this module.
In that case, this patch should do it :)
Comment #18
jhodgdonAh, I see that is what those other EntityWithPluginCollection classes do... but we'll need to do more than that. The Add More button doesn't work at all with that patch. I get this in the dblog when the add button fails:
So. Really, the body is only currently sort of a collection of TextPlugin items... it needs to actually become a real collection probably... The TextSectionPluginManager may also need some work...
Comment #19
amateescu commentedYes, some more work is likely needed, I posted the patch from #17 without any kind of testing.
But it really just shows why we had that notice in the dblog, and it was because the return value of
\Drupal\Core\Plugin\ObjectWithPluginCollectionInterface::getPluginCollections()needs to be keyed by a string which represents a property of the config entity.Comment #20
jhodgdonOK, I think this works!
What it does:
a) Changes the body schema for the config entity to use 'id' instead of 'type' for the TextSection plugin ID
b) That allows us to use the default plugin collection constructor for the TextSectionPluginCollection
This makes everything work in the UI without errors in DB log. You have to uninstall/reinstall the module though.
I am running the tests locally and they have failures so this isn't final patch yet but you can see where it is headed.
Comment #21
jhodgdonAh, I forgot to update the configs in the test module for the new config schema. I think this may work... running tests locally again...
Comment #22
jhodgdonIncidentally this takes care of #6 too, because we don't pass the HelpTopic into the TextSectionPluginCollection constructor at all now, just the body array. Which will make that plugin collection more generic as well.
Comment #23
amateescu commented#21 looks great! If it passes all the tests, consider it RTBC from my POV :)
Comment #25
jhodgdonAlso filed #2923139: Move some functionality into the TextSectionPluginCollection... not quite but somewhat related to this issue.
Anyway, the tests pass locally, so @amateescu says this is RTBC, and I went ahead and committed it. Will update the Core patch shortly as well, and make sure amateescu gets credit there if not previously credited.
Thanks for the suggestion, review, help, etc.!
Comment #26
andypostGreat! Makes a lot of sense! I will try to check follow-up later this week