Forum

Posted by
Henrik (Grubba) Grubbström  -  December 2008
From lyskom://community.roxen.com/20566:

Dear Roxen developers and users,

I have one question.  Are there any smart way to modify variable
defined in parent scope?  It doesn't matter whether through RXML or
pike.



Situation is:

I have many pages which accepts form.limit and form.offset variables,
and produce list with limit/offest parameters.

Page A-1:
<html>
<body>
..
<list_a id="1" limit="&form.limit;" offset="&form.offset;" />
..
</body>
</html>

Tag definition for list_a follows like this:

<define tag="list_a">
  <ul>
  <emit source="sql"
     query="SELECT x,y FROM table_a WHERE id=:id
            LIMIT :limit OFFSET :offset"
     bindings="id=id, limit=limit, offset=offset">
    <li>&_.x; - &_.y;</li>
  </emit>
  </ul>
</define>


I must sanitize these form variables to be proper integer, and limit
must be positive, offset must be positive and smaller than 100 or so,
and, and...

Same time I also have Page B(s), which use tag list_b, accepts same
limit/offset form variables.  They should be get sanitzed same way.


If it is possible, I want to do like this:

<define tag="cleanup_limit_offset" >
  <sscanf format="%d" variables="Parent.limit">&Parent.limit;</sscanf>
  <sscanf format="%d" variables="Parent.offset">&Parent.offset;</sscanf>
  <if variable="Parent.limit < 0">
   <set variable="Parent.limit" value="0" />
  </if>
  ...same for offset...
</define>

And modify list_a definition as:
<define tag="list_a">
  <clean_formvars />
  <ul>
  <emit source="sql" ...
  ...
</define>


I know this below works:

<define tag="list_a">
  <clean_limit_offset limit="&_.limit;" offset="&_.offset;"
         parentscope="list_a" />
  <ul>
  <emit source="sql" ...
  ...
</define>

<define tag="clean_limit_offset" >
  ...some sanitization coding...
  <set variable="limit" from="_.limit" scope="&_.parentscope;" />
  <set variable="offset" from="_.offset" scope="&_.parentscope;" />
</define>


But making variation tags later (like list_e, list_f,...), I know I
will forget to modify parentscope parameter as "list_x" for tag
list_x.



So, are there any way to modify parent scope(name not known) variable
directly/indirecly anyway, or pass scope name(no hardcode) to child?


Best regards,

--
  ITANI Eiichiro
(20566) /Eiichiro ITANI <emu@ceres.dti.ne.jp>/
 
Posted by
Peter Jönsson  -  December 2008
Eh, I dont know and it is a bit late too but arent you making things a bit complicated here?

why dont you just use the cleaned vars as they are? Like this:

<define tag="clean_formvars">
  <sscanf format="%d" variables="limit" scope="form">&form.limit;</sscanf>
  <if variable="form.limit > 0"/>
  <else>  <!-- could not verify, set to safe value -->
   <set variable="form.limit" value="0" />
  </else>
...etc...
</define>

<define tag="list_a">
  <clean_formvars />
  <ul>
  <emit source="sql" query="SELECT x,y
FROM table_a
WHERE id=&form.id:mysql;
LIMIT &form.limit:mysql; OFFSET &form.offset:mysql;">...</emit>
   </ul>
</define>


Repeating your own code like this it might be a bit cumbersome in the long run. Wouldn't it be possible to make a common function for many of these calls? Just an example where you put the sql-query itself in the calling tag:

<define container="list_whatever">
  <clean_formvars />
  <set variable="var.tmpQuery"><contents value-of=".//query"/></set>
  <ul>
  <emit source="sql" query="&var.tmpQuery:mysql;"><li>...</li></emit>
   </ul>
  <unset variable="var.tmpQuery"/>
</define>

<list_whatever>
  <query>Select x,y from list_a where x='&form.x;'</query>
</list_whatever>

Hope this can be helpful. Please post replys on the planet roxen forum

/Peter
 
Posted by
ITANI Eiichiro  -  December 2008
Peter, thank you for your suggestion.

At beginning, I tried to do that way, wrapper tag.  But after years,
variation of list/wrappers increased, many copy-and-pasted patterns
written.  So it's a bit hard work that refactoring all of them... sigh.

Modifing form variables directory, it's clean but not enough for my
demand.  Because pages have more than one list_x entities, one is limited
by form variable, others have their own limitations independent from form
variable.  "list_x" tags must accept their own limitation attributes.

Anyway, playing with roxen and looking around source, I managed to
find a way to access parent scope name from child tag.  It's not clean
but work anyway.


<define tag="what_my_parent_name" trimwhites="yes">
<attrib name="level">0</attrib>
<?pike
  object fr = RXML.get_context()->frame;
  int level = (int)_.level;
  string parent_scope_name = "";
  catch {
    for (int i=-2;i<level;i++) {
      fr = fr->up;
    }
    if (!stringp(fr->scope_name) && objectp(fr->up))
      fr = fr->up;
    parent_scope_name= fr->scope_name;
  };
  if (parent_scope_name == 0 && zero_type(parent_scope_name))
     parent_scope_name="" ;
  write("%s",parent_scope_name);
?>
</define>

<define tag="modify_parent_limit">
  <set variable="parent_name"><what_my_parent_name level="2" /></set>
  <sscanf format="%d" variables="limit"><insert variable="limit" scope="&_.parent_name;" /></sscanf>
  <if variable="limit > 0">
  </if><else>
    <set variable="limit" value="0" />
  </else>
  <set variable="limit" scope="&_.parent_name;" value="&_.limit;" />
</define>

<define tag="test_a">
<p>limit is &_.limit;</p>
<modify_parent_limit />
<p>limit is now &_.limit;</p>
</define>


And page "test.html" as follows:

...
<test_a limit="&form.lm;" />
...


Accessing "test.html?lm=8xa&lm=foobar":

...
limit is 8xa&#0;18
limit is now 8
...


Yes, it's ugly.
 
Posted by
Martin Stjernholm  -  December 2008
It's intentional that the innermost scope is accessible by shortcut and the rest only by name. Generalizing the shortcut access to parent scopes by number or similar can make the code overly context dependent.

It's the same reasoning as to why the "break <n>" construct in e.g. sh hasn't become very popular and spread to other languages - e.g. Java and Pike went for "break <label>" instead.

I think your first approach with passing the scope name is sound. I'd probably satisfy myself with that even though it requires a little more typing.


But making variation tags later (like list_e, list_f,...), I know I
will forget to modify parentscope parameter as "list_x" for tag
list_x.


You can use the scope attribute to <define> to keep the same scope name in all your defines.
 
Posted by
ITANI Eiichiro  -  December 2008
You can use the scope attribute to <define> to keep the same scope name in all your defines


...Wow. I never noticed that.  wow.

I think your first approach with passing the scope name is sound. I'd probably satisfy myself with that even though it requires a little more typing.


I see your design policy.
So, can I get current scope name dynamically?  It's not bad, not violating the design policy, is it? If possible, that would ease building complex logic with nested tags.

Like below:
<define tag="list_some">
  <get_current_scope variable="my_namespace" />
  <child_logic_x namesp="&_.my_namespace;" />
  ...
</define>

I know a simpler version of previous what_my_parent_name do this job.  It would be nice that caller side looked simple and clean.
 
Posted by
Martin Stjernholm  -  December 2008
There's no tag for that afaik, but it sounds reasonable.
 
Posted by
David Hunter  -  May 2009
very late reply but have been doing a bit of work in this area lately.

is the below a possible solution where you just pass the variable name with its scope included to the tags?
the logic would probably need updating to suite your expected default limit.

<define tag="list_a">
   <clean-limit-offset limit="list_a.limit" offset="list_a.offset"/>
   <ul>
      <emit source="sql" query="
         SELECT x,y
         FROM table
         WHERE id = '&_.id;'
         LIMIT &_.limit; OFFSET &_.offset;
         ">
         <li>&_.x; &_.y;</li>     
      </emit>
   </ul>
</define>

<define tag="clean-limit-offset">
   <comment>fix limit variable</comment>
   <if variable="&_.limit; is ?*">
      <sscanf format="%d" variables="_.limit_clean"><insert variable="&_.limit;"/></sscanf>
      <if not='' variable="_.limit_clean > 0">
         <set variable="&_.limit;" value="0"/>
      </if>
      <else>
          <set variable="&_.limit;" value="&_.limit_clean;"/>
      </else>
   </if>
   <else>
      <set variable="&_.limit;" value="10"/>
   </else>
   <comment>fix offset variable</comment>
   <if variable="&_.offset; is ?*">
      <sscanf format="%d" variables="_.offset_clean"><insert variable="&_.offset;"/></sscanf>
      <if not='' variable="_.offset_clean > 0">
         <set variable="&_.offset;" value="0"/>
      </if>
      <else>
         <set variable="&_.offset;" value="&_.offset_clean;"/>
      </else>
   </if>
   <else>
      <set variable="&_.offset;" value="0"/>
   </else>
</define>

<list_a id="94" limit="&form.limit;" offset="&form.offset;" />
 
1
Search this thread: