I' am creating a hierarchical menu using MySQL Database. I' am currently stuck at this point where I' am not able to convert the multidimensional array into a string.
The Outcome
/media/photo-gallery/Title-1
Var Dump of the array
array(2) {
[0]=>
array(2) {
[0]=>
array(1) {
[1]=>
string(5) "media"
}
[1]=>
string(13) "photo-gallery"
}
[1]=>
string(7) "Title-1"
}
I have tried using Implode function, this is what I get
$path = implode("/", $path);
string(19) "Array/photo-gallery"
Get the parent slug from database
function get_path( $page_id ) {
global $db;
$sql = "SELECT * FROM pages WHERE page_id = $page_id";
$query = $db->SELECT($sql);
$rows = $db->FETCH_OBJECT();
$path = array();
foreach( $rows as $row ){
$page_id = $row->page_id;
$page_parent = $row->page_parent;
$page_slug = $row->page_slug;
$path[] = $page_slug;
$path[] = get_path( $page_parent );
$path = array_reverse( $path );
$path = array_filter( $path );
}
return $path;
}
Displays the HTML Menu
function display_children( $parent = "0", $level = "0" ){
global $db;
echo "<ul>";
// retrieve all children of $parent
$sql = "SELECT * FROM pages WHERE page_parent = $parent";
$query = $db->SELECT($sql);
$rows = $db->FETCH_OBJECT();
foreach( $rows as $row ){
$page_id = $row->page_id;
$page_parent = $row->page_parent;
$page_title = $row->page_title;
$page_slug = $row->page_slug;
$path = get_path($page_parent);
$path = array_unique(array_values($path));
var_dump($path);
echo "<li>";
echo "<a href=\"\">";
echo "$page_title | Parent ID: $page_parent";
echo "</li>";
echo "</a>";
// child's children
display_children($page_id, $level + 1);
}
echo "</ul>";
}
looks like your input array is in reverse order, the topmost item goes to the end and the last leaf is the first item. Here is a small function which you can try.
$path = array(array(array('media'),'photo-gallery'),'Title-1');
var_dump($path);
$path = implode('/',sanitizePath($path));
echo $path;
function sanitizePath($pathArray, $initialPath=array()){
foreach($pathArray as $a){
if(is_array($a)){
$initialPath=sanitizePath($a,$initialPath);
}else{
array_push($initialPath,$a);
}
}
return $initialPath;
}
Try this
$array = array(
0 =>array(
0 => array("media","photo-gallery"),
),
1 => "Title-1"
);
$new_array = array();
foreach($array as $k1=>$v1){
if(is_array($v1)){
$new_array = parseArray($new_array, $k1, $v1);
}else{
$new_array = array_merge($new_array, array($k1=>$v1));
}
}
function parseArray($new_array, $key, $val){
if(is_array($val)){
foreach($val as $k2=>$v2){
if(is_array($v2)){
$new_array = parseArray($new_array, $k2, $v2);
}else{
$new_array = array_merge($new_array, array($k2=>$v2));
}
}
}else{
$new_array = array_merge($new_array, array($key=>$val));
}
return $new_array;
}
echo implode('/', $new_array);
Output:
media/photo-gallery/Title-1
With Standard PHP Library (SPL) you can get the desired output
<?php
$array = array(
0 =>array(
0 => array("media","photo-gallery"),
),
1 => "Title-1"
);
$op = new RecursiveIteratorIterator(new RecursiveArrayIterator($array));
foreach($op as $each) {
$result .= '/'.$each;
}
echo $result;.
Output:
/media/photo-gallery/Title-1
Related
I have a string like this:
$config = 'app.name = "My App";
app.id = "myappid";
app.components.cache.id = "Memcache";';
I need to convert it to array like this:
app=>[
'name=>'My App',
'id'=>'myappid',
'components'=>[
'cache'=>['id'=>'Memcache']
]
]
I use explode for divide on the pieces, but i don't know what i need to do next.
$arr = explode(";", $config);
$data = [];
foreach ($arr as $item) {
$pieces = explode('=', $item);
$pieces_dotes = explode('.', $pieces[0]);
foreach ($pieces_dotes as $piece) {
//what i need to do here?
}
}
How about this? Within the inner foreach loop, you're assigning the temp variable by reference to itself, so you build a stack of array keys, and then assign the value to it at the end.
$config = 'app.name = "My App";
app.id = "myappid";
app.components.cache.id = "Memcache";';
$arr = explode(";", $config);
$data = [];
foreach ($arr as $item) {
$temp = &$data;
$item = trim($item);
if (empty($item)) continue;
list($setting, $value) = explode("=", trim($item));
$setting = explode(".", trim($setting));
foreach ($setting as $set) {
$temp = &$temp[$set];
}
$temp = trim($value, '" ');
}
print_r($data);
This can be solved by building the array levels based on the key and keeping a reference to the last added level in the array. My solution (based on what you already had) is as follows:
<?php
$config = 'app.name = "My App";
app.id = "myappid";
app.components.cache.id = "Memcache";';
$arr = explode(";", $config);
$data = [];
foreach ($arr as $item) {
$pieces = explode('=', $item);
$currentValue = trim(str_replace('"', '', $pieces[1]));
$pieces_dotes = explode('.', $pieces[0]);
// Set initial value of $currentLevel to root of data array
$currentLevel = &$data;
// Initiate count & iterator vars
$numPieces = count($pieces_dotes);
$i = 0;
foreach ($pieces_dotes as $piece) {
// Increment $i and set $newKey to be trimmed version of current piece of the dot notated level
$i++;
$newKey = trim($piece);
// Skip empty $newKey
if(empty($newKey)) {
continue;
}
// Assign the $currentValue once we are at the required depth
if($i == $numPieces) {
$currentLevel[$newKey] = $currentValue;
}
// We are not at the required depth yet so initiate the key as an array if required
if(empty($currentLevel[$newKey])) {
$currentLevel[$newKey] = [];
}
// Set the $currentLevel to reference the new key
if(is_array($currentLevel[$newKey])) {
$currentLevel = &$currentLevel[$newKey];
}
}
}
Hope this helps!
The solution using custom recursive function fillBypath:
/**
* Fills an array by hierarchical 'key path'
*
* #param type $value value in each 'key path'
* #param type $keys hierarchical key list
* #param type $arr the resulting array(passed by reference)
*/
function fillByPath($value, $keys, &$arr) {
$c = count($keys) - 1;
foreach ($keys as $idx => $k) {
if ($idx == $c) { // check if it's the last key in the "key path"
$arr[$k] = $value;
break;
}
if (isset($arr[$k]) && is_array($arr[$k])) {
fillByPath($value, array_slice($keys, $idx + 1), $arr[$k]);
break;
} else {
$arr[$k] = [];
fillByPath($value, array_slice($keys, $idx + 1), $arr[$k]);
break;
}
}
}
$config = 'app.name = "My App";
app.id = "myappid";
app.components.cache.id = "Memcache";';
$result = [];
foreach (array_filter(explode(";", $config)) as $path) {
list($keyPath, $v) = explode(" = ", trim($path));
$keys = explode(".", $keyPath); // getting key list
fillByPath($v, $keys, $result);
}
print_r($result);
The output:
(
[app] => Array
(
[name] => "My App"
[id] => "myappid"
[components] => Array
(
[cache] => Array
(
[id] => "Memcache"
)
)
)
)
I would like to concatenate each element of array to next one. I want the output array to be:
Array
(
[0] => test
[1] => test/test2
[2] => test/test2/test3
[3] => test/test2/test3/test4
)
I tried the following way which concatenates each string to itself:
$url = preg_split("/[\s\/]+/", "test/test2/test3/test4");
foreach ($url as $dir) {
$dir .= $dir;
}
Any help appreciated.
Maybe another way
<?php
$data = array( 'test', 'test2', 'test3', 'test4' );
for( $i = 0; $i < count( $data ); $i++ )
{
if( $i != 0 )
{
$new[ $i ] = $new[ $i - 1 ] .'/'. $data[ $i ];
}
else
{
$new[ $i ] = $data[ $i ];
}
}
var_dump( $new );
Output
array(4) {
[0]=>
string(4) "test"
[1]=>
string(10) "test/test2"
[2]=>
string(16) "test/test2/test3"
[3]=>
string(22) "test/test2/test3/test4"
}
You should obtain the result you need in $my_array
$url = explode("/", "test/test2/test3/test4");
$str ='';
foreach($url as $key => $value){
if ( $str == '') {
$str .= $str;
} else {
$str .= '/'.$str;
}
$my_array[$key] = $str ;
echo $str . '<br />';
}
var_dump($my_array);
$url = preg_split("/[\s\/]+/", "test/test2/test3/test4");
$arr = array();
$str = '';
foreach ($url as $key => $dir) {
if ($key !== 0) {
$str .= '/' . $dir;
} else {
$str .= $dir;
}
$arr[] = $str;
}
On each iteration concate a string with new value and add it as a separate value for your output array.
Here's a quick way. For simple splitting just use explode():
$url = explode("/", "test/test2/test3/test4");
foreach($url as $value) {
$temp[] = $value;
$result[] = implode("/", $temp);
}
Each time through the loop, add the current value to a temporary array and implode it into the next element of the result.
How can I access the contents of $value[$i] which is an array. No luck using foreach in the form below.
The idea is to loop through $contentArray and display one item from each sub-array on every iteration.
$addsContent = $Adds->selectAdds(10);
$sharedArticlesContent = $SharedContent->getSharedContent($topic_selected, $filter_selected);
$blogPostsContent = $BlogPosts->getRecentBlogPostsByTopic("business");
$contentArray = array(
$sharedArticlesContent,
$addsContent ,
$blogPostsContent
);
foreach($contentArray as $value)
{
if(count($value)>$maxLength)
{
$maxLength = count($value);
}
}
for($i=0; $i<$maxLength; $i++)
{
foreach($contentArray as $value)
{
if(isset($value[$i]))
{
if($value==$sharedArticlesContent){
$data = $value[$i];
foreach($sharedArticlesContent as $data){
$post_id = $data['id'];
$uploaded_by = $data['uploaded_by'];
$text = $data['text'];
$image = $data['image'];
require 'template1.php';
}
}elseif($value==$addsContent){
//template2
}else{
//template3
}
}
}
}
You're dealing with an associative array here, you can access it like that:
<?php
$addsContent = $Adds->selectAdds(10);
$sharedArticlesContent = $SharedContent->getSharedContent($topic_selected, $filter_selected);
$blogPostsContent = $BlogPosts->getRecentBlogPostsByTopic("business");
$contentArray = array(
$sharedArticlesContent,
$addsContent ,
$blogPostsContent
);
foreach($contentArray as $value)
{
if(count($value)>$maxLength)
{
$maxLength = count($value);
}
}
for($i=0; $i<$maxLength; $i++)
{
foreach($contentArray as $value)
{
if(isset($value[$i]))
{
if($value==$sharedArticlesContent)
{
$post_id = $value[$i]['id'];
$uploaded_by = $value[$i]['uploaded_by'];
$text = $value[$i]['text'];
$image = $value[$i]['image'];
require 'template1.php';
}
elseif($value==$addsContent)
{
//template2
}
else
{
//template3
}
}
}
}
You don't need the foreach. $data is an associative array, you don't need to loop through it.
if($value==$sharedArticlesContent){
$data = $value[$i];
$post_id = $data['id'];
$uploaded_by = $data['uploaded_by'];
$text = $data['text'];
$image = $data['image'];
require 'template1.php';
}
I have the following line:
$formatsArray = $_POST['formats'];
$topicsArray = $_POST['topics'];
// Converting the array into individual strings
$formats = implode(",", $formatsArray);
$topics = implode(",", $topicsArray);
// Prepare the statement
$resources = $con->prepare("SELECT * FROM resources WHERE
(format IN (?))
AND (topic IN (?))");
// Bind the statement
$resources->bind_param('ss',$formats, $topics);
The problem is that topics derived from an array where it could contain multiple string, but 's' will only recognize 1. I would want that if the topic array has 10 entries, than there would be 10s, and same for format.
I have thinking of counting the size of the array and adding an s in every iteration, but not sure how.
Any help would be appreciated.
// Count array
$formatCount = count($formatsArray);
$topicCount = count($topicsArray);
How about this then:
<?php
$con = new mysqli("localhost", "USERNAME", "PASSWORD", "DATABASE");
$formatsArray = array('a','b','c','d',);
$topicsArray = array('x','y','z',);
$sql = 'SELECT * FROM resources WHERE (format IN (FORMAT_REPLACE_ME)) AND (topic IN (TOPIC_REPLACE_ME))';
$formatsPlaceholders = makePlaceHolders($formatsArray);
$topicsPlaceholders = makePlaceHolders($topicsArray);
$sql = str_replace('FORMAT_REPLACE_ME', $formatsPlaceholders, $sql);
$sql = str_replace('TOPIC_REPLACE_ME', $topicsPlaceholders, $sql);
//error_log(print_r($sql,1).' '.__FILE__.' '.__LINE__,0);
try {
$s = $con->prepare($sql);
$vals = array_merge($formatsArray, $topicsArray);
// from http://stackoverflow.com/a/31562035/1814739
$typDfs = str_repeat( 's' , count( $vals ) );
$params = array( $typDfs );
foreach ( $vals as $k => $v ) {
${ 'varvar' . $k } = $v;
$params[] = &${ 'varvar' . $k }; # provide references
}
call_user_func_array( array( $s, 'bind_param' ) , $params );
$s->execute();
$output = array();
$res = $s->get_result();
while ($row = $res->fetch_array(MYSQLI_NUM))
{
//error_log(print_r($row,1).' '.__FILE__.' '.__LINE__,0);
$output []= array(
'id' => $row[0],
'format' => $row[1],
'topic' => $row[2],
);
}
$s->close();
sanitize_output($output);
}
catch (\Exception $e) {
error_log(print_r($e->getMessage(),1).' '.__FILE__.' '.__LINE__,0);
}
function makePlaceHolders($arr){
$ph = '';
for ($i = 1; $i <= count($arr); $i++) {
$ph .= '?,';
}
return rtrim($ph,',');
}
function sanitize_output(array &$arr, array $args=array()) {
array_walk_recursive($arr,'so',$args);
}
function so(&$v,$k,$args) {
$excludes = isset($args['excludes']) ? $args['excludes'] : array();
if (!in_array($k,$excludes)) {
$v = trim($v);
$v = (get_magic_quotes_gpc()) ? stripcslashes($v) : $v;
$v = htmlspecialchars($v);
}
}
?>
<html>
<body>
<ul>
<?php foreach($output as $k => $o) { ?>
<li><?php echo $o['id']; echo $o['format']; echo $o['topic']; ?></li>
<?php } ?>
</ul>
</body>
</html>
I have a multidimensional array that's contains all user data , and I've build a function to get array value with the given key .
the problem is that the array is multidimensional array , and I don't know how many level .
this is the function
function getUserSessionData($key)
{
$arrKeys = explode('.', $key);
if(count($arrKeys) == 1){
if(isset($_SESSION['user_data'][$arrKeys[0]])){
return $_SESSION['user_data'][$arrKeys[0]];
}
}
else{
if(isset($_SESSION['user_data'][$arrKeys[0]][$arrKeys[1]])){
return $_SESSION['user_data'][$arrKeys[0]][$arrKeys[1]];
}
}
return 0;
}
and this is an example of the call.
getUserSessionData('profile.firstName');
The (.) indicates of level of the array .
the function is support only tow levels .. is there any way to enhance this function so it can support more than tow levels ??
Sure, use a looping structure:
function getUserSessionData($key) {
$parts = explode('.', $key);
$data = $_SESSION["user_data"];
while (count($parts) > 0) {
$part = array_shift($parts);
$data = $data[$part];
}
return $data;
}
Or independently of the session:
function resolveKey($array, $key) {
$parts = explode('.', $key);
while (count($parts) > 0) {
$part = array_shift($parts);
$array = $array[$part];
}
return $array;
}
echo resolveKey(array(
"foo" => array(
"bar" => array(
"baz" => "ipsum"
)
)
), "foo.bar.baz"); // "ipsum"
echo resolveKey($_SESSION["user_data"], 'profile.firstName');
Here's a PHP-Fiddle
function getUserSessionData($key){
$arrKeys = explode('.', $key);
$data = $_SESSION['user_data'];
foreach($arrKeys as $k){
if(isset($data[$k])) $data = $data[$k];
else return false;
}
return $data;
}
Example usage:
session_start();
$_SESSION['user_data'] = [];
$_SESSION['user_data']['user'] = [];
$_SESSION['user_data']['user']['name'] = [];
$_SESSION['user_data']['user']['name']['first'] = "robert";
echo getUserSessionData("user.name.first"); // echos "robert"
Thank you #Halcyon
you've been very helpful.
but I've modified your function to get it to work .
this is the new function
function getUserSessionData($key) {
$data = Yii::app()->session['account_data']['user_data'];
$parts = explode('.', $key);
while (count($parts) > 0) {
$part = $parts[0];
if(!isset($data[$part])){
return 0;
}
$data = $data[$part];
array_shift($parts);
}
return $data;
}