You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
(This issue came up in our Evans Hunt team Slack at least as early as Oct 2017, so it likely originated long before the current version.)
Description
When looping over a DataList within a template, making use of .Filter, .Sort, or .Limit methods will push the template context one level deeper per method use, making additional calls to Up within the loop necessary to reach the context outside the loop.
Expected behaviour
<h1>Children of '$Title'</h1>
<% loop $Children.Limit(2) %>
<p>Page '$Title' is a child of '$Up.Title'</p>
<% end_loop %>
Given the following structure I would expect this output.
My Page
|
+-+ Child 1
|
+-+ Child 2
|
+-+ Child 3
Children of 'My Page'
Page 'Child 1' is a child of 'My Page'
Page 'Child 2' is a child of 'MyPage'
Actual behaviour
The code above will actually output the following
Children of 'My Page'
Page 'Child 1' is a child of ''
Page 'Child 2' is a child of ''
If I throw an $Up.Me into the loop. I'll get this error:
[Emergency] Uncaught BadMethodCallException: Object->__call(): the method 'forTemplate' does not exist on 'SilverStripe\ORM\HasManyList'
The limit method apparently pushes the template context one level deeper, adding a level where the context is a list object itself. A list object is never an accessible context within a template without using Filter, Sort, or Limit so this is unexpected behaviour from my perspective.
Workaround
You can access the correct context by adding an extra Up
<h1>Children of '$Title'</h1>
<% loop $Children.Limit(2) %>
<p>Page '$Title' is a child of '$Up.Up.Title'</p>
<% end_loop %>
Further examples
This nested context compounds itself if you use multiple modifiers to the DataList. You could find yourself doing the following.
<h1>Children of '$Title'</h1>
<% loop $Children.Limit(2).Sort('Title ASC') %>
<p>Page '$Title' is a child of '$Up.Up.Up.Title'</p>
<% end_loop %>
Or go even deeper
<h1>Children of '$Title'</h1>
<% loop $Children.Limit(2).Sort('Title ASC').Filter('ImageID:GreaterThan', 0) %>
<p>Page '$Title' is a child of '$Up.Up.Up.Up.Title'</p>
<% end_loop %>
Conclusion
This does not seem like it should be the intended behaviour. If the core team believes otherwise then I think this should be reflected in the docs.
I suspect the underlying cause is related to the following comments in the DataList and ArrayList source code respectively:
/**
* DataLists are _immutable_ as far as the query they represent is concerned. When you call a method that
* alters the query, a new DataList instance is returned, rather than modifying the existing instance
/**
* Note that (like DataLists), the implementations of the methods from SS_Filterable, SS_Sortable and
* SS_Limitable return a new instance of ArrayList, rather than modifying the existing instance.
If this is indeed a bug, the fix will be a breaking change as there are likely plenty of templates out there using an extra Up.
The text was updated successfully, but these errors were encountered:
Thanks @davejtoews, this has been fixed for SS5 (#8148) and you’re right - unfortunately we can’t fix this in SS4 as it’d be a breaking change. We do have a small note about it in the docs, I think that’s about all we can do about this issue for now 😞
Affected Version
Silverstripe 4.6.1
(This issue came up in our Evans Hunt team Slack at least as early as Oct 2017, so it likely originated long before the current version.)
Description
When looping over a DataList within a template, making use of
.Filter
,.Sort
, or.Limit
methods will push the template context one level deeper per method use, making additional calls toUp
within the loop necessary to reach the context outside the loop.Expected behaviour
Given the following structure I would expect this output.
Actual behaviour
The code above will actually output the following
If I throw an
$Up.Me
into the loop. I'll get this error:The limit method apparently pushes the template context one level deeper, adding a level where the context is a list object itself. A list object is never an accessible context within a template without using Filter, Sort, or Limit so this is unexpected behaviour from my perspective.
Workaround
You can access the correct context by adding an extra
Up
Further examples
This nested context compounds itself if you use multiple modifiers to the DataList. You could find yourself doing the following.
Or go even deeper
Conclusion
This does not seem like it should be the intended behaviour. If the core team believes otherwise then I think this should be reflected in the docs.
I suspect the underlying cause is related to the following comments in the DataList and ArrayList source code respectively:
If this is indeed a bug, the fix will be a breaking change as there are likely plenty of templates out there using an extra
Up
.The text was updated successfully, but these errors were encountered: