I cannot access the objects properties using the Twig dot notation. For example, from looking at the object dump, I should be able to do image.copyright, which should print "Blue button near the Cayman Islands, Caribbean (© Lawson Wood/Aurora Photos)" for the first item.
The error message I get is
Method "copyright" for object "SimpleXMLElement" does not exist in ARRaiDesignBundle:Default:wallpapers.html.twig at line 12
While dumping the object using dump(image) dumps each of the objects.
Controller class:
$host = 'http://www.bing.com';
$file = $host . '/HPImageArchive.aspx?format=xml&idx=0&n=10&mkt=en-US';
$xml = simplexml_load_file($file);
return $this->render('ARRaiDesignBundle:Default:wallpapers.html.twig', array('xml' => $xml, 'host' => $host));
wallpapers.html.twig file:
...
{% for image in xml %}
<p><pre>{{ image.copyright }}</pre></p>
{% endfor %}
...
Object dump using dump(image) in Twig:
object(SimpleXMLElement)#268 (12) {
["startdate"]=>
string(8) "20130330"
["fullstartdate"]=>
string(12) "201303300000"
["enddate"]=>
string(8) "20130331"
["url"]=>
string(46) "/az/hprichbg/rb/BlueButton_EN-US1108621411.jpg"
["urlBase"]=>
string(43) "/az/hprichbg/rb/BlueButton_EN-US10208337365"
["copyright"]=>
string(77) "Blue button near the Cayman Islands, Caribbean (© Lawson Wood/Aurora Photos)"
["copyrightlink"]=>
string(74) "http://www.bing.com/search?q=Blue+Button+%28Porpita+porpita%29&form=hpcapt"
["drk"]=>
string(1) "1"
["top"]=>
string(1) "1"
["bot"]=>
string(1) "1"
...
Can anyone suggest how to do this? I know I can use PHP rendering instead of Twig, but that's not a fix for me. Thanks.
with example php doc http://www.php.net/manual/fr/simplexml.examples-basic.php
in twig, to get attribute 'type' from 'rating' item, use attributes (="#attributes") like :
{% for rating in movies.movie.rating %}
{{ rating.attributes.type }}
{% endfor %}
It seems to me that your SimpleXMLElement does not have magic methods implemented. When you call in Twig object.property - it invokes getProperty() method of your object. Try do access property directly in Twig:
{{ image['copyright'] }}
This was happening due to Bing's werid XML structure, the last bit is not iterative friendly. With standard PHP it's fine, but with Twig, it doesn't catch the errors for the last element.
<images>
<image>...</image>
<image>...</image>
<image>...</image>
<image>...</image>
<image>...</image>
<image>...</image>
<image>...</image>
<image>...</image>
<tooltips>...</tooltips>
</images>
To fix this, I just unset tooltips. "unset($xml->tooltips)"
Thanks #JaredFarrish for providing clean xml. :)
I believe you have to proxy that object. Create a new object that wraps the SimpleXMLElement object and define a getCopyright() method.
class Element
{
protected $xmlElement;
public function getCopyright()
{
return $this->xmlElement->copyright;
}
}
Related
I'm trying to retrieve the user's metadata by first calling a custom field (using advanced custom fields plugin), using array values, the problem is that I could do that using PHP, but I have to use Timber because of my theme and there's not much info out there teaching how to use Timber and ACF (using advanced custom fields), even the info available is confusing and poor. I'm using Wordpress with Gantry5 framework and Helium theme.
First I set the custom field in ACF as "relational > user", then I set the data format as User Array, save, then I open a post and setup the fields inside the post, by choosing the user of each field.
So let's say the field name is "post_autor" and I need to display it below the post, the only problem is that I need to retrieve its arrays, so this is what I've tried to find the array values:
{% set author = post.get_field("post_autor") %} then {{ dump() }}
That line of code goes here:
“themes/g5_helium/custom/views/partials/content-single.html.twig”, after this part:
{# Begin Page Content #}
{{ post.paged_content|raw }}
{{ function('wp_link_pages', {'before': '<div class="page-links" itemprop="pagination"><ul class="pagination-list">', 'after': '</ul></div>', 'link_before': '<span class="page-number page-numbers">', 'link_after': '</span>', 'echo': 0}) }}
{# End Page Content #}
And this is the result I'm getting:
then array(1) { [0]=> array(11) { ["ID"]=> int(1) ["user_firstname"]=> string(7) "John" ["user_lastname"]=> string(5) "Doe" ["nickname"]=> string(4) "john" ["user_nicename"]=> string(13) "johndoe" ["display_name"]=> string(13) "John Doe" ["user_email"]=> string(23) "contact#site.com" ["user_url"]=> string(23) "https://siteDOTcom" ["user_registered"]=> string(19) "2019-03-12 03:53:10" ["user_description"]=> string(0) "" ["user_avatar"]=> string(472) "John Doe" } }
Of course I changed some data before posting here, because it's personal data.
I believe that this tutorial https://www.advancedcustomfields.com/resources/querying-relationship-fields/ has something to do with what I'm trying to achieve, but I'm not sure.
Basically it's this:
Field name --
=> Array value 1
=> Array value 2
=> Array value 3
First I need to get the field, then retrieve its "sub" values and display them. I tried to do my best to explain this, if anyone else needs more info, just ask.
Thanks in advance.
To access elements from a 2d array you can do {{ author.user_firstname }} or if there were further level you can do {{ author.level1.level2 }}
FYI, you can still use php and then add the data to your twig files by extending the context.
For example in your single.php
// usual php stuff
$logic = some_logic_function();
// get context
$context = Timber::context();
// add to context
$context['logic'] = $logic;
// render view
Timber::render('single.twig', $context);
Then in your single.twig file you can access the data as such:
{{ logic }}
as indicated in your comment, acf fields can be accessed in much the same way as you'd access other meta properties.
if it's a repeater, it'll have multiple values, so you can loop over them (only use .meta for the 'parent' property)
code sample for template.twig:
{% if post.meta('partner_organisations')|length %}
{% for item in post.meta('partner_organisations') %}{% if item.status == "publish" %}
{{ item.name }}<br />{% endif %}
{% endfor %}
{% endif %}
here, first we make sure there's actually some values. as this is for Posts, they have a status which might be draft, so we check for a published status before displaying the linked name. if you wanted an unordered list, you'd add the <ul> tags inside the if
you can also build an array with the relevant references in your template.php before passing it over to twig.
other ways of interacting with arrays/lists in timber/twig:
{{ dump(post.meta('list_field')|first) }}
{{ post.meta('list_field')|join(', ') }}
{{ post.meta('list_field')|join(', ', ' and ') }}
documentation on nested repeaters and more is available here https://timber.github.io/docs/guides/acf-cookbook/#nested-repeater-fields
if you're looking for details specifically using a relationship field - the doc above also has info on that, as you;d want to make sure it's a Timber\Post so you can interact with its properties as usual:
{% for item in Post(post.relationship_field) %}
{{ item.title }}
{# Do something with item #}
{% endfor %}
I find this strange behaviour when using Twig (v1.23.3)
In a templace I have an array of objects : I use the dump function to display it, like this :
<pre align="left" style="text-align: left; font-size: 80%">
{{ dump(current_balances) }}
</pre>
{% for key, val in current_balances %}
{{ val.name }} : {{ val.balance | number_format(2, '.', ' ') }} €<br>
{% else %}
Aucun solde trouvé.
{% endfor %}
The output of dump is as expected :
array(2) {
[0]=>
object(Record)#20 (3) {
["name"]=>
string(32) "Bank 1 - Account"
["balance"]=>
string(7) "2000.00"
}
[1]=>
object(Record)#21 (3) {
["name"]=>
string(32) "Bank 2 - Account"
["balance"]=>
string(8) "1000.00"
}
}
But the output of the for loop is not correct. {{ val.name }} is displayed, but {{ val.balance }} is empty.
I dit this kind of loops hundreds of time - this code is merely cut-and-paste from a template that works.
Event more curious is that, if I invert the order of the vars in the object (as is it matters), putting balance before name, then balance is displayed, and not name !
Don't really know where to look with this one. Of course, my template are rendered with controllers calling models, so this is only a little part of the code.
I think I found a bug, similar to Variables not replaced in Twig template but it's hard to tell.
That's not a bug ! I finally enable the cache in Twig and looked at the resulting code. Guess what ? Some non-printable char has find its way near the val.balance. A "cat -A" on the template file shows this :
{{ val.name }} : {{M-BM- val.balance }} M-bM-^BM-,<br>$
And result in this in the compiled template :
$this->getAttribute((isset($context[" val"]) ? $context[" val"] : null)
Noticed the space before val ?
Lost one hour with this one. Source problem is an obsolete frenck keymap in Debian....
I know there are many questions on this topic, but none quite deal with this (as far as I could see).
I have a PHP array (which FYI, is returned via Guzzle response) in a Laravel Project.
The PHP array
$users = array(2) {
["error"]=>
bool(false)
["spirits"]=>
array(2) {
[0]=>
array(2) {
["id"]=>
string(1) "1"
["name"]=>
string(5) "Foo"
}
[1]=>
array(2) {
["id"]=>
string(1) "2"
["name"]=>
string(3) "Bar"
}
}
}
I simply want to extract the "id" and "name" keys below, to use in a view but I'm a little stumped. I've tried the suggestions below, but can't quite work it out.
How to Flatten a Multidimensional Array?
PHP foreach with Nested Array?
I've also looked into array_walk_recursive.
Any help would be awesome and appreciated! I want to be able to use these 2 keys in Laravel like so:
Controller
return View::make('users')->with('users',$users);
View
#foreach ($users as $key => $user)
{{ $user["id"] }}
{{ $user["name"] }}
#endforeach
You may try this:
#foreach ($users['spirits'] as $user)
{{ $user["id"] }}
{{ $user["name"] }}
#endforeach
It's better to check the returned result in your controller before you send it to the view using something like this so there will be no errors in your view:
$users = 'Get it from somewhere...';
if(!$users['error']) {
return View::make('users')->with('users', $users);
}
else {
// Show an error with a different view
}
in case your users are always stored in the spirits-key of your $users variable you simply could modify your #foreach-loop as follow:
#foreach ($users['spirits'] as $user)
{{ $user['id'] }}
{{ $user['name'] }}
#endforeach
Otherwise you could edit your return value from the controller. That means you simply could change the line:
return View::make('users')->with('users',$users);
to
return View::make('users')->with('users',$users['spirits']);
In this case you don't have access to your error-key.
I have been looking around for a way of doing this. I know it is possible to store an array in the session with the following: Session::push('user.teams', 'developers');
Is it possible to do the same but with flash data? Something like Session::flashpush('user.teams', array('developers', 'designers')); would be great.
The usecase for me at this moment is primarily the following:
Session::flash('flash_message', $validator->messages());
As far as I know, you can do it. I've checked this just in case:
Session::flash('test', array('test1', 'test2', 'test3'));
... After the request
dd(Session::get('test'));
// array(2) { [0]=> string(5) "test1" [1]=> string(5) "test2" [2]=> string(5) "test3" }
It works. Also you can serialize an array or object as Christopher Morrissey just commented
I use this:
Session::flash($key, array_merge((array)Session::get($key), array($value)));
I created this helper class:
<?php
class Flash {
public static function push($key, $value) {
$values = Session::get($key, []);
$values[] = $value;
Session::flash($key, $values);
}
}
It allows you push multiple items to the same key such that it always return an array when fetched.
Usage:
Flash::push('success','Feature saved');
Twig template (Blade shouldn't be too much different):
{% if session_has('success') %}
<div class="alert alert-block alert-success fade in">
<button class="close" data-dismiss="alert">×</button>
{% for msg in session_get('success') %}
<p><i class="fa-fw fa fa-check"></i> {{ msg }}</p>
{% endfor %}
</div>
{% endif %}
In your scenario, you would probably use it like this:
Flash::push('flash_message', 'user.teams');
Flash::push('flash_message', 'developers');
Laravel 8
This is the most efficient way I've found using the latest version of Laravel if you want to store info input by the user as an array and then pull it separately. I'm using for a Madlibs app.
$req->session()->put([
'adj1' => $req->input('adj1'),
'noun1' => $req->input('noun1'),
'place' => $req->input('place'),
]);
return $req->session()->flash('test',
array('adj1', 'noun1', 'place',
));
I hope this helps a future users.
I am trying to add pairs of key value to an array with their current values for all those attributes not starting by '_'. For some reason, the merge replaces the value of "key" (i.e slug) with the string 'key'.
For example when slug is the only attribute with key not starting with '_',
key = slug
value = something
it behaves as follows:
{% for key,value in app.request.attributes.all %}
{% if '_' != key | slice(0, 1) %}
{{ dump(key) }} // string(4) "slug"
{% set params = params | merge({ key : value}) %}
{{ dump(key) }} // string(4) "slug"
{% endif %}
{% endfor %}
{{ dump(params) }} // array(1) { ["key"]=> string(9) "something" }
I have added what the dumps return next to them.
The final dump returns
array(1) { ["key"]=> string(9) "something" }
while i'm expecting
array(1) { ["slug"]=> string(9) "something" }
I'd say it's a similar problem to Twig forgets array-keys but the conclusion on that question is that is a mongodb problem and I am not using it. I am working with attributes from the request.
For some reason, the merge({ key : value}) is behaving as merge({ 'key' : value}).
You need to wrap your variable with parenthesis to be able to use it as a key.
{% set params = params | merge({ (key) : value}) %}
With numeric keys you can lose your key in the process, with the m̀erge`filter.
I couldn't find any documentation about the '+' operator applied with arrays, but it works well in this case:
{% set array = {(1): 2} + array %}
Source: https://github.com/twigphp/Twig/issues/2741#issuecomment-417445042