Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wrong results of parent #3

Closed
Hannes-III opened this issue Jul 16, 2013 · 11 comments
Closed

Wrong results of parent #3

Hannes-III opened this issue Jul 16, 2013 · 11 comments

Comments

@Hannes-III
Copy link

In a chunk which is called uncached <[[!...]]> I unsed setPlaceholders to get some inforamtion from the current Parent resource.
I wrote the following HTML to test the snippet after I recived unexpected results.

[[setPlaceholders? &id=`[[+parent]]` &ph=`id`]]
[[setPlaceholders? &id=`[[+id]]` &ph=`parent.id`]]

[[!setPlaceholders? &prefix=`ex.` &id=`[[+parent]]` &ph=`id`]]
[[!setPlaceholders? &prefix=`ex.` &id=`[[+id]]` &ph=`parent.id`]]


<pre style="padding:5px; background-color: #bbbbbb; margin-bottom: 10px">
My ID: [[+id]]
Parent ID: [[+parent]]

SPH   ID from Parent : [[+sph.id]]
SPH   My Parents ID  : [[+sph.parent.id]]
SPH ! ID from Parent : [[+ex.id]]
SPH ! My Parents ID  : [[+ex.parent.id]]
</pre>

The result of <[[+id]]> and <[[+parent]]> always show the right result. From the four setPlaceholders methods only this one had the right result after iterating over three resources from two different Parents:

[[setPlaceholders? &id=`[[+id]]` &ph=`parent.id`]]

I thougth that all four should output the same result.
Here is the output of iterating over the three resources:

My ID: 5
Parent ID: 2

SPH   ID from Parent : 2
SPH   My Parents ID  : 2
SPH ! ID from Parent : 2
SPH ! My Parents ID  : 2
-------------------------------------------------

My ID: 8
Parent ID: 3

SPH   ID from Parent : 3
SPH   My Parents ID  : 3
SPH ! ID from Parent : 2
SPH ! My Parents ID  : 2
-------------------------------------------------

My ID: 10
Parent ID: 2

SPH   ID from Parent : 3
SPH   My Parents ID  : 2
SPH ! ID from Parent : 2
SPH ! My Parents ID  : 2
-------------------------------------------------

I hope this report will help to improve this handy snippet, I just deleted one of my snippets, because yours is so much better then mine, which had quite a limited approach.

Regards, Hannes

@oo12
Copy link
Owner

oo12 commented Jul 17, 2013

Hey, thanks for an excellent report Hannes. I appreciate the clarity and detail!
I've taken a look at this. It's an interesting problem.

First, would you please check if SPH ID from Parent : 3 is correct in the third section of the output (ID: 10)? Seems like that should be a 2...

I'm guessing you're using getResources? Something like

[[getResources? &parents=`-1` &resources=`6,13,22` &tpl=`sphtestTpl`]]

where sphtestTpl is the chunk from the top of your post? (I set up a test on one of my sites, so the resource ID numbers will be different than yours, but the idea is the same.)

After the resource has been cached, if you look in the cache you'll see it looks something like this:

[[!setPlaceholders? &prefix=`ex.` &id=`20` &ph=`id`]]
[[!setPlaceholders? &prefix=`ex.` &id=`22` &ph=`parent.id`]]

<pre style="padding:5px; background-color: #bbbbbb; margin-bottom: 10px">
My ID: 22
Parent ID: 20

SPH   ID from Parent : 20
SPH   My Parents ID  : 20
SPH ! ID from Parent : [[+ex.id]]
SPH ! My Parents ID  : [[+ex.parent.id]]
</pre>


[[!setPlaceholders? &prefix=`ex.` &id=`9` &ph=`id`]]
[[!setPlaceholders? &prefix=`ex.` &id=`13` &ph=`parent.id`]]

<pre style="padding:5px; background-color: #bbbbbb; margin-bottom: 10px">
My ID: 13
Parent ID: 9

SPH   ID from Parent : 9
SPH   My Parents ID  : 9
SPH ! ID from Parent : [[+ex.id]]
SPH ! My Parents ID  : [[+ex.parent.id]]
</pre>


[[!setPlaceholders? &prefix=`ex.` &id=`2` &ph=`id`]]
[[!setPlaceholders? &prefix=`ex.` &id=`6` &ph=`parent.id`]]

<pre style="padding:5px; background-color: #bbbbbb; margin-bottom: 10px">
My ID: 6
Parent ID: 2

SPH   ID from Parent : 2
SPH   My Parents ID  : 2
SPH ! ID from Parent : [[+ex.id]]
SPH ! My Parents ID  : [[+ex.parent.id]]
</pre>

The regular cached calls to setPlaceholders have been evaluated and those placeholders filled in, and what's left is the uncached calls and those placeholders which depend on them.
My guess is that the problem occurs because MODX first evaluates all the snippet calls, then all the placeholders, instead of evaluating them based on their order (2 snippets, 2 placeholders, 2 snippets, 2 placeholders, etc.). The three sets of snippets all use the same placeholder names, so for example [[+ex.id]] first gets set to 20, then 9, then finally to 2. Only after that are the placeholders evaluated, and by this point they're set to the results of the final pair of setPlaceholders calls, so each set of placeholders ends up with the same values as the final set and the output looks wrong.

To verify this is in fact what's happening, change your tpl chunk just a little. Make the uncached calls like this:

[[!setPlaceholders? &prefix=`ex.` &id=`[[+parent]]` &ph=`id` &output=`1`]]
[[!setPlaceholders? &prefix=`ex.` &id=`[[+id]]` &ph=`parent.id` &output=`1`]]

That way you'll see exactly what setPlaceholders is returning each time it's run. You should see that it's actually returning the correct values, but that the placeholders are getting overwritten before finally being evaluated.

Does that explanation match what you're seeing?

One way to prevent that from happening would be to do something like:

[[!setPlaceholders? &prefix=`ex[[+idx]].` &id=`[[+parent]]` &ph=`id`]]
[[!setPlaceholders? &prefix=`ex[[+idx]].` &id=`[[+id]]` &ph=`parent.id`]]
SPH ! ID from Parent : [[+ex[[+idx]].id]]
SPH ! My Parents ID  : [[+ex[[+idx]].parent.id]]

That way the prefix changes with each iteration (ex1, ex2, ex3) and you don't have the problem of lots of placeholders with the same name and stuff getting overwritten.

Or don't called it uncached, which is probably the best thing. Is there some reason you need to do that?

@Hannes-III
Copy link
Author

Thanks for your answer. I really appreciate a sophisticated discussion. One can learn so much.

My szenario is not so easy. I have Set up some Categories and the User may select some of the Elements from each category to be represented on his StartPage.
Therefore he places symlinks to the Resorces into his StatPage Container.
I Do it like this, because the way he can rearange symlinks by drag and drop in his StatPage Container is very convenient.
Every element on the StartPage is represented in a different color depending on the Container Category it came from. There is also a view to see all resources of a category.
See this screenshot for better illustration:
xxx1

Hence my getResources calls are quite complex:
First I have to read all the Symlinks out of my StartPage Container:

[[!getResources?
  &parents=`[[++site_start]]`
  &depth=`0`
  &tpl=`BallWrapper`
  &limit=`0`
  &sortby=`menuindex`
  &sortdir=`ASC`
  &includeContent=`1`
]]

The Chunk BallWrapper reads the the real recource ID and calls another snippet:

[[!getresources?
  &parents=`-1`
  &resources=`[[+content]]`
  &depth=`0`
  &tpl=`Ball`
  &includeContent=`1`
  &includeTVs=`1`
  &includeTVList=`ball_pic`
]]

My Ball Chunk contained the Test I posted in my first Comment.
But as I wrote this now I realized, that the whole second getREsources call could be replaced by setPlaceholders (which I was not aware of when I wrote the Chunk).
Now it looks like This:

[[ setPlaceholders? &id=`[[+content]]` &ph=`id || parent.id `]]
[[!setPlaceholders? &id=`[[+content]]` &ph=`id || parent.id ` &prefix=`ex.`]]

The first works fine, the second does not. It always prints the ID of the last result. But after I changed it to:

[[!setPlaceholders? &id=`[[+content]]` &ph=`id || parent.id ` &prefix=`ex[[+id]].`]]

YES! This helps.
It's strange, that it acts exactly as I did not expect. I thought that when I call the Snippet uncached, [[!...]] that I would not have any caching problems, but when I call it cached i Would.

A also tried your suggestion for &output=1 which proves that its not your fault. It always prints the right result. Without looking at the cached versions (Where can I find them? I am Quite new to MODx) I uderstand that it is a problem of the Placeholder that should print a different Value for every iteration, but it has the same Name, so it gets filled with the same Value in every case.
Now I think I also understand why it always replaces the placeholder with the Value of the last iteration.

First I thought I am in a hurry, I have to finish my Project, I will answer later, but now I even profit from having answered immediately, the new Way without the nested getResources call saves a lot of resources. Look at this:

BEFORE:
test_1

AFTER:
test_2

Conclusion:
I will use one of those two Methods. cached and uncached with ID in Placeholder Prefix:

[[!setPlaceholders? &id=`[[+content]]` &ph=`id || parent.id ` &prefix=`ex[[+id]].`]]
[[ setPlaceholders? &id=`[[+content]]` &ph=`id || parent.id ` &prefix=`sph[[+id]].`]]

while this Method works at first sight (call without caching disabled):

[[ setPlaceholders? &id=`[[+content]]` &ph=`id || parent.id `]]

It does not work if the getREsources call, is placed twice in the StartPage template.

Finally I speedtested the two approaches above. The average load time of cached was slightly faster (testing 100 Page calls). The winer is:

[[ setPlaceholders? &id=`[[+content]]` &ph=`id || parent.id ` &prefix=`sph[[+id]].`]]

regards, Hannes

PS.: it shows that this issue is not concerned with setPlaceholders, but I think the result of our discussion is quite useful and should be mentioned in the Documentation.

@Hannes-III
Copy link
Author

This is my suggestion for the Documentation, I just took notes for myself in german, here is my translation (it needs some improvment, maybe ;.) ).

If setPlaceholders is used in a CHUNK, that is called several times on a page, and every time it will deliver different Values for the Placeholders (e.g. the CHUNK Is called through getPlaceholders then you have to make sure, that the there are no placeholders that have the same name but different values. This is achived by renaming the Prefix for every iteration. Look at this:

[[ setPlaceholders? &id=`[[+content]]` &ph=`id` &prefix=`sph[[+id]].`]]

This is only necessary if you explicitly set the ID of the resource in question. If you do not use &id='[[+content]]' dynamically, setPlaceholders will only be used for one resource and hence there will not be any Problems.

@oo12
Copy link
Owner

oo12 commented Jul 18, 2013

Hi Hannes,

Yes, I'll add a note to the documentation about this; it's something other people might encounter and scratch their heads about :-)

Cached resources you can find in core/cache/resource/web/resources/. They're named by resource ID. They're instructive to look at and frequently offer some clues about how to improve performance or about what might be happening when you're trying to understand a problem, like in this case here.

Would you be able to send me the whole start page template and all the chunks related to the getResources calls on it? I know you mostly have, but I'm still a bit confused about what you've got set up and why various snippets need to be called uncached. Seems like they shouldn't need to be. There are a few pitfalls with getResources and caching and sometimes you need to use a trick on two in order for things to work properly.

Thanks for taking the time to make those performance graphs. They're interesting to look at!

@Hannes-III
Copy link
Author

I'll try again:

In my template use get Resources to retreve all the symlinks that are in the container.

[[!getResources?
  &parents=`[[++site_start]]`
  &depth=`0`
  &tpl=`BallWrapper`
  &limit=`0`
  &sortby=`menuindex`
  &sortdir=`ASC`
  &includeContent=`1`
]]

in the CHUNK BallWrapper I use setPlaceholders to retrieve the data of the symlinked resources and print them out using the winner from above:

[[ setPlaceholders? &id=`[[+content]]` &ph=`id || parent.id ` &prefix=`sph[[+id]].`]]

Referring my screenshot above, getResources retrieves the IDs 7, 9, 11. setPlaceholders reads from the [[+content]] Placehoder the ID the symlink points to and gets the data from the real resources: 7 Points to 5 and Parent is 2, 9=>8 p3, 11=>10 p2.

The getResources snippet I call uncached [[!...]]. I don't know if that is right or necessary. It works, and I don't have any performacne issunes. I think I have never seen any getResources example that was called without the ! so I do it too. If you can explain or point me to some place where I couls read about the criteria that influence the decision for ! or not, i would be grateful.

BTW: For the Stats, I use Apache jmeter http://jmeter.apache.org/ . Really easy to use.

@oo12
Copy link
Owner

oo12 commented Jul 19, 2013

Yes, there's a lot of confusion around cached vs. uncached snippets. You'll see plenty of needlessly uncached snippets in code posted in the MODX forums, and even in some documentation. There's certainly a fair amount of confusion out there, so it can be an understandably hard thing to figure out for sure.

Most of the time people use uncached snippets, there's no need to. So whenever you see that, it's good to stop and think whether there's any reason for it or not. Things work like this: if the snippet is called normally ( [[snippet]] ), then the first time somebody goes to that page the snippet runs and its output is stored in the cache. Effectively the snippet is replaced by its result, so it's no longer really there in the cache and whenever the page is accessed in the future, it doesn't have to run at all. Until the cache is cleared, at which point things start over.
Uncached snippets ( [[!snippet]] ) are run every time the page is loaded. If your site doesn't get much traffic that's not a big deal unless the snippet takes seconds to execute, but any sizable amount of traffic is going to hammer your server if you've got lots of uncached snippets on every page.

In order to determine which version to use, think about how often that element needs to be updated. Every time the page is loaded, or only when you add/delete/edit something in the manager? For most things it's the latter. You'd need uncached for, say, returning the results of a user's search (if that were cached, everybody would get the same results as the first search until the cache was cleared again).

This seems a little strange to me

[[ setPlaceholders? &id=`[[+content]]` &ph=`id || parent.id ` &prefix=`sph[[+id]].`]]

First, since it's inside a getResources call [[+id]] should be [[+idx]]. idx is a placeholder getResources sets. It starts at one and increments with each iteration. [[+id]] is the id of the resource getResources is processing. In this case that would work ok, but [[+idx]] is more correct. Second, you don't need to set a placeholder for id since you already have that number in [[+content]]. In effect you're saying "What's the id of the resource who's id is X?". Well, the answer is always X right? So just use [[+content]] where you would have used [[+sph[[+id]].id]].
With those two changes it becomes

[[setPlaceholders? &id=`[[+content]]` &ph=`parent.id ` &prefix=`sph[[+idx]].`]]

Make sense?

jmeter does look like a useful tool. I'll have to look into it more. Thanks!

@Hannes-III
Copy link
Author

Thanks for the explanation of caching or not.
That means, if I have a Page that shows a list of all resources in a container. The cache only gets deleted if the Container Resource is changed, but the cache would not be deleted if only one of the sub-resources is set offline. Therefor getResources should be called uncached, so that the list is always up to date.
Or if I do not call it uncached, I have to instruct my client to clear cache after he had done any changes on the site.
Yes I understand that you asked yourself what I intended to do with my snippet, calling on an ID and setting a placeholder containing the same ID. I know that this is nonsense, but I just did that, because I wanted to test if my placeholders set by setPlaceholders showed the same ID as the [[+content]] ID was.

@oo12
Copy link
Owner

oo12 commented Jul 19, 2013

No, it your case getResources should definitely be cached. The system cache is automatically cleared whenever you add/edit/delete/unpublish/whatever any resource or element. So whenever your client logs in to the manager and changes something, the cache will be cleared and then rebuilt as people visit each page.

Almost all of the time snippets should be cached. If you're not sure, cache it :-)

Here are a couple of use cases though where you would legitimately call getResources uncached:

  • You're using it to randomly select some items to display on a page and want the items to change each time somebody visits the page. Say, feature 3 random products from a certain category on your start page. Since you want the items to change each time somebody visits the site—and not just when you or your client log in to edit something—then it needs to be uncached so it runs on every page load.
  • You're displaying a list of items filtered by some criterion specified by the visitor. Maybe you have a page which will list all products by default, but will also take a GET parameter ( products.html?category=chicken ) to only display a certain subset of products. If you cached getResources on that page, then the result wouldn't change until the next time you edit the site, which isn't what you'd want.

@Hannes-III
Copy link
Author

WOW, thank you! That was important. I had a wrong concept of that "Clear Cache" option in the resource.
Good that I repeated what I understood. I think now I really understood the Caching stuff.

@oo12
Copy link
Owner

oo12 commented Jul 27, 2013

Going back to your original problem, I came across this blog post the other day which goes into a lot of detail about uncached snippets, placeholders and evaluation order.

@Hannes-III
Copy link
Author

Yes, very interesting, good post, thank you!

@oo12 oo12 closed this as completed Aug 3, 2013
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants