Accessing value of iterated field in Mustache PHP - php

Say I have an array in PHP that looks like so:
$values = Array(
'0' => 'value1',
'1' => 'value2',
'2' => 'value3'
)
I'd like to iterate through the array using Mustache but I'd like the associated value. This is what I'm hoping to do:
{{#values}}
{{the current value}}
{{/values}}
I hope there returned result would be:
value1
value2
value3
I've been getting around this by changing my structure to:
$values = Array(
'0' => array('value=' =>'value1'),
'0' => array('value=' =>'value2'),
'0' => array('value=' =>'value3'),
)
And call {{valule}} inside the Mustache iterator.
Should I be doing this a completely different way? I'm using a SplFixedArray in PHP and I'd like to iterate through the values using this method...
Thanks!

The implicit Iterator is the way to go for simple data. If your data is more complex then PHPs ArrayIterator does the job well.
Here is an example that I have working. Hope it is useful for somebody else.
$simple_data = array('value1','value2','value3');
$complex_data = array(array('id'=>'1','name'=>'Jane'),array('id'=>'2','name'=>'Fred') );
$template_data['simple'] = $simple_data;
$template_data['complex'] = new ArrayIterator( $complex_data );
$mustache->render('template_name', $template_data );
And in the template you could have
{{#simple}}
{{.}}<br />
{{/simple}}
{{#complex}}
<p>{{ id }} <strong>{{ name }}</strong></p>
{{/complex}}

You can use the implicit iterator feature of mustache for this:
https://github.com/bobthecow/mustache.php/tree/master/examples/implicit_iterator
{{#values}}
{{.}}
{{/values}}
Your original array probably needs numeric keys and now string though. It might work that way, but I haven't tested it.

I was working on a super old php framework, which was using smarty like syntax but double curly braces, kept me hanging for quite sometime, so the following made the loop run for me :) maybe it will help you too.
{{ #each link in bluelinks }}
<p><strong>{{ link }}</strong></p>
{{/each}}

Related

How to implement array_filter() to make more clear

I need a little help in the PHP, because I'm trying to use the array_filter() to prevent to many lines and make it simply and clear, but I'm struggling in this one, even if I'm reading this documentation: Array_Filter so I need a correct way to implement, because sometimes the getCategoryTree() comes empty or with null values, which I'm trying to not show it, I thought to create other function to show only specific things without category, but I feel that it is not efficient:
What I'm trying is to populate from the url www.foobar.com/checkout/payments, and this is the original code:
$page['eData'] = [
'codeMoneyFormatter' => $this->moneyFormatter->getcodeMoneyFormatter(),
'checkout' => [
'actionField' => ['step' => 3, 'option' => 'Review Order'],
// ---------------- THIS ONE MUST REFACTOR -------
'products' => $this->getCartFromOrder($order),
],
];
// --------------------- REFACTOR ------------------
$itemData['category'] = $category ? $this->getCategoryTree($category->getId()) : '';
// -------------------------------------------------
This function is where it shows the category, but I don't like it because at all, because in some pages it comes empty/null which it's not correct, so I want to use the array_filter()
// --------------------- ARRAY_FILTER ------------------
$itemData['category'] = array_filter($category ? $this->getCategoryTree($category->getId()) : '');
// -------------------------------------------------
The function that I created to show only specific thing, it's correct because it does not show the category, but I feel that it's unnecessary because its repeating the same from the original one:
$page['eData'] = [
'codeMoneyFormatter' => $this->moneyFormatter->getcodeMoneyFormatter(),
'checkout' => [
'actionField' => ['step' => 3, 'option' => 'Review Order'],
'products' => $this->getCheckoutFromOrder($order),
],
];
It's repeating almost the same functions and it's not the correct standard of DRY (Don't repeat yourself) that's why I thought to implement the array_filter() but how???
Array_Filter so I need a correct way to implement, because sometimes the getCategoryTree() comes empty or with null values
Easy, don't change types and feed array filter something it shouldn't eat.
array_filter($category ? $this->getCategoryTree($category->getId()) : '');
Should be (something like)
$data = $category ? $this->getCategoryTree($category->getId()) : [];
if(!is_array($data)) $data = [];
array_filter($data);
You can probably do it simpler then this. But, type changes in PHP can be troublesome because the language is loosely typed and won't complain to much.
This can be easly tested
var_dump(array_filter(''));
output
<br />
<b>Warning</b>: array_filter() expects parameter 1 to be array, string given in <b>[...][...]</b> on line <b>3</b><br />
NULL
Sandbox
This on the other hand
var_dump(array_filter([]));
Simply returns an empty array.
The last thing I will say is about 80% of the code you put in the question was unnecessary to answer the question and just serves to confuse other users.

Laravel - Cannot Access Collection Indexes

For sure it's an understanding issue on my part. I'm just trying to create a collection in which the elements can be output.
Example:
So I want to be able to execute:
$collection=collect([
'index1' => 'data1',
'index2' => 'data2',
'index3' => 'data3',
]);
$row=$collection->first();
dd($row->index1);
Or similar.. But I get the error
trying to get property of a non object.
It's an understanding issue about Laravel collections, I've read the Laravel documentation which goes from basic usage, to API reference. I cannot find the information on how to produce this basic static collection.
Can someone help?
$row=$collection->first(); points to the value data1, not an object/array.
To get the expected behavior try the code below, it wraps each in individual arrays.
$collection=collect([
['index1' => 'data1'],
['index2' => 'data2'],
['index3' => 'data3'],
]);
$row=$collection->first();
dd($row->index1);
As Laravel collections implement ArrayAccess you can simply access collection items as you do with an array
$value = $collection['index1'];
or you can use the get method on collections
$value = $collection->get('index1');
Thanks for your answers, I see the $collection['index1']; format works.
It's not exactly what I wanted, let me explain why. I know there's probably a better way of doing it although, for the sake of this particular coding requirement I'd like to know the answer to this.
I'm building a CRUD blade form.
On my blade I'll have 'field1' with initial output of $dbcollection->field1
Now of course if the database returns a null (create required) this output will fail. So what I'm trying to do here is pass blade a NULL-filled collection it understands so at least it doesn't complain about non instance of an object and avoiding #if statements on the blade form to account for differences in coding format.
I believe this is what you are looking for:
Controller:
$collection=collect([
'index1' => 'data1',
'index2' => 'data2',
'index3' => 'data3',
]);
$row = $collection->first();
view:
<input type="text" value="{{ ($row->index1 ? $row->index1 : '') }}" >
.
.
.
.

Associative array of arrays

Ive come upon the following code and having trouble deciphering its use.
(changed up the variable names a bit for simplicity)
$fooo = array(
'dog' => array('pages', 'home'),
'cat' => array('users', 'login'),
'bird' => array('users', 'reset', 1),
);
I am familiar with associative arrays but have not seen this "nested array" implementation before.
Is this code creating an array of arrays?
For example, $fooo['dog'] returns an array where $dog[0]='pages' and $dog[1]='home'
That seems wrong.
Yes, this is an array of arrays. But it perhaps may be more accurate to describe it as an associative array with an indexed array for every value.
The following can be done with it:
$fooo['dog'] // gets array("pages", "home")
$fooo['bird'][0] // gets "users"
$fooo['cat'][1] // gets "login"
$fooo['cow'] = array('x', 'y'); // adds another value to the outer array
$fooo['bird'][] = 2; // $fooo['bird'] now equals array('users', 'reset', 1, 2)
There is nothing wrong with this code, but your example is lacking practicality. There is plenty of code that uses such structures though. For example, a logical representation of a menu with sub-menus on a website (which seems like the source of your sample), this data structure can then be looped to generate an HTML/CSS menu.

array of required twig variables in symfony

If there any way to discover the variables required from a Twig template? Example, if I had:
Hello {{ user }}! You're {{ age }} years old, well done big man!
I'd be able to load this template and then gather each of the required variables, eventually allowing me to have something like:
Array ( [0] => user [1] => age )
The end goal of this is to be able to define a view and then have the system create a form based on the required variables in a template file.
Working Solution
Thanks to morg for pointing me towards tokenize I was able to get what I wanted using the following (I placed it in my controller for testing):
$lexer = new \Twig_Lexer(new \Twig_Environment());
$stream = $lexer->tokenize(new \Twig_Source('{{test|raw}}{{test2|raw|asd}}{{another}}{{help_me}}', null));
$variables = array();
while (!$stream->isEOF()) {
$token = $stream->next();
if($token->getType() === \Twig_Token::NAME_TYPE){
$variables[] = $token->getValue();
while (!$stream->isEOF() && $token->getType() !== \Twig_Token::VAR_END_TYPE) {
$token = $stream->next();
}
}
}
$variables = array_unique($variables);
This returns:
Array
(
[0] => test
[1] => test2
[2] => another
[3] => help_me
)
You'll notice I only get variables and not any of the functions (this is through design), although you could remove the nested while loop if you wish to get both variables and functions.
You can use the twig tokenizer for this.
$stream = $twig->tokenize($source, $identifier);
The tokenizer has a toString() Method, whose resulting string you can parse for
VAR_START_TYPE()
NAME_TYPE(varname)
VAR_END_TYPE()
Look at this for more detailed information.
You can try using preg_match_all('{{\s*(\w+)\s*}}', 'template {{string }} with {{ var}}', $matchesArray);. The $matchArray is structured as following:
Array(
0 => array(0 => '{{string }}', 1 => 'string'),
1 => array(0 => '{{ var}}', 1 => 'var')
)
Another way of doing this from inside PHP code is not elegant, but still more reliable than any regex will be:
$source = "My template string with {{ some }} parameters.";
$stream = $twig->tokenize(new \Twig_Source($source, "source"));
$matches = [];
preg_match_all(
"/NAME_TYPE\((.*)\)/", $stream->__toString(), $matches
);
if (count($matches) > 1) {
$params = array_unique($matches[1]);
} else {
$params = [];
}
This works by using Twig internal mechanisms to tokenize the template string and then extract parameters names with a regex.
Edit: The previous version of my answer used the parse method to create a tree of nodes, but it didn’t seem to work anymore, and matching on NAME_TYPE at the previous step seems more reliable, not sure if I missed something there…

PHP : Formatting multiple arrays for database (laravel)

I've got this input form: (Using the blade template engine with Laravel, but the html should be easy to understand from this and ultimately trivial)
{{ Form::text('amount[]', Input::old('amount')) }}
<?php echo Form::select('unit[]',
array(
'whole' => _('whole'),
'ml' => _('milliliter'),
'l' => _('liter'),
'dl' => _('deciliter'),
'mg' => _('milligram'),
'g' => _('gram'),
'kg' => _('kilogram'),
'tsp' => _('teaspoon'),
'tbs' => _('tablespoon'),
)) ?>
{{ Form::text('ingredient[]', Input::old('ingredient')) }}
I'm trying to format this to my database to return it in a string like this :
<li><span>1</span> liter red wine</li>
I'm considering making it a simpler form and eliminating the unit measurement forcing my users to type it in instead for flexibility, but I'll still have to cramp it all into one table for my database. The span tag is used in a jQuery to dynamically increase the number so is needed. I've been at this for quite a few days on and off but I can't crack how to do this.
Here is my formatting logic:
$amount = Input::get('amount[]');
$unit = Input::get('unit[]');
$ingredient = Input::get('ingredient[]');
for ( $i = 0, $c = count(Input::get('ingredient[]')); $i < $c; $i++ )
{
$ingredients .= '<li><span>'.$amount[$i].'</span>'.$unit[$i].' '.$ingredient[$i].'</li>';
}
and I send it using
$new = Recipe::create(array(
'title' => Input::get('title'),
'curiousity' => Input::get('curiousity'),
'ingredients' => $ingredients,
'steps' => Input::get('recipe')
));
I've tried numerous ways and I get errors like the $ingredients array not being defined or not being able to use [] in the variable. I tried defining the variable as an '$ingredients = '';' variable but that just produced an empty string. My problem must be in the logic.
Build your select list outside the form for brevity as well as (what I do anyway to keep controllers very slim) send the input to the model all at once.
$input = Input::all();
$new = Recipe::create($input);
Build the array for the ingredients elsewhere. In the model (perhaps?):
$ingredients = array(
'dbname1' => 'displayname1',
'dbname2' => 'displayname2'
);
And display it accordingly, then the form inputs should be sent over with the $input in an array that you can parse and then save to your db.
Other notes about Blade syntax. I'm not aware of a need to define the array brackets [].
{{Form::open()}}
{{Form::label('label1','Display Label 1')}}
{{Form::text('fieldname1',Input::old('fieldname1'))}}
With your ingredients array already built (your current syntax will produce a dropdown and I assume you want checkboxes)
{{Form::select('ingredientsFIELDNAME',$ingredients)}}
{{Form::close()}}
In your Input::all() array your ingredientsFIELDNAME field name will have an array if you've built it as checkbox instead of select. Hope this all makes sense.

Categories