statamic / cms

The core Laravel CMS Composer package
https://statamic.com
Other
3.71k stars 508 forks source link

nocache tag result in error 500 "Serialization of 'Closure' is not allowed" when used after a paginated collection tag #8052

Closed dadaxr closed 7 months ago

dadaxr commented 1 year ago

Bug description

As mentioned in the title, using a nocache tag pair after a calling a collection tag using a "paginate" param, fails !

I guess the paginate param create some closures somewhere in the global context and the nocache tag tries to "capture" it but fails...

How to reproduce

just put the bellow code in a template

{{ recettesVideo = {collection:recettes paginate="20" as="items"} }}
{{ nocache }}
   this fails
{{ /nocache }}

however the bellow examples dont trigger any error :

{{ recettesVideo = {collection:recettes as="items"} }}
{{ nocache }}
   no problem (no paginate param)
{{ /nocache }}
{{ nocache }}
   no problem !
{{ /nocache }}
{{ recettesVideo = {collection:recettes paginate="20" as="items"} }}

If we use a "classical" collection tag syntax :

{{ collection:recettes video:exists="true" paginate="20" as="items" }}
        {{ items }}
            {{ title }}
        {{ /items }}
{{ /collection:recettes }}
{{ nocache }}
   no problem ! because the context is restored after the closing collection tag, so there is no closure in the global context
{{ /nocache }}

however if we use a nocache tag inside the tag pair :

{{ collection:recettes video:exists="true" paginate="20" as="items" }}
        {{ items }}
            {{ title }}            
             {{ nocache }}
              This fails !  because there is a closure accessible in the current context 
             {{ /nocache }}
        {{ /items }}
{{ /collection:recettes }}

To give a concrete example : I have a list of receipt and that I want to show on a listing page. everything can be cached, except one value of each receipt (the rating) which can change dynamically. So I have that collection tag pair with a "nocache" tag inside it surrounding the rating part... and here comes the closure serialization error.

I dont know what can be done to resolve this issue ?

Logs

No response

Environment

Environment
Application Name: Statamic leporc
Laravel Version: 9.52.7
PHP Version: 8.1.14
Composer Version: 2.5.1
Environment: local
Debug Mode: ENABLED
URL: leporc.localhost
Maintenance Mode: OFF

Cache
Config: NOT CACHED
Events: NOT CACHED
Routes: NOT CACHED
Views: CACHED

Drivers
Broadcasting: log
Cache: statamic
Database: mysql
Logs: stack / single
Mail: smtp
Queue: sync
Session: file

Statamic
Addons: 1
Antlers: runtime
Stache Watcher: Disabled
Static Caching: Disabled
Version: 3.4.8 PRO

Statamic Addons
statamic/seo-pro: 4.0.1

Installation

Fresh statamic/statamic site via CLI

Antlers Parser

runtime (new)

Additional details

No response

jakubjo commented 1 year ago

Unfortunately this is a huge issue. I had this several times. It also affects custom variables ({{ items = {collection ...} }}) which are all put into the context and can't be serialized, when paginated.

If you can put the iterated code into a partial, there's a workaround:

{{ collection:recettes video:exists="true" paginate="20" as="items" }}
        {{ items }}
            {{ partial src="..." :paginate="null" }}
        {{ /items }}
{{ /collection:recettes }}

Partial's content:

{{ title }}            
{{ nocache }}
  This should work.
{{ /nocache }}

Besides that, the pagination in general does not work well with {{ nocache }}. If you wrap the whole collection + the pagination in a {{ nocache }} tag pair, you'll get links like example.com/!/nocache?page=2.

{{ nocache }}
  {{ collection:pages paginate="10" }}
      <ul>
          {{ entries }}
              <li>
                  {{ title }}
              </li>
          {{ /entries }}
      </ul>

      {{ paginate }}
          <!-- Will only work on first impression & will not work as expected, when served from cache. -->
          Next Page URL: {{ next_page }}
      {{ /paginate }}
  {{ /collection:pages }}
{{ /nocache }}
dadaxr commented 1 year ago

passing a null "paginate" param to a partial is a nice trick ! (when it can be done)

Thanks for sharing the pagination link issue, I'll have a look next time !

tenmillionteeth commented 1 year ago

I have also had this issue.