Twig iterating though a non nested array ( mysql_fetch_array ) - arrays

When I use the following code:
$members = array();
$members[] = array([id]=>"1", [name]=>"name") ; // mysql_fetch_array($row)
I can iterate with twig like this:
{% for member in members %}
<tr><td>{member.id}</td><td>{member.name}</td></tr>
{% endfor}
But I have more rows, and I don't want to allocate the entire array in the memory, it seems like a waste of resources to me.
So how do I loop through:
$members = array([id]=>"1", [name]=>"name");
Currently it seems to iterate each array key, in stead of the entire array:
{% for member in members %}
<tr><td>{member.id}</td><td>{member.name}</td></tr>
{% endfor}
outputs :
<tr><td>1</td></tr>
<tr><td>test</td></tr>
And I don't want to use: (unless there is no alternative)
return array( mysql_fetch_array($data) );

Your problem, as I understand it
You wish to iterate through a mysql resultset in twig, without loading the whole thing into php arrays.
What you have tried
Loading the first row into a nested array. This worked, but of course you only got the first record echoed in twig.
You're looking for a way to fetch the next row from twig, using only the array. This is not possible, because the array that you have has no connection to the mysql result pointer (besides having the data of the first record).
Possible solutions
Note that I have not tested any of the code examples.
Load the whole thing into php
If the resultset is reasonably small, like say below a 100 rows, you can just bite the bullet and load it completely into a nested array and pass that to twig. You'll have no problems iterating over it with a simple {% for %} loop like in your question.
Create a generator[docs]
This would require that you upgrade to at least php 5.5, which introduced this feature. Your code would look something like this:
return array( //I'm assuming this returns data to be passed to twig
"data" => function () use ($result) {
//$result is the returned value of mysql_query
yield mysql_fetch_row($result);
},
);
You can then do {% for row in data %} in your template.
Create an Iterator
On older versions, such as your 5.3.3, generators are not available. But that's only a shortcut to writing classes implementing the \Iterator[docs] interface. This involves some code, but you can create a generic class that you can construct using only a result pointer, and you can either foreach (in php) or for (in twig) over it, just like arrays or generators.
Switch to PDO
Depending on your project size this may be the best option (this is the one I recommend). It is very easy to start using PDO, and when you do a query it returns a \PDOStatement object, which implements \Traversable, meaning you can foreach or {% for %} over it - without writing any wrapper code. This was one of the main reasons why I switched to PDO from mysql_* (the other being prepared statements).
Create a twig extension
Just to mention this one. Probably the most involving (both time and code) solution is to create a while tag in twig, and the possibility to call mysql_fetch_* on a result pointer.

Related

How to store value from loop in liquid to display it into the variable

I am solving here issue - If the customer comes via direct url to the product, I don't get the collection name in the form(because it's not contained in the url). How can I solve this please, so that the collection listed by foor loop gets into a variable and can be displayed at the bottom.
I am trying to display the result of the loop into a variable.
the collection.title is still blank in this case because when the for cycle ends it will lost all the data.
Any solution please?
I tried to assign the result of the for loop to a variable, but it failed. I had syntax problems. I thought of assigning a collection with index [1] here. Since the index [0] contains the generic name of the collection, I need to use [1] - technically I couldn't do that.
You can do something like:
{% assign myTitle = '' %}
{% for collection in product.collections reversed offset:1 %}
{% assign myTitle = collection.title %}
{% break %}
{% endfor %}
{{ myTitle }}
Obviously, it would be a good idea to add some if statements around the assignment to make sure the correct title gets assigned and later on if myTitle is not empty but at minimum, this should do the trick. Remember that this code is going to work well if the product has only one collection but this assumption usually is wrong.
EDIT: optionally you can add a break statement like I did to break it after the first iteration so it won't get reassigned. With this code we assume that the correct title is the title of the first collection in the loop (which could not be true)

Twig - Why does it not allow us to set object / array values?

I'm extremely confused by the decision of Twig to not allow setting values of arrays and object properties via set.
For example, the following code will error out:
{% set entry.depth = 1 %}
Will result in the error:
Unexpected token "punctuation" of value "." ("end of statement block" expected)
Also the following way will also error (which I know twig doesn't prefer to use):
{% set entry['depth'] = 1 %}
So this effectively means we're unable to change properties of objects and arrays. I quite frankly find this bizarre.
Can someone please explain the decision behind this? Maybe if I get a technical reason why it's not possible it might make it less baffling.
Edit: Thanks for the solution, I was more after the reasoning behind the fact you have to use merge rather than just simply being able to override variables.
Twig's a bit weird in this regard. You'll need to use the merge filter for this.
{% set entry = entry|merge({'depth': 1}) %}

Iteration of array in Liquid

I'm using an analog of Shopify and I'm stuck with syntax of Liquid.
I need to output in the template the field with an id product[product_field_values_attributes][][value]
So I need to write a loop to get the i value of this array.
I'm confused with this empty element in the brackets.
I've looked through the examples of loop syntax in Liquid but all of those arrays are simple and they are not my case.
For example, the Title field has id product[title] and in Liquid template i call this variable product.title and it works fine.
But all my tries to write a loop for this array failed.
Please, help to write a loop to get the values of the array stated above.
Try outputting the array directly onto the page using {{ product }} or {{ product[product_field_values_attributes] }} somewhere in the HTML. That will do a JSON-like string representation of the array. From there you can figure out what the keys for the array are.
I'm not sure what you're saying about the i value. You don't reference i anywhere else in your question. If you can clarify that then we can see if something can be done about it.

How to append to multidimensional array in a smarty template?

I can append to a single array using
{append var='name' value='Bob' index='first'}
However, if I have a multi-dimensional array such as:
$name[first][last] = ['this','array']
and I want to append another value to the array at $name[first][last] e.g. to make the array like this:
$name[first][last] = ['this','array','appended']
how can I do this in the smarty template?
You can do this without using append:
{$name[first][last][] = 'this'}
{$name[first][last][] = 'array'}
{$name[first][last][] = 'appended'}
I must highlight though - templates should be used for specific purpose: to display prepared data; having to do the above is a code smell
I've tested many cases to try achieve it and I think it's not possible (in documentation there is also no info or example of multidimensional key or var)
You should also really think do you need it at all. Logic should be in PHP and role of Smarty is only displaying data not manipulating them

how to access the values of the array

I have been trying to access the values of the the array .. in the foreach loop but no luck, the first two calls get the values, but the ones in the foreach loop nothing.. comes empty although if i print the array all the values are there.
You never actually access the $dish variable in the foreach loop.
Try
$dish['Dish']['dish_name'];
instead of
$dishes['Dish']['dish_name'];
etc.
Additionally, you will get an error because the first element in your array is not a Dish, its a Dish_Category. Thus, either remove this element from the array, or use a simple if statement before you access the $dish such as:
if($dish['dish_name'])
//DO STUFF HERE
Also, there is no reason for so many
<?php ?>
tags. Couldn't you put the whole block of code in one?

Resources