XML array with 2 href attributes - php

I have the following XML array:
["link"]=>
array(2) {
[0]=>
object(SimpleXMLElement)#311 (1) {
["#attributes"]=>
array(3) {
["type"]=>
string(9) "text/html"
["href"]=>
string(48) "http://twitter.com/bob/statuses/1226112723"
["rel"]=>
string(9) "alternate"
}
}
[1]=>
object(SimpleXMLElement)#312 (1) {
["#attributes"]=>
array(3) {
["type"]=>
string(9) "image/png"
["href"]=>
string(59) "http://a3.twimg.com/profile_images/226895523/Dan_normal.png"
["rel"]=>
string(5) "image"
}
}
}
It's inside a bigger array, I need to get the first and second hef attribute seperatly so that I can put one href as a <a> link and another with a <img>.
How can I output each href rather than both together?
Currently trying this:
foreach($entry->link as $link) {
echo $link->attributes()->href;
}

$url = 'http://api.twitter.com/1/favorites/bob.atom';
$feed = simplexml_load_file($url);
$testStop = 0;
foreach($feed->entry as $entry) {
echo 'title: ', $entry->title, "\n";
// store all link/#href in a hashtable
// so you can access them in any order you like
// without resorting to xpath or alike.
$links = array();
foreach($entry->link as $link) {
$links[(string)$link['rel']] = (string)$link['href'];
}
if ( isset($links['image']) ) {
echo '<img src="', $links['image'], '" />', "\n";
}
if ( isset($links['alternate']) ) {
echo '<a href="', $links['alternate'], '" />alternate</a>', "\n";
}
echo "----\n";
if ( 2 < ++$testStop ) die;
}
(currently) prints
title: kolchak: Sometimes I think I need a new butler. But then it's like "Nah, he's still got one thumb. We good."
<img src="http://a1.twimg.com/profile_images/668496250/Picture_14_normal.jpg" />
<a href="http://twitter.com/kolchak/statuses/10648055680" />alternate</a>
----
title: shitmydadsays: "War hero? No. I was a doc in Vietnam. My job was to say "This is what happens when ."
<img src="http://a3.twimg.com/profile_images/362705903/dad_normal.jpg" />
<a href="http://twitter.com/shitmydadsays/statuses/10580558323" />alternate</a>
----
title: shitmydadsays: "I lost 20 pounds...How? I drank bear piss and took up fencing. How the you think, son? I exercised."
<img src="http://a3.twimg.com/profile_images/362705903/dad_normal.jpg" />
<a href="http://twitter.com/shitmydadsays/statuses/10084782056" />alternate</a>
----
But you might also be interested in xsl(t)

You can access the href attributes using normal array/object access. Just store them in an array for later use:
$hrefs = array();
foreach($array['links'] as $links) {
foreach($links->attributes as $key>=$value) {
if('href' == $key) {
$hrefs[] = $value;
}
}
}
// $href[0] = "http://twitter.com/bob/statuses/1226112723"
// $href[1] = "http://a3.twimg.com/profile_images/226895523/Dan_normal.png"
This makes use of SimpleXMLElement's attributes() method.
I don't think that you can access the attributes directly ($elment->#attributes) as this is not a valid syntax.

First href - $xml['link'][0]->attributes()->href
Second href - $xml['link'][1]->attributes()->href

Related

How to echo data from a Multi-Dimensional Array in PHP?

I need to echo/return the data to the page like this:
Catalog: 251-2010
Gauge: 20g
Length: 10cm
Tip Size: 10mm
Here is the array called $vararray. It contains several different arrays of product variation data:
array(3) {
[0]=> array(1) {
["251-2010"]=> array(1) {
["Gauge"]=> string(3) "20g"
}
}
[1]=> array(1) {
["251-2010"]=> array(1) {
["Length"]=> string(4) "10cm"
}
}
[2]=> array(1) {
["251-2010"]=> array(1) {
["Tip Size"]=> string(4) "10mm"
}
}
}
array(3) {
[0]=> array(1) {
["600-VR1620"]=> array(1) {
["Chart Type"]=> string(14) "Shirt"
}
}
[1]=> array(1) {
["600-VR1152"]=> array(1) {
["Chart Type"]=> string(13) "Trousers"
}
}
[2]=> array(1) {
["600-VR16211"]=> array(1) {
["Chart Type"]=> string(13) "Socks"
}
}
}
I need something like this:
$vargroup = array();
foreach ($vararray as $vitems) {
$varmeta = array_values($vararray);
foreach ($varmeta as $metain => $vardetails) {
vargroup[$metain]['catalog'] = $vardetails['Catalog'];
vargroup[$metain]['gauge'] = $vardetails['Gauge'];
vargroup[$metain]['length'] = $vardetails['Length'];
vargroup[$metain]['tipsize'] = $vardetails['Tip Size'];
}
$vars_profile = '';
foreach ($vargroup as $vgrp) {
$vars_profile .= $vgrp[catalog] . '<br>' . $vgrp[gauge] . '<br>' . $vgrp[length] . '<br>' . $vgrp[tipsize];
}
}
return $vars_profile;
I'm having a lot of trouble getting it right. Here is how I need it to look:
Catalog: 251-2010
Gauge: 20g
Length: 10cm
Tip Size: 10mm
Catalog: 600-VR1620
Chart Type: Shirt
Catalog: 600-VR1152
Chart Type: Trousers
Catalog: 600-VR16211
Chart Type: Socks
You can't get all of Catalog, Gauge, Length, and Tip Size from the same $vardetails element, they're in different elements of the array. You need to drill into each element to get its key and value.
You can create $vars_profile in the loop that's processing the original array, you don't need $vargroup.
To show the category only once, use a variable to hold the last value. Only output the category line when this field changes.
$vars_profile = '';
$last_metain = null;
foreach ($vararray as $vitem) {
foreach ($vitem as $metain => $vardetails) {
if ($metain != $last_metain) {
$vars_profile .= "<p>\nCatalog: $metain<br>\n";
$last_metain = $metain;
}
foreach ($vardetails as $key => $value) {
$vars_profile .= "$key: $value<br>\n";
}
}
}
return $vars_profile;

Advanced PHP loop

I get translations from database and want to get generate it in Javascript object, like:
var Lang = {
eng: {
txtUserName: 'Username',
txtLogout: 'Logout'
},
dnk: {
txtUserName: 'Brugernavn',
txtLogout: 'Afslut'
}
}
I got stuck in loops, the result I get is not what I need.
This is my PHP:
var Lang = {
<?php
$allLangs = $this->params->getLanguages;
foreach ($allLangs as $allLang) :
echo $allLang->lang_code . ': ';
echo '{';
foreach ( $translationsall as $translation ) :
if ( $translation['it_text'] == 'txtUserName' ) :
for ( $i = 1; $i <= 1; $i++ ){
var_dump($translationsall[$i]);
}
endif;
endforeach;
echo '},';
echo "\r\n";
endforeach;
?>
}
And this is what I get:
var Lang = {
dnk: {array(2) {
["it_text"]=>
string(8) "appTitle"
["it_name"]=>
string(3) "VMS"
}
array(2) {
["it_text"]=>
string(8) "appTitle"
["it_name"]=>
string(3) "VMS"
}
},
eng: {array(2) {
["it_text"]=>
string(8) "appTitle"
["it_name"]=>
string(3) "VMS"
}
array(2) {
["it_text"]=>
string(8) "appTitle"
["it_name"]=>
string(3) "VMS"
}
}
How can I edit my loops to get result I need?
Maybe there is a smarter way to generate Lang object?
And, forgot to mention that I need only few translations, that's why I have this in PHP if:
if ( $translation['it_text'] == 'txtUserName' ) :
//stuff
endif;
Any ideas are welcome :)
And this what I get from var_dump($translationsall):
array(2748) {
[0]=>
array(2) {
["it_text"]=>
string(8) "appTitle"
["it_name"]=>
string(3) "CMS"
}
[1]=>
array(2) {
["it_text"]=>
string(8) "appTitle"
["it_name"]=>
string(3) "CMS"
}
[2]=>
array(2) {
["it_text"]=>
string(9) "txtLogout"
["it_name"]=>
string(6) "Afslut"
}
[3]=>
array(2) {
["it_text"]=>
string(9) "txtLogout"
["it_name"]=>
string(6) "Logout"
}
[4]=>
array(2) {
["it_text"]=>
string(10) "btnRefresh"
["it_name"]=>
string(9) "Hent Igen"
}
[5]=>
array(2) {
["it_text"]=>
string(10) "btnRefresh"
["it_name"]=>
string(7) "Refresh"
}
}
Please, don't do this. - Make an API call to a PHP backend producing the data you need. - Using either out of the box functions such as $.ajax from jQuery or other prebuilt frameworks will help you achieve this.
If you still want to go down the line of dynamically doing this (your question) - remove var_dump - which is ultimately dumping the type and other details (as it should) and use foreach (key, value) which will help you generate what you need. - But rather going down this dodgy route I'd recommend you take a look at how to serve an API using Laravel or other frameworks.
You could pass data from PHP to JS with JSON.
From PHP, you can use json_encode():
echo json_encode($translation);
And in your JS use JSON.parse():
var obj = JSON.parse('{"key":value}');
You can then do:
<?php
$allLangs = $this->params->getLanguages;
$json = json_encode($allLangs);
?>
<script>
var Lang = JSON.parse('<?php echo $json; ?>');
</script>
As others here have already mentioned; it is a bad idea to dynamically create your javascript like this - I would instead use JSON to serialize and deserialize the data. Anyway, if you insist on dynamic creation; it'll probably be something along the lines of;
var Lang = {
<?php
$allLangs = $this->params->getLanguages;
foreach ($allLangs as $allLang) {
echo $allLang->lang_code . ': {';
foreach ( $translationsall as $translation ) {
$total_words_to_translate = count($translation);
for($i = 0; i <= $total_words_to_translate; $i++){
if ( $translation['it_text'] == 'txtUserName' ){
print("txtUserName: ".$translationsall[$i]);
}
if ( $translation['it_text'] == 'txtLogout' ){
print("txtLogout: ".$translationsall[$i]);
}
}
}
echo '},';
echo "\r\n";
}
?> }
Its somewhat hard to determine the exact code when we don't know the structure / naming conventions of your database / variables.
Use json_encode:
var Lang = <?php
$all_langs = $this->params->getLanguages();
echo json_encode($all_langs);
?>;
Not sure how close I am with the data definitions, but I've included them so you can see what I'm assuming and hopefully be able to adjust it to your needs.
The way it works is that it starts at the beginning of $translationsall array and assumes that the $allLangs array is in the same order as the entries ( so in this case the dnk and then the eng values). These it then populates into the output under the language key, with it_text as the key and it_name as the translation.
$translationsall = [["it_text" => "txtLogout", "it_name"=>"Afslut"],
["it_text"=> "txtLogout", "it_name"=> "Logout"],
["it_text" => "txtLogout2", "it_name"=>"Afslut2"],
["it_text"=> "txtLogout2", "it_name"=> "Logout2"]
];
$allLangs = [ (object)["lang_code"=> "dnk"], (object)["lang_code"=> "eng"] ];
$countTrans = count($translationsall);
$out = [];
$i = 0;
while( $i < $countTrans ) {
foreach ( $allLangs as $language ) {
$out[$language->lang_code][$translationsall[$i]["it_text"]] = $translationsall[$i]["it_name"];
$i++;
}
}
echo json_encode($out, JSON_PRETTY_PRINT);
This prints out
{
"dnk": {
"txtLogout": "Afslut",
"txtLogout2": "Afslut2"
},
"eng": {
"txtLogout": "Logout",
"txtLogout2": "Logout2"
}
}
You can try with echo see bellow code :
var Lang = {
<?php
$allLangs = $this->params->getLanguages;
foreach ($allLangs as $allLang) :
echo $allLang->lang_code . ': ';
echo '{';
foreach ( $translationsall as $translation ) :
if ( $translation['it_text'] == 'txtUserName' and $translation['itl_lang_code '] == $allLang->lang_code) :
echo "txtUserName:'".$translation['it_text']."',txtLogout:'".$translation['it_name']."' ";
endif;
endforeach;
echo '}';
echo '},';
echo "\r\n";
endforeach;
?>
}

Getting a specific value from multi-dimensional array [duplicate]

I have a multidimensional array like this:
array(2) {
[1]=>
array(3) {
["eventID"]=>
string(1) "1"
["eventTitle"]=>
string(7) "EVENT 1"
["artists"]=>
array(3) {
[4]=>
array(2) {
["name"]=>
string(8) "ARTIST 1"
["description"]=>
string(13) "artist 1 desc"
["links"]=>
array(2) {
[1]=>
array(2) {
["URL"]=>
string(22) "http://www.artist1.com"
}
[6]=>
array(2) {
["URL"]=>
string(24) "http://www.artist1-2.com"
}
}
}
[5]=>
array(2) {
["name"]=>
string(8) "ARTIST 8"
["description"]=>
string(13) "artist 8 desc"
["links"]=>
array(1) {
[8]=>
array(2) {
["URL"]=>
string(22) "http://www.artist8.com"
}
}
}
[2]=>
array(2) {
["ime"]=>
string(8) "ARTIST 5"
["opis"]=>
string(13) "artist 5 desc"
["links"]=>
array(1) {
[9]=>
array(2) {
["URL"]=>
string(22) "http://www.artist5.com"
}
}
}
}
}
[2]=>
array(3) {
["eventID"]=>
string(1) "2"
["eventTitle"]=>
string(7) "EVENT 2"
["artists"]=>
array(3) {
[76]=>
array(2) {
["name"]=>
string(9) "ARTIST 76"
["description"]=>
string(14) "artist 76 desc"
["links"]=>
array(1) {
[13]=>
array(2) {
["URL"]=>
string(23) "http://www.artist76.com"
}
}
}
[4]=>
array(2) {
["name"]=>
string(8) "ARTIST 4"
["description"]=>
string(13) "artist 4 desc"
["links"]=>
array(1) {
[11]=>
array(2) {
["URL"]=>
string(22) "http://www.artist4.com"
}
}
}
}
}
}
I would like to make html output like this:
--
EVENT 1
ARTIST 1
artist 1 desc
http://www.artist1.com, http://www.artist1-2.com
ARTIST 8
artist 8 desc
http://www.artist8.com
ARTIST 5
artist 5 desc
http://www.artist5.com
--
EVENT 2
ARTIST 76
artist 76 desc
http://www.artist76.com
ARTIST 4
artist 4 desc
http://www.artist4.com
--
etc.
I'm confused about digging deeper and deeper in arrays, especially when my array keys are not sequential numbers but IDs of artist/link/etc.
These arrays will kill me, honestly! =)
Thanks for any help in advance!!!
You're best using the foreach construct to loop over your array. The following is untested and is off the top of my head (and probably therefore not as thought through as it should be!) but should give you a good start:
foreach ($mainArray as $event)
{
print $event["eventTitle"];
foreach ($event["artists"] as $artist)
{
print $artist["name"];
print $artist["description"];
$links = array();
foreach ($artist["links"] as $link)
{
$links[] = $link["URL"];
}
print implode(",", $links);
}
}
The foreach statement will take care of all of this for you, including the associative hashes. Like this:
foreach($array as $value) {
foreach($value as $key => $val) {
if($key == "links") {
}
/* etc */
}
}
I think a good way to approach this is "bottom up", ie. work out what to do with the inner-most values, then use those results to work out the next-level-up, and so on until we reach the top. It's also good practice to write our code in small, single-purpose, re-usable functions as much as possible, so that's what I'll be doing.
Note that I'll assume your data is safe (ie. it's not been provided by a potentially-malicious user). I'll also assume that the keys "ime" and "opi" are meant to match the "name" and "description" of the other arrays ;)
We can ignore the innermost strings themselves, since we don't need to modify them. In that case the inner-most structure I can see are the individual links, which are arrays containing a 'URL' value. Here's some code to render a single link:
function render_link($link) {
return "<a href='{$link['URL']}'>{$link['URL']}</a>";
}
This has reduced an array down to a string, so we can use it remove the inner-most layer. For example:
// Input
array('URL' => "http://www.artist1.com")
// Output
"<a href='http://www.artist1.com'>http://www.artist1.com</a>"
Now we move out a layer to the 'links' arrays. There are two things to do here: apply "render_link" to each element, which we can do using "array_map", then reduce the resulting array of strings down to a single comma-separated string, which we can do using the "implode" function:
function render_links($links_array) {
$rendered_links = array_map('render_link', $links_array);
return implode(', ', $rendered_links);
}
This has removed another layer, for example:
// Input
array(1 => array('URL' => "http://www.artist1.com"),
6 => array('URL' => "http://www.artist1-2.com"))
// Output
"<a href='http://www.artist1.com'>http://www.artist1.com</a>, <a href='http://www.artist1-2.com'>http://www.artist1-2.com</a>"
Now we can go out another level to an individual artist, which is an array containing 'name', 'description' and 'links'. We know how to render 'links', so we can reduce these down to a single string separated by linebreaks:
function render_artist($artist) {
// Replace the artist's links with a rendered version
$artist['links'] = render_links($artist['links']);
// Render this artist's details on separate lines
return implode("\n<br />\n", $artist);
}
This has removed another layer, for example:
// Input
array('name' => 'ARTIST 1',
'description' => 'artist 1 desc',
'links' => array(
1 => array(
'URL' => 'http://www.artist1.com')
6 => array(
'URL' => 'http://www.artist1-2.com')))
// Output
"ARTIST 1
<br />
artist 1 desc
<br />
<a href='http://www.artist1.com'>http://www.artist1.com</a>, <a href='http://www.artist1-2.com'>http://www.artist1-2.com</a>"
Now we can move out a layer to the 'artists' arrays. Just like when we went from a single link to the 'links' arrays, we can use array_map to handle the contents and implode to join them together:
function render_artists($artists) {
$rendered = array_map('render_artist', $artists);
return implode("\n<br /><br />\n", $rendered);
}
This has removed another layer (no example, because it's getting too long ;) )
Next we have an event, which we can tackle in the same way we did for the artist, although I'll also remove the ID number and format the title:
function render_event($event) {
unset($event['eventID']);
$event['eventTitle'] = "<strong>{$event['eventTitle']}</strong>";
$event['artists'] = render_artists($event['artists']);
return implode("\n<br />\n", $event);
}
Now we've reached the outer array, which is an array of events. We can handle this just like we did for the arrays of artists:
function render_events($events) {
$rendered = array_map('render_event', $events);
return implode("\n<br /><br />--<br /><br />", $rendered);
}
You might want to stop here, since passing your array to render_events will give you back the HTML you want:
echo render_events($my_data);
However, if we want more of a challenge we can try to refactor the code we've just written to be less redundant and more re-usable. One simple step is to get rid of render_links, render_artists and render_events since they're all variations on a more-general pattern:
function reduce_with($renderer, $separator, $array) {
return implode($separator, array_map($renderer, $array));
}
function render_artist($artist) {
$artist['links'] = reduce_with('render_link', ', ', $artist['links']);
return implode("\n<br />\n", $artist);
}
function render_event($event) {
unset($event['eventID']);
$event['eventTitle'] = "<strong>{$event['eventTitle']}</strong>";
$event['artists'] = reduce_with('render_artist',
"\n<br /><br />\n",
$event['artists']);
return implode("\n<br />\n", $event);
}
echo reduce_with('render_event', "\n<br /><br />--<br /><br />", $my_data);
If this is part of a larger application, we may want to tease out some more general patterns. This makes the code slightly more complex, but much more re-usable. Here are a few patterns I've spotted:
// Re-usable library code
// Partial application: apply some arguments now, the rest later
function papply() {
$args1 = func_get_args();
return function() use ($args1) {
return call_user_func_array(
'call_user_func',
array_merge($args1, func_get_args()));
};
}
// Function composition: chain functions together like a(b(c(...)))
function compose() {
$funcs = array_reverse(func_get_args());
$first = array_shift($funcs);
return function() use ($funcs, $first) {
return array_reduce($funcs,
function($x, $f) { return $f($x); },
call_user_func_array($first, func_get_args()));
};
}
// Transform or remove a particular element in an array
function change_elem($key, $func, $array) {
if is_null($func) unset($array[$key]);
else $array[$key] = $func($array[$key]);
return $array;
}
// Transform all elements then implode together
function reduce_with($renderer, $separator) {
return compose(papply('implode', $separator),
papply('array_map', $renderer));
}
// Wrap in HTML
function tag($tag, $text) {
return "<{$tag}>{$text}</{$tag}>";
}
// Problem-specific code
function render_link($link) {
return "<a href='{$link['URL']}'>{$link['URL']}</a>";
}
$render_artist = compose(
papply('implode', "\n<br />\n"),
papply('change_elem', 'links', papply('reduce_with',
'render_link',
', '));
$render_event = compose(
papply('implode', "\n<br />\n"),
papply('change_elem', null, 'eventID'),
papply('change_elem', 'eventTitle', papply('tag', 'strong')),
papply('change_elem', 'artists', papply('reduce_with',
$render_artist,
"\n<br /><br />\n")));
echo reduce_with($render_event, "\n<br /><br />--<br /><br />", $my_data);

get comments of post on facebook in php via graph

i want to get facebook comments on public post via graph.facebook
i want to get the name, the content and the id of the commenter
example of the graph
http://graph.facebook.com/comments/?ids=391265991032089
mycode so far
<?php
$data = file_get_contents('http://graph.facebook.com/comments/?ids=391265991032089');
$json = $data;
$obj = json_decode($json);
$comm_no = $obj->391265991032089->{'data'};
echo("<pre>");
var_dump($comm_no);
?>
wich gives me
array(25) {
[0]=>
object(stdClass)#437 (7) {
["id"]=>
string(31) "337379989797698_337380613130969"
["from"]=>
object(stdClass)#433 (2) {
["id"]=>
string(15) "100002978598053"
["name"]=>
string(28) "Àñä Båñòtá Bãskõtã"
}
["message"]=>
string(38) "سقفه لاخوكو ابو جبل :D"
["can_remove"]=>
bool(false)
["created_time"]=>
string(24) "2014-12-15T18:58:24+0000"
["like_count"]=>
int(10)
["user_likes"]=>
bool(false)
}
how to stip it down to just show only
name , message and id
isearched alot and didnt find any thing
If there is more than an answer then use the following code:
<?php
$data = file_get_contents('http://graph.facebook.com/comments/?ids=391265991032089');
$json = $data;
$obj = json_decode($json);
$comm_no = $obj->391265991032089->{'data'};
foreach($comm_no as $answer_id => $v) {
echo $v->from->id . '<br />';
echo $v->from->name. '<br />';
echo $v->message. '<br />';
}
?>

Looping a multidimensional array in php

I have a multidimensional array like this:
array(2) {
[1]=>
array(3) {
["eventID"]=>
string(1) "1"
["eventTitle"]=>
string(7) "EVENT 1"
["artists"]=>
array(3) {
[4]=>
array(2) {
["name"]=>
string(8) "ARTIST 1"
["description"]=>
string(13) "artist 1 desc"
["links"]=>
array(2) {
[1]=>
array(2) {
["URL"]=>
string(22) "http://www.artist1.com"
}
[6]=>
array(2) {
["URL"]=>
string(24) "http://www.artist1-2.com"
}
}
}
[5]=>
array(2) {
["name"]=>
string(8) "ARTIST 8"
["description"]=>
string(13) "artist 8 desc"
["links"]=>
array(1) {
[8]=>
array(2) {
["URL"]=>
string(22) "http://www.artist8.com"
}
}
}
[2]=>
array(2) {
["ime"]=>
string(8) "ARTIST 5"
["opis"]=>
string(13) "artist 5 desc"
["links"]=>
array(1) {
[9]=>
array(2) {
["URL"]=>
string(22) "http://www.artist5.com"
}
}
}
}
}
[2]=>
array(3) {
["eventID"]=>
string(1) "2"
["eventTitle"]=>
string(7) "EVENT 2"
["artists"]=>
array(3) {
[76]=>
array(2) {
["name"]=>
string(9) "ARTIST 76"
["description"]=>
string(14) "artist 76 desc"
["links"]=>
array(1) {
[13]=>
array(2) {
["URL"]=>
string(23) "http://www.artist76.com"
}
}
}
[4]=>
array(2) {
["name"]=>
string(8) "ARTIST 4"
["description"]=>
string(13) "artist 4 desc"
["links"]=>
array(1) {
[11]=>
array(2) {
["URL"]=>
string(22) "http://www.artist4.com"
}
}
}
}
}
}
I would like to make html output like this:
--
EVENT 1
ARTIST 1
artist 1 desc
http://www.artist1.com, http://www.artist1-2.com
ARTIST 8
artist 8 desc
http://www.artist8.com
ARTIST 5
artist 5 desc
http://www.artist5.com
--
EVENT 2
ARTIST 76
artist 76 desc
http://www.artist76.com
ARTIST 4
artist 4 desc
http://www.artist4.com
--
etc.
I'm confused about digging deeper and deeper in arrays, especially when my array keys are not sequential numbers but IDs of artist/link/etc.
These arrays will kill me, honestly! =)
Thanks for any help in advance!!!
You're best using the foreach construct to loop over your array. The following is untested and is off the top of my head (and probably therefore not as thought through as it should be!) but should give you a good start:
foreach ($mainArray as $event)
{
print $event["eventTitle"];
foreach ($event["artists"] as $artist)
{
print $artist["name"];
print $artist["description"];
$links = array();
foreach ($artist["links"] as $link)
{
$links[] = $link["URL"];
}
print implode(",", $links);
}
}
The foreach statement will take care of all of this for you, including the associative hashes. Like this:
foreach($array as $value) {
foreach($value as $key => $val) {
if($key == "links") {
}
/* etc */
}
}
I think a good way to approach this is "bottom up", ie. work out what to do with the inner-most values, then use those results to work out the next-level-up, and so on until we reach the top. It's also good practice to write our code in small, single-purpose, re-usable functions as much as possible, so that's what I'll be doing.
Note that I'll assume your data is safe (ie. it's not been provided by a potentially-malicious user). I'll also assume that the keys "ime" and "opi" are meant to match the "name" and "description" of the other arrays ;)
We can ignore the innermost strings themselves, since we don't need to modify them. In that case the inner-most structure I can see are the individual links, which are arrays containing a 'URL' value. Here's some code to render a single link:
function render_link($link) {
return "<a href='{$link['URL']}'>{$link['URL']}</a>";
}
This has reduced an array down to a string, so we can use it remove the inner-most layer. For example:
// Input
array('URL' => "http://www.artist1.com")
// Output
"<a href='http://www.artist1.com'>http://www.artist1.com</a>"
Now we move out a layer to the 'links' arrays. There are two things to do here: apply "render_link" to each element, which we can do using "array_map", then reduce the resulting array of strings down to a single comma-separated string, which we can do using the "implode" function:
function render_links($links_array) {
$rendered_links = array_map('render_link', $links_array);
return implode(', ', $rendered_links);
}
This has removed another layer, for example:
// Input
array(1 => array('URL' => "http://www.artist1.com"),
6 => array('URL' => "http://www.artist1-2.com"))
// Output
"<a href='http://www.artist1.com'>http://www.artist1.com</a>, <a href='http://www.artist1-2.com'>http://www.artist1-2.com</a>"
Now we can go out another level to an individual artist, which is an array containing 'name', 'description' and 'links'. We know how to render 'links', so we can reduce these down to a single string separated by linebreaks:
function render_artist($artist) {
// Replace the artist's links with a rendered version
$artist['links'] = render_links($artist['links']);
// Render this artist's details on separate lines
return implode("\n<br />\n", $artist);
}
This has removed another layer, for example:
// Input
array('name' => 'ARTIST 1',
'description' => 'artist 1 desc',
'links' => array(
1 => array(
'URL' => 'http://www.artist1.com')
6 => array(
'URL' => 'http://www.artist1-2.com')))
// Output
"ARTIST 1
<br />
artist 1 desc
<br />
<a href='http://www.artist1.com'>http://www.artist1.com</a>, <a href='http://www.artist1-2.com'>http://www.artist1-2.com</a>"
Now we can move out a layer to the 'artists' arrays. Just like when we went from a single link to the 'links' arrays, we can use array_map to handle the contents and implode to join them together:
function render_artists($artists) {
$rendered = array_map('render_artist', $artists);
return implode("\n<br /><br />\n", $rendered);
}
This has removed another layer (no example, because it's getting too long ;) )
Next we have an event, which we can tackle in the same way we did for the artist, although I'll also remove the ID number and format the title:
function render_event($event) {
unset($event['eventID']);
$event['eventTitle'] = "<strong>{$event['eventTitle']}</strong>";
$event['artists'] = render_artists($event['artists']);
return implode("\n<br />\n", $event);
}
Now we've reached the outer array, which is an array of events. We can handle this just like we did for the arrays of artists:
function render_events($events) {
$rendered = array_map('render_event', $events);
return implode("\n<br /><br />--<br /><br />", $rendered);
}
You might want to stop here, since passing your array to render_events will give you back the HTML you want:
echo render_events($my_data);
However, if we want more of a challenge we can try to refactor the code we've just written to be less redundant and more re-usable. One simple step is to get rid of render_links, render_artists and render_events since they're all variations on a more-general pattern:
function reduce_with($renderer, $separator, $array) {
return implode($separator, array_map($renderer, $array));
}
function render_artist($artist) {
$artist['links'] = reduce_with('render_link', ', ', $artist['links']);
return implode("\n<br />\n", $artist);
}
function render_event($event) {
unset($event['eventID']);
$event['eventTitle'] = "<strong>{$event['eventTitle']}</strong>";
$event['artists'] = reduce_with('render_artist',
"\n<br /><br />\n",
$event['artists']);
return implode("\n<br />\n", $event);
}
echo reduce_with('render_event', "\n<br /><br />--<br /><br />", $my_data);
If this is part of a larger application, we may want to tease out some more general patterns. This makes the code slightly more complex, but much more re-usable. Here are a few patterns I've spotted:
// Re-usable library code
// Partial application: apply some arguments now, the rest later
function papply() {
$args1 = func_get_args();
return function() use ($args1) {
return call_user_func_array(
'call_user_func',
array_merge($args1, func_get_args()));
};
}
// Function composition: chain functions together like a(b(c(...)))
function compose() {
$funcs = array_reverse(func_get_args());
$first = array_shift($funcs);
return function() use ($funcs, $first) {
return array_reduce($funcs,
function($x, $f) { return $f($x); },
call_user_func_array($first, func_get_args()));
};
}
// Transform or remove a particular element in an array
function change_elem($key, $func, $array) {
if is_null($func) unset($array[$key]);
else $array[$key] = $func($array[$key]);
return $array;
}
// Transform all elements then implode together
function reduce_with($renderer, $separator) {
return compose(papply('implode', $separator),
papply('array_map', $renderer));
}
// Wrap in HTML
function tag($tag, $text) {
return "<{$tag}>{$text}</{$tag}>";
}
// Problem-specific code
function render_link($link) {
return "<a href='{$link['URL']}'>{$link['URL']}</a>";
}
$render_artist = compose(
papply('implode', "\n<br />\n"),
papply('change_elem', 'links', papply('reduce_with',
'render_link',
', '));
$render_event = compose(
papply('implode', "\n<br />\n"),
papply('change_elem', null, 'eventID'),
papply('change_elem', 'eventTitle', papply('tag', 'strong')),
papply('change_elem', 'artists', papply('reduce_with',
$render_artist,
"\n<br /><br />\n")));
echo reduce_with($render_event, "\n<br /><br />--<br /><br />", $my_data);

Categories