Access element of hash by variable value

21 views
Skip to first unread message

al james

unread,
Jun 4, 2009, 6:44:42 PM6/4/09
to H2o template PHP
Hi there... I dont know quite how to word this problem, so I will show
you in PHP.

How do I do this:

<?= $my_hash[$my_key] ?>

In H2o? If I do:

{{ my_hash.my_key }}

Its the equivalent of:

<?= $my_hash['my_key'] ?>

Right? Maybe:

{{ my_hash.:my_key }}

?

Cheers!

Taylor luk

unread,
Jun 4, 2009, 8:15:47 PM6/4/09
to H2o template PHP

Originally, Supporting bracket syntax is kind of the only reason for
this kind of feature, but i am not too sure on this one just yet.

{{ myhash[variable] }}


However adding a quick filter can fix your problem.

h2o::addFilter('at', 'h2o_at');
function h2o_at($hash, $index) { return $hash[$index]; }

{{ my_hash|at variable }}

Luke Visinoni

unread,
Jun 5, 2009, 12:26:19 PM6/5/09
to h2o-temp...@googlegroups.com
Or maybe that just isn't code that should be in the template? What does your code look like? Is it possible to push some of the logic to the controller and no longer need this? Just curious.

<")))><
Luke Visinoni

Taylor Luk

unread,
Jun 5, 2009, 12:45:49 PM6/5/09
to h2o-temp...@googlegroups.com
@luke I agree on that one too, It kind of also force you to create simplier data api design.

@james - I am trying to think of a use case for this,

Lets say u have following code where u want to use the index to switch current collection

$collection['tag-listing'] = array(new Tag, new Tag, new Tag);
$collection['article-listing'] = array(new Article, new Article, new Article);
$current = 'article-listing;

echo h2o('
  {% for item in collection[current] %}
     {% debug item %}
  {% endfor %}
')->render(compact('collection','list_type'));

But it can be easily replaced with following object which is got a bit proxy capability going on (my favorite pattern building data objects for h2o)  its slightly a bit more advanced but please checkout the actually variables in h2o templates,

class PaginateCollection extends ArrayObject {
   $h2o_safe = true;
   function initialize($list) {
      $this->list = $list;
      $this->type = 'article-listing';
   }

   function __call($method) {
      return $this->list[$method];
   }

   function current() {
      return $this->list[$this->current];
  }
}

$collection = new PaginateCollection(array(
   'article-listing' => array(...),
   'tag-listing' => array(...)
);

And the best part is in the template, you are accessing data in a way never possible in other templates before, because h2o template play very well with php overloaded objects and magic methods :)

echo h2o('
 
   {% for item in collection.current. %}
     {% debug item %}
   {% endfor %}

   Number of articles {{ collection.article-listing.length }}

   All your tags  {{ collection.tag-listing.join(', ') }}

')->render(compact('collection','list_type'));

Your template data api doesn't feel like php any more :)

Taylor Luk

unread,
Jun 5, 2009, 12:49:25 PM6/5/09
to h2o-temp...@googlegroups.com
correction.. virtual array property are there (list.first, list.last, list.length list.count ) but join is actually a filter

  All your tags  {{ collection.tag-listing | join(', ') }}

al james

unread,
Jun 11, 2009, 4:56:32 AM6/11/09
to H2o template PHP
Hi all...

Use case for this (something I repeatedly come across):

Say I have a list of rows taken from a database, e.g. (showing static
data, but would be taken from the DB):

$categories = array(
array('id'=>1, 'title'=>"Category 1", 'desc'=>"Category
description"),
array('id'=>2, title'=>"Category 2", 'desc'=>"Category
description"),
array('id'=>3, title'=>"Category 3", 'desc'=>"Category description")
);

And also (from another query) a hash of category id => number if
posts:

$number_of_posts_per_category = array(
1=>10,
2=>15,
3=>8
)

In my template I would like to do:

<ul>
{% for category in categories %}
<li>{{ category.id}} ({{ number_of_posts_per_category[category.id] }}
posts)</li>
{% endfor %}
</ul>

See what I mean?

I could combine the number of posts into the $categories variable, but
IMO that just adds unnecessary code to my controller...

Al

On Jun 5, 5:49 pm, Taylor Luk <subject...@gmail.com> wrote:
> correction.. virtual array property are there (list.first, list.last,
> list.length list.count ) but join is actually a filter
>
>   All your tags  {{ collection.tag-listing | join(', ') }}
>
> > And the *best part* is in the template, you are accessing data in a way
> > never possible in other templates before, because h2o template play very
> > well with php overloaded objects and magic methods :)
>
> > echo h2o('
>
> >    {% for item in collection.current. %}
> >      {% debug item %}
> >    {% endfor %}
>
> >    Number of articles {{ collection.article-listing.length }}
>
> >    All your tags  {{ collection.tag-listing.join(', ') }}
>
> > ')->render(compact('collection','list_type'));
>
> > Your template data api doesn't feel like php any more :)
>
> > On Sat, Jun 6, 2009 at 2:26 AM, Luke Visinoni <luke.visin...@gmail.com>wrote:
>
> >> Or maybe that just isn't code that should be in the template? What does
> >> your code look like? Is it possible to push some of the logic to the
> >> controller and no longer need this? Just curious.
>
> >> <")))><
> >> Luke Visinoni
>

al james

unread,
Jun 11, 2009, 5:36:21 AM6/11/09
to H2o template PHP
Sorry, I mean:

<ul>
{% for category in categories %}
<li>{{ category.title}} ({{ number_of_posts_per_category
[category.id] }}
posts)</li>
{% endfor %}
</ul>

Taylor Luk

unread,
Jun 11, 2009, 6:36:23 AM6/11/09
to h2o-temp...@googlegroups.com
I understand your concern, i have done some reading on django documentation which also doesn't support this and i know there are similar templates that supports the bracket syntax (ruby liquid),

however, considering such changes yield little benefit vs the changes to the parser. I think making your data more self contained does get you better result, instead of doing this in your controller, i recommend to do it in your model.

# category.posts_count
foreach ($categories as &$category)
  $category['posts_count'] = $number_of_posts_per_category[$category['id']];

In addition, depends on the kind of ORM you are using this is actually a quite popular optimization pattern call counter caching, which you have a new column holds the counter value of your associated objects and it updates on post create and post delete, so it doesn't need seperate query for most of the time.

category.posts_count
category.comments_count

# Template :
Alternatively, a different technique you can also create a filter like this , but since currently there are no easy want to get a reference of current context object, If you really want to do this, then i can should you how to do it..

({{ number_of_posts_per_category| at category.id }})

Taylor luk

unread,
Jun 11, 2009, 6:38:04 AM6/11/09
to H2o template PHP
typo:

i can *show you how to
do it..

On Jun 11, 8:36 pm, Taylor Luk <subject...@gmail.com> wrote:
> I understand your concern, i have done some reading on django documentation
> which also doesn't support this and i know there are similar templates that
> supports the bracket syntax (ruby liquid),
>
> however, considering such changes yield little benefit vs the changes to the
> parser. I think making your data more self contained does get you better
> result, instead of doing this in your controller, i recommend to do it in
> your model.
>
> # category.posts_count
> foreach ($categories as &$category)
>   $category['posts_count'] = $number_of_posts_per_category[$category['id']];
>
> In addition, depends on the kind of ORM you are using this is actually a
> quite popular optimization pattern call counter caching, which you have a
> new column holds the counter value of your associated objects and it updates
> on post create and post delete, so it doesn't need seperate query for most
> of the time.
>
> category.posts_count
> category.comments_count
>
> # Template :
> Alternatively, a different technique you can also create a filter like this
> , but since currently there are no easy want to get a reference of current
> context object, If you really want to do this, then i can should you how to
> do it..
>
> ({{ number_of_posts_per_category| at category.id }})
>

al james

unread,
Jun 11, 2009, 3:29:36 PM6/11/09
to H2o template PHP
> however, considering such changes yield little benefit vs the changes to the
> parser. I think making your data more self contained does get you better
> result, instead of doing this in your controller, i recommend to do it in
> your model.
>

IMO this is a step backward for two reasons:

1) Additional code just for the presentation of content.
2) (Worse) the model would now contain some presentational logic (e.g.
I would have to change it if I wanted to add some more information to
(say) the rows of a table rendered in the template layer).

Fundamentally, there is some code required to merge together data from
two or more sources. Should this be done in the model, view or
controller. I think the model is the wrong place (it makes too many
assumptions about presentation). In my mind as its a presentational
element, the view is the place to do it *as long as it does not cause
over complexity in the template*. In my mind, bracket syntax on arrays
does not really cause too much complexity.

But anyway, thats just my opinion, I respect yours.

> In addition, depends on the kind of ORM you are using this is actually a
> quite popular optimization pattern call counter caching, which you have a
> new column holds the counter value of your associated objects and it updates
> on post create and post delete, so it doesn't need seperate query for most
> of the time.
>

Sure, but thats another subject (e.g. if you are stuck with a certain
amount of legacy code, you cant just pick up a new ORM).

> # Template :
> Alternatively, a different technique you can also create a filter like this
> , but since currently there are no easy want to get a reference of current
> context object, If you really want to do this, then i can should you how to
> do it..
>
> ({{ number_of_posts_per_category| at category.id }})

Well thats not as readable as [category.id] is it? Its not that
important as its solvable in a million different ways, but its just
something that I feel constrained by when using template systems that
dont allow this....
Reply all
Reply to author
Forward
0 new messages