Problem: you need to know where an asset has been placed in the SitePlan.
Well, I have a similar situation. I designed a site in a such way that the css of an asset is picked looking at the category of the parent page.
This is not odd: when you navigate a site and reach a page with a given style (that changes according to the sections of the site), if you navigate to the detail , usually what you want is children keep the same style of the parent page.
So, basically I want to locate the parent page (or at least the first parent page, since I know the asset can be actually placed in more than one page).
However, that is the problem. What is the solution?
Note: I normally use the infamous parameter p to find the parent page. Well, I found the p is not the more appropriate way of implementing the concept "pick the style from the parent". There are way too many cases where assigning the p correctly is difficult.So, how do you think you can find the parent? The simple solution is: enumerating all the pages, then check all the children until you find your asset. Well, I am sure you will agree if I say this solution is horrible, both performance wise and coding wise.
Fortunately I found is a better solution that I am posting here. This post is also a good opportunity to introduce an advanced Content Server techniques as well: the TreeManager.
The solution is basically looking into the table AssetRelationTree (that stores all the parent-children relationship) using the TreeManager (an internal server of ContentServerm accessible with a tag available in the tag libriry).
The problem, expressed in a more technical way, is: given an asset identified by his content id (stored in the "cid" variable), find the id of all the pages having that asset as a children. My Solution follows.
Step 1: locate a list of all the children assets in the AssetRelationTree with the TreeManager
<ics:treemanager> <ics:argument name="ftcmd" value="findnode"/> <ics:argument name="treename" value="AssetRelationTree"/> <ics:argument name="where" value="oid"/> <ics:argument name="oid" value='<%=ics.GetVar("cid")%>'/> </ics:treemanager>
Step 2: extract parents using their node id (nid) and getparent
The returned list is only a list of the available relations.
Using the nid of such a relation you can look for the parent.
This is the code to retrieve the parents:
<ics:copylist from="AssetRelationTree" to="List"/> <ics:listloop listname="List"> <ics:listget listname="List" fieldname="nid" output="nid" /> <ics:treemanager> <ics:argument name="ftcmd" value="getparent"/> <ics:argument name="treename" value="AssetRelationTree"/> <ics:argument name="node" value='<%=ics.GetVar("nid")%>'/> </ics:treemanager> <!-- now do something with the found id - see Step3 --> </ics:listlooop>
Note that I copied the list from the first TreeManager call because another call to TreeManager will store the result always in the same AssetRelationTree list. Since I have to call the TreeManager again I am preventing the list to be overwritten and I am working on a copy.
Step 3: grab parents and do something with them.
Inside the loop in Step2, you will get all the parents of the asset.
You can retrive the id of a parent with
<ics:listget listname="AssetRelationTree" fieldname="oid" output="p"/>
also you can read the type with
<ics:listget listname="AssetRelationTree" fieldname="otype" output="ptype"/>
but it should be always "Page". Now you can do what you want with the parent (in my case, I was just using the retrieved parent to set the p parameter).
Well, you could retrieve the parent with this simple database query, tested with jumpstart and hypersonic:
select otype,oid from AssetRelationTree where nid in (select nparentid from AssetRelationTree where oid = 123456789)
where 123456789 is the cid of the asset you are looking for its parents.
However, as a general rule, I do not trust too much explicit queries because they are database dependent.