I have repeated sections in my web site.
I'm trying to decrease them,
My approach is one time i will create a html schema (predefined as array), via this schema my function undestranding that what kind of output user needs and outputs results according to my variables..
My problem is I could not find a way to complete situation..
Input variables might be (infinitive)
$vals = array('Country Name' => 'USA', 'Country Name' => 'Canada', 'Country Name' => 'Mexico');
$vals = array('Country Name' => 'USA', 'Country Name' => 'Canada');
$vals = array('Country Name' => 'USA');
Expected outputs are in order
<div class="lines">
<div><span>Country Name</span>USA</div>
<div><span>Country Name</span>Canada</div>
<div><span>Country Name</span>Mexico</div>
</div>
<div class="lines">
<div><span>Country Name</span>USA</div>
<div><span>Country Name</span>Canada</div>
</div>
<div class="lines">
<div><span>Country Name</span>USA</div>
</div>
Schema is the variables that is totally suitable with html
$schema = array(
array(
'tag' => 'div',
'class' => 'lines',
array(
'tag' => 'div',
array(
'tag' => 'span',
'key' => '$key'
),
'key' => '$key'
),
)
);
My function creates outputs from this schema. (Schema might be expand accordings to user need.)
function get_output($schema, $vals, $t = -1){
$t++;
$tag = "";
$atts = array();
$keys = array();
$code = array();
foreach($schema as $k => $v){
if(is_array($v)){
$keys[] = get_output($v, $vals, $t);
} else {
switch($k){
case "tag": $tag = $v; break;
case "key": break;
case "type": break;
default: $atts[$k] = $v; break;
}
}
}
if($tag){
$code[] = "<$tag";
foreach($atts as $k=>$v)
{
$code[] = ' '.$k.'="'.urlencode($v).'"';
}
$code[] = ">";
$code = array(implode('', $code));
}
foreach($keys as $k)
{
$code[] = $k;
}
if($tag){
$code[] = '</'.$tag.'>';
}
return implode("", $code);
}
After all this process I will just call my function with the variables., Schema predefined once.
$vals = array('Country Name' => 'USA', 'Country Name' => 'Canada', 'Country Name' => 'Mexico');
echo get_output($schema, $vals, -1);
UPDATE1
My current output is the following html code, I could not find a way to push variables. Which are Country Name / Country
<div class="lines">
<div><span></span></div>
<div><span></span></div>
</div>
UPDATE3 Different Approach to Schema
$schema = array(
'div' => array(
'class' => 'lines',
'div' => array(
'span' => array(
'key' => '$k[0]'
),
'key' => '$k[1]'
)
);
Related
I'm trying to wrap my head around how to accomplish this…
I have an that's something like:
$contributors = array(
[0] => array(
[name] => 'John',
[role] => 'author',
),
[1] => array(
[name] => 'Gail',
[role] => 'author',
),
[2] => array(
[name] => 'Beth',
[role] => 'illustrator',
),
)
I'm trying to use this information to construct a detailed byline, like:
Written by John and Gail. Designed by Beth.
I need to compare each role to the previous and next ones in order to:
Use a label before the first instance of each role
Separate multiple instances of the same role with a comma
Use "and" instead of a comma before the last instance of each role
I'm no PHP expert so I'm having a hard time figuring out how to approach this! I have a function to output the right label depending on the role, but it's the comparisons I can't seem to figure out. I've considered foreach and while loops, but neither seems up to the job. I've never used a for loop so I don't know if it applies.
Some additional background:
I'm working with WordPress and the Advanced Custom Fields plugin.
$contributors is the value of an ACF Repeater field, where name and role are subfields. (I've simplified the names to make things easier.)
You can group the array per role and use array_pop to remove the element. implode the remaining array elements and just append the popped value.
$contributors = array(
array(
"name" => 'John',
"role" => 'author',
),
array(
"name" => 'Gail',
"role" => 'author',
),
array(
"name" => 'Jose',
"role" => 'author',
),
array(
"name" => 'Thomas',
"role" => 'author',
),
array(
"name" => 'Beth',
"role" => 'illustrator',
),
array(
"name" => 'Mary',
"role" => 'producer',
),
array(
"name" => 'Criss',
"role" => 'producer',
),
);
//Grouped the names according to role
$grouped = array_reduce($contributors, function($c, $v) {
if ( !isset( $c[ $v['role'] ] ) ) $c[ $v['role'] ] = array();
$c[ $v['role'] ][] = $v['name'];
return $c;
}, array());
//Construct final Array
$final = array();
foreach( $grouped as $key => $group ) {
$last = array_pop( $group );
if ( count( $group ) == 0 ) $final[ $key ] = $last; /* One one name on the role, no need to do anything*/
else $final[ $key ] = implode( ", ", $group ) . " and " . $last;
}
echo "<pre>";
print_r( $final );
echo "</pre>";
This will result to:
Array
(
[author] => John, Gail, Jose and Thomas
[illustrator] => Beth
[producer] => Mary and Criss
)
You can now use it as
echo 'Written by ' . $final["author"] . '. Designed by ' . $final["illustrator"] . '. Produced by ' . $final["producer"];
And will result to:
Written by John, Gail, Jose and Thomas. Designed by Beth. Produced by
Mary and Criss
You can try like this -
$contributors = array(
array(
'name' => 'John',
'role' => 'author',
),
array(
'name' => 'Gail',
'role' => 'author',
),
array(
'name' => 'Ali',
'role' => 'author',
),
array(
'name' => 'Beth',
'role' => 'illustrator',
)
);
#This function prepare array to expected String
function PrepareArray($data){
$combined = '';
if (count($data)>1) {
$last = array_slice($data, -1);
$first = join(', ', array_slice($data, 0, -1));
$both = array_filter(array_merge(array($first), $last), 'strlen');
$combined = join(' and ', $both);
}else{
$combined = implode('', $data);
}
return $combined;
}
$authors = array();
$designers = array();
foreach ($contributors as $key => $value) {
if ($value['role']=='author') {
$authors[] = $value['name']; #Keep Authors name in Array
}else if ($value['role']=='illustrator') {
$designers[] = $value['name']; #Keep Designers name in Array
}
}
$authors = PrepareArray($authors);
$designers = PrepareArray($designers);
echo "Written by {$authors}. Designed by {$designers}.";
Output :
Written by John, Gail and Ali. Designed by Beth.
Try below code:
<?php
$contributors = array(
0 => array(
'name' => 'John',
'role' => 'author',
),
1 => array(
'name' => 'Gail',
'role' => 'author',
),
2 => array(
'name' => 'Beth',
'role' => 'illustrator',
),
3 => array(
'name' => 'Albert',
'role' => 'author',
),
);
$labels = ['author'=>'Written by', 'illustrator'=>'Designed by', 'producer'=>'Produced by'];
$new_contributors = [];
foreach($contributors as $cont){
$new_contributors[$cont['role']][] = $cont['name'];
}
$str = '';
foreach($labels as $role=>$label){
if(isset($new_contributors[$role]) && is_array($new_contributors[$role])){
$str .= ' '.$label.' ';
foreach($new_contributors[$role] as $key=>$new_contributor){
$count = count($new_contributors[$role]);
if(($count - $key) == 1 ){
$str .= ' and ';
$str .= $new_contributor;
}else if(($count - $key) == 2){
$str .= $new_contributor;
}else{
$str .= $new_contributor.', ';
}
}
}
}
echo $str;
I have an array in a class and want to obtain the 'Apple' key value ('iPhone').
I assume a for each loop needs to be used.
How would I go about doing this?
UPDATE: I also need to specify the customerType and productType key values.
class Products {
public function products_list() {
$customerType = 'national';
$productType = 'phones';
$phoneType = 'Apple';
$productsArr = array();
$productsArr[] = array(
'customerType' => 'national',
'productType' => array(
'phones' => array(
'Apple' => 'iPhone',
'Sony' => 'Xperia',
'Samsung' => 'Galaxy'
),
'cases' => array(
'leather' => 'black',
'plastic' => 'red',
),
),
'international' => array(
'phones' => array(
'BlackBerry' => 'One',
'Google' => 'Pixel',
'Samsung' => 'Note'
),
'cases' => array(
'leather' => 'blue',
'plastic' => 'green'
),
)
);
}
}
I have created a function that you can more or less give it any product and it will return the key and value from the array
<?php
class Products
{
public function products_list()
{
$customerType = 'national';
$productType = 'phones';
$phoneType = 'Apple';
$productsArr[] = array(
'customerType' => 'national', 'productType' => array(
'phones' => array(
'Apple' => 'iPhone',
'Sony' => 'Xperia',
'Samsung' => 'Galaxy'
),
'cases' => array(
'leather' => 'black',
'plastic' => 'red',
),
),
'international' => array(
'phones' => array(
'BlackBerry' => 'One',
'Google' => 'Pixel',
'Samsung' => 'Note'
),
'cases' => array(
'leather' => 'blue',
'plastic' => 'green'
),
)
);
echo $this->get_value($phoneType, $productsArr) .'<br>';
echo $this->get_value($customerType, $productsArr) .'<br>';
echo $this->get_value($productType, $productsArr) .'<br>';
}
function get_value($product, array $products)
{
$iterator = new RecursiveIteratorIterator(new RecursiveArrayIterator($products), RecursiveIteratorIterator::CHILD_FIRST);
foreach ($iterator as $key => $value) {
if (is_string($value) && ($key == $product)) {
return 'key ->' . $key .' value ->'.$value;
}
}
return "";
}
}
$phone_products = new Products();
$phone_products->products_list();
To use it within the class just call
$this->get_value($phoneType, $productsArr);
from without the class call
$phone_products = new Products();
echo ($phone_products->get_value($phoneType, $productsArr));
//output: key ->Apple value ->iPhone
NB: $phoneType, $productsArr will either be defined the methods they are being used in or passed from other methods or define global variables within the class.
If you want single entry:
echo $productsArr[0]['productType']['phones']['Apple']."<br />";
If there are multiple data, you can use foreach:
foreach ($productsArr as $prod){
echo $prod['productType']['phones']['Apple']."<br />";
}
just try
foreach($productsArr[0]['productType']['phones'] as $phones){
echo $phones[$phoneType]; }
foreach($productsArr as $key1 => $data1 ){
if(is_array($data1))
foreach($data1 as $key2 => $data2 ){
if(is_array($data2))
foreach($data2 as $key3 => $data3 ){
if(array_key_exists('Apple', $data3)) {
echo $data3['Apple'] ."\n";
}
}
}
}
I'm trying to make a menu from an array in PHP.
I would like to make it more readable, so I used an array.
My array is the following:
$menu = array(
'calendar' => array(
'text' => 'Calendar',
'rights' => 'user'
),
'customers' => array(
'text' => 'Customers',
'rights' => 'user',
'sub' => array(
'create-new' => array(
'text' => 'Create new customer',
'rights' => 'user'
),
'show-customers' => array(
'text' => 'Show all customers',
'rights' => 'user'
)
)
)
);
And the PHP to parse the array:
buildMenu($menu);
function buildMenu($menu_array, $is_sub=FALSE) {
$attr = (!$is_sub) ? ' id="menu"' : ' class="submenu"';
$menu = "<ul".$attr.">";
foreach($menu_array as $id => $properties) {
foreach($properties as $key => $val) {
if(is_array($val)) {
$sub = buildMenu($val, TRUE);
}
else {
$sub = NULL;
$$key = $val;
}
}
if(!isset($url)) {
$url = $id;
}
$menu .= "<li>".$text."".$sub."</li>";
unset($url, $text, $sub);
}
return $menu . "</ul>";
}
Do I miss something ?
It don't echo me anything.
Thanks for your help.
Just return will not give output you need to either use below code, inside function.
echo $menu . "</ul>";
instead of
return $menu . "</ul>";
or use below code if you return your html output.
echo $output = buildMenu($menu);
instead of
buildMenu($menu);
how can i print the whole multidimensional array by using foreach?
<?php
$shop=array // main array
(
"laptop"=>array
(
"conpaq",
"IBM",
"DELL",
"Lenovo"
),
"printer"=>array
(
"canon",
"Hp"
),
"Tabs"=>array
(
"Hp",
"Dell",
"deny"
)
);
This one is a simple list using recursion, it also have tabs to make it more clear when there's a new array-group.
Please try it and adjust for your code.
$shop = array(
'computers' => array(
'dell' => array(
'i7' => array(
'model1' => 'Model 1',
'model2' => 'Model 2',
),
'i5' => 'Model 1'
),
'hp' => array(
'model1' => 'Model 1'
)
),
'printers' => array(
'Epson' => 'Model 1'
)
);
function printProducts($products, $tabsCount = 0){
$result = ''; $tabs = '';
for($i = 0; $i < $tabsCount; $i++){ $tabs .= ' '; }
foreach($products AS $index=>$product){
if(is_array($product)){
$result .= $tabs.$index.'<br>';
$result .= printProducts($product, $tabsCount+1);
}else{
$result .= $tabs.$product.'<br>';
}
}
return $result;
}
echo printProducts($shop);
Ask if there is something you don't understand.
for 2 levels and without recursion. Recusion would be better but this will work.
foreach($shop as $value) {
if (is_array($value)) {
foreach($shop as $value) {
echo "$value<br />";
}
} else {
echo "$value<br />";
}
}
?>
Ok, so say I have an array as follows:
$buttons = array(
'mlist' => array(
'title' => 'Members',
'href' => $scripturl . '?action=mlist',
'show' => $context['allow_memberlist'],
'sub_buttons' => array(
'mlist_view' => array(
'title' => 'View the Member List',
'href' => $scripturl . '?action=mlist',
'show' => true,
),
'mlist_search' => array(
'title' => 'Search for Members',
'href' => $scripturl . '?action=mlist;sa=search',
'show' => true,
'is_last' => true,
),
),
),
'home' => array(
'title' => 'Home',
'href' => $scripturl,
'show' => true,
'sub_buttons' => array(
),
'is_last' => $context['right_to_left'],
),
'help' => array(
'title' => 'Help',
'href' => $scripturl . '?action=help',
'show' => true,
'sub_buttons' => array(
),
),
);
I need to sort through this array and return all indexes of it in another array as an index, and the values of these arrays will be the title. So it should return an array as follows:
array(
'mlist' => 'Members',
'mlist_view' => 'View the Member List',
'mlist_search' => 'Search for Members',
'home' => 'Home',
'help' => 'Help',
);
How can this be achieved easily? Basically, need the key of each array if a title is specified and need to populate both within another array.
The following snippet loops over all of the arrays (recursively) to extract the key/title pairs.
$index = array();
$iterator = new RecursiveIteratorIterator(new ParentIterator(new RecursiveArrayIterator($buttons)), RecursiveIteratorIterator::SELF_FIRST);
foreach ($iterator as $key => $value) {
if (array_key_exists('title', $value)) {
$index[$key] = $value['title'];
}
}
var_dump($index);
How can this be achieved easily?
initialize an empty, new array
foreach the $buttons array with key and value
extract title from value
set the key in the new array with the title
done.
Edit: In case a recursive array iterator catches too much (identifying elements as children while they are not - just being some other array), and you don't want to write an extension of the recursive iterator class, stepping through all children can be solved with some "hand written" iterator like this:
$index = array();
$childKey = 'sub_buttons';
$iterator = $buttons;
while(list($key, $item) = each($iterator))
{
array_shift($iterator);
$index[$key] = $item['title'];
$children = isset($item[$childKey]) ? $item[$childKey] : false;
if ($children) $iterator = $children + $iterator;
}
This iterator is aware of the child key, so it will only iterate over childs if there are some concrete. You can control the order (children first, children last) by changing the order:
if ($children) $iterator = $children + $iterator;
- or -
if ($children) $iterator += $children;
I'm sure my answer is not most efficient, but using many foreach loops and if checks, it can be done. However, with my solution if you nested another array inside of say 'mlist_view' that you needed to get a title from, it would not work. My solution works for a max of 2 arrays inside of arrays within buttons. A better (and more general purpose solution) would probably involve recursion.
$result = array();
foreach($buttons as $field => $value) {
foreach($value as $nF => $nV) {
if($nF === 'title') {
$result[$field] = $nV;
}
if(is_array($nV)) {
foreach($nV as $name => $comp) {
if(is_array($comp)) {
foreach($comp as $nnF => $nnV) {
if($nnF === 'title') {
$result[$name] = $nnV;
}
}
}
}
}
}
}
foreach($result as $f => $v) {
echo $f.": ".$v."<br/>";
}
This works for your value of $buttons, fairly simple:
function get_all_keys($arr) {
if (!is_array($arr)) return array();
$return = array();
foreach (array_keys($arr) as $key) {
if (is_array($arr[$key])
&& array_key_exists('title', $arr[$key]))
$return[$key] = $arr[$key]['title'];
$return = array_merge($return, get_all_keys($arr[$key]));
}
return $return;
}
echo "<pre>";
print_r(get_all_keys($buttons));
echo "</pre>";
Which returns:
Array
(
[mlist] => Members
[mlist_view] => View the Member List
[mlist_search] => Search for Members
[home] => Home
[help] => Help
)