gremo
gremo

Reputation: 48899

How to traverse an object like it was an array (i.e. get key/val pairs) in Twig?

In Twig, how can I list all keys/value pairs from an object (read: private/protected properties), given that the proper getters exist?

class MyObject
{
    protected $foo;

    public function __construct()
    {
        $this->foo = 'bar';
    }

    public function getFoo()
    {
        return $this->foo;
    }

}

In the above example I'd like to get "foo" (the key) and "bar" (the value). Twig already let me do something like myobject.foo or myobject['foo'] to get "bar".

The following doesn't work (array-like syntax):

{% for key, val in myobject %}
    {{ key }}={{ val }}
{% endfor %}

Should I implement Iterator interface or there is a better/native way?

Upvotes: 1

Views: 2027

Answers (2)

Flosculus
Flosculus

Reputation: 6946

If you're looking for a solution other than Iterator (which personally I would go with), you could create a twig extension that provides a filter:

http://symfony.com/doc/current/cookbook/templating/twig_extension.html

From here you can manipulate the object however you wish. For example a to_array filter, that accepts various types of values and converts them (to the best of its ability) to an array, eg:

Convert PHP object to associative array

{% for key, val in myobject|to_array %}
    {{ key }}={{ val }}
{% endfor %}

However this is simply providing you with the solution you asked for, Peter's method is generally better practice.

Upvotes: 1

Peter Bailey
Peter Bailey

Reputation: 105868

This has nothing to do with Twig directly, but rather how PHP handles the iteration of objects.

So, for example, what happens if you do this?

class MyObject
{
  protected $foo;

  public function __construct()
  {
    $this->foo = 'bar';
  }

  public function getFoo()
  {
    return $this->foo;
  }
}

$myObject = new MyObject();

foreach ( $myObject as $property => $value )
{
  echo "$property: $value<br>";
}

Nothing. Zilch. Nada. A white screen in your browser.

However, if you cast your object as an array, then it works

foreach ( (array) $myObject as $property => $value )
{
  echo "$property: $value<br>";
}

// *foo: bar

What's up with that asterisk? More on that later...

However, you can't use PHP's explicit type casting in Twig. So what now? Enter IteratorAggregate

class MyObject implements \IteratorAggregate
{
  protected $foo;

  public function __construct()
  {
    $this->foo = 'bar';
  }

  public function getFoo()
  {
    return $this->foo;
  }

  public function getIterator()
  {
    return new \ArrayIterator( (array) $this );
  }
}

However, you will still have one issue: that darned asterisk. It's there because MyObject::$foo is protected - PHP automatically does this when the type is converted from MyObject to array. So, what now? Well, there are other ways to expose/create iterators on objects. You could always do it "manually"

  public function getIterator()
  {
    return new \ArrayIterator( array(
      'foo' => $this->getFoo()
    ) );
  }

You could alternatively implement Iterator or go even deeper down the rabbit's hole and inherit from ArrayObject

Upvotes: 3

Related Questions