Recursive function to generate flat array from hierarchical array - php

What I've tried to do for the past hour is a function that will let me generate a flat array of the same pages, but with the children having their parents title before them
what I could do so far is get 1 level of the parents, I need the logic behind this and I can do the code, the main point is to have an array to fetch in select menu
i.e:
Parent
parent / Sub 1
Parent / Sub 1 / Sub 2
Parent 2
parent 2 / Sub 1
Parent 2 / Sub 1 / Sub 2
My array looks like this :
Array (
[0] => Array (
[object]=>menuObject
[title]=>title
[parent_id]=>parent_id
[children]=>array(
[0] => Array (
[object]=>menuObject
[title]=>title
[parent_id]=>parent_id
[children]=>''
)
)
)
);
the array I need will look like:
Array(
[14]=>'parent / sub / sub 1'
//[ID]=>[Title]
)

Well, after pretty long time I figured out a way to do it with 2 functions,
the first to flatten the array, and the other to find out the path, though I had to Query the DB to make it
public function parseSelectArray($tree)
{
$return=array();
foreach ($tree as $key => $value) {
//The other function call to create the path
$return[$key]=Controller_Admin_Pages::createPath($key);
}
return empty($return) ? null : $return;
}
public function createPath($id) {
//Query the page, though I could get the value from the array.
$page=Model_Page::find($id);
if($page->idparent == 0) {
$name = $page->title;
return $name;
} else {
$name = $page->title;
return Controller_Admin_Pages::createPath($page->idparent). " / ".$name;
}
}

Related

Accumulate strings and array values into an array as a class property via method

I have a class with method add() that accepts strings and arrays. I need to have an array with all users, but I cannot seem to get it. All I get is multiple arrays with all users. How could I merge those arrays into one?
class Users {
function add($stringOrArray) {
$arr = array();
if(is_array($stringOrArray)) {
$arr = $stringOrArray;
} else if(is_string($stringOrArray)) {
$arr[] = $stringOrArray;
} else {
echo('errrrror');
}
print_r($arr);
}
When I use this test:
public function testOne() {
$users = new Users();
$users->add('Terrell Irving');
$users->add('Magdalen Sara Tanner');
$users->add('Chad Niles');
$users->add(['Mervin Spearing', 'Dean Willoughby', 'David Prescott']);
This is what I get, multiple arrays but I need one array.
Array
(
[0] => Terrell Irving
)
Array
(
[0] => Magdalen Sara Tanner
)
Array
(
[0] => Chad Niles
)
Array
(
[0] => Mervin Spearing
[1] => Dean Willoughby
[2] => David Prescott
)
You can cut a lot of unnecessary bloat from your method.
You can cast ALL incoming data to array type explicitly. This will convert a string into an array containing a single element. If the variable is already an array, nothing will change about the value.
Use the spread operator (...) to perform a variadic push into the class property.
Code: (Demo)
class Users
{
public $listOfUsers = [];
function add($stringOrArray): void
{
array_push($this->listOfUsers, ...(array)$stringOrArray);
}
}
$users = new Users;
$users->add('Terrell Irving');
$users->add(['Magdalen Sara Tanner', 'Chad Niles']);
$users->add(['Mervin Spearing']);
var_export($users->listOfUsers);
Output:
array (
0 => 'Terrell Irving',
1 => 'Magdalen Sara Tanner',
2 => 'Chad Niles',
3 => 'Mervin Spearing',
)
All you need is to store the added users in a class property, for example $listOfUsers.
If adding the array you use the array_merge() function otherwise just add new user at the end of indexed array.
<?php
class Users {
// here will be all the users stored
public $listOfUsers = array();
function add($stringOrArray) {
//$arr = array();
if(is_array($stringOrArray)) {
// merge two arrays - could create duplicate records
$this->listOfUsers = array_merge($this->listOfUsers, $stringOrArray);
} else if(is_string($stringOrArray)) {
// simply add new item into the array
$this->listOfUsers[] = $stringOrArray;
} else {
echo('errrrror');
}
print_r($this->listOfUsers);
}
}
In your example you are storing the data locally within the method add() and it is not kept for future usage. This behavior is corrected using the class property $listOfUsers that can be accesed using $this->listOfUsers within the class object and if needed outside of the class.

Change global 2d array from a function PHP?

$q = $_POST['q'];
$inCart = isset($_COOKIE['cart']) ? unserialize($_COOKIE['cart']) : array();
function alreadyInCart() {
global $inCart, $good, $q;
foreach ($inCart as $inCart1) {
if ($inCart1[0] == $good->id) { // if this good already in cart
$inCart1[1] = $inCart1[1] + $q; // write sum of q's to existing array
return true; // and return true
}
}
return false; // return false if not
}
if (alreadyInCart() == false) { // if good added to cart for the first time
$inCart[] = array($good->id, $q); // add array at the end of array
}
Hello. So my problem is that I'm running a function to find out if $good->id is already inside of 2d $inCart array.
$inCart looks something like this:
Array
(
[0] => Array
(
[0] => 6
[1] => 1
)
[1] => Array
(
[0] => 5
[1] => 1
)
)
Where [0] is a good ID and [1] is an amount of this good in a cart.
So I tracked that function actually does what I want and returns true/false as expected, but looks like it only does it inside of itself. Cause if I put print_r($inCart1[1]) inside of a function it does add up and outputs the sum, as expected. But when I output the array at the end of the code (outside the function) the amount doesn't add up, just stays how it was before the function run.
Any ideas why that happens?
Ok, in case someone faces the same problem: found a solution.
Or should I say found a mistake?
The problem was with the foreach ($inCart as $inCart1). Must be replaced with foreach ($inCart as &$inCart1) in order to change array values in a loop. The other way, it just reads values, bit can't change them.

Zend framework foreach loop stop ate the first iteration

I'm actually working on ZF. I have a category table with which, I want to create a tree in order to get display the data as below :
Category
--Sub cat 1
--Sub cat 2
----Su sub cat 1
Another Category
--Sub cat 1
//...etc...
I'm using the fetchAll method to get all my data. Everyting works fine. But then I'm now trying to create my tree into a double foreach loop as below :
$tree = array();
foreach($data as $parent){
$tree[$parent->name] = array();
foreach($data as $child){
if($child->parent_id == $parent->id){
$tree[$parent->name][] = $child->name;
}
}
}
The problem is that the loop stop after the main loop first iteration so I'm just getting the first parent and it's sub category but it does not continue to the second parent.
My database table as the following fields :
id, name, parent_id
Any idea?
EDIT
Thanks to you Thibault, it did work using the good old for loop :
for($i=0;$i<count($data);$i++){
$tree[$data[$i]->name] = array();
for($j=0;$j<count($data);$j++){
if($data[$j]->parent_id == $data[$i]->id){
$tree[$data[$i]->name][] = $data[$j]->name;
}
}
}
You may have a conflict between the cursor of both $data variables.
You should use a copy of $data for the second foreach loop.
Or use for loops with $i and $j index, and call them via $data[$i] and $data[$j] to access the array, so the loops don't get messed up.
EDIT
Happy i could help, but after some research, i created this piece of code :
<?
class o {
public $id;
public $name;
public $parent_id;
function __construct($_id,$_name,$_parent) {
$this->id = $_id;
$this->name = $_name;
$this->parent_id = $_parent;
}
}
$data = array(
new o(1,'toto',0),
new o(2,'truc',1),
new o(3,'machin',1),
new o(4,'bidule',2),
new o(5,'titi',3),
new o(6,'tutu',3),
);
$tree = array();
foreach($data as $parent){
$tree[$parent->name] = array();
foreach($data as $child){
if($child->parent_id == $parent->id){
$tree[$parent->name][] = $child->name;
}
}
}
print_r($tree);
And your code works just fine :
(something must be wrong somewhere else ...)
Array
(
[toto] => Array
(
[0] => truc
[1] => machin
)
[truc] => Array
(
[0] => bidule
)
[machin] => Array
(
[0] => titi
[1] => tutu
)
[bidule] => Array
(
)
[titi] => Array
(
)
[tutu] => Array
(
)
)

Array key exists in multidimensional array

I'm trying to arrange a group of pages in to an array and place them depending on their parent id number. If the parent id is 0 I would like it to be placed in the array as an array like so...
$get_pages = 'DATABASE QUERY'
$sorted = array()
foreach($get_pages as $k => $obj) {
if(!$obj->parent_id) {
$sorted[$obj->parent_id] = array();
}
}
But if the parent id is set I'd like to place it in to the relevant array, again as an array like so...
$get_pages = 'DATABASE QUERY'
$sorted = array()
foreach($get_pages as $k => $obj) {
if(!$obj->parent_id) {
$sorted[$obj->id] = array();
} else if($obj->parent_id) {
$sorted[$obj->parent_id][$obj->id] = array();
}
}
This is where I begin to have a problem. If I have a 3rd element that needs to be inserted to the 2nd dimension of an array, or even a 4th element that needs inserting in the 3rd dimension I have no way of checking if that array key exists. So what I can't figure out is how to detect if an array key exists after the 1st dimension and if it does where it is so I can place the new element.
Here is an example of my Database Table
id page_name parent_id
1 Products 0
2 Chairs 1
3 Tables 1
4 Green Chairs 2
5 Large Green Chair 4
6 About Us 0
Here is an example of the output I'd like to get, if there is a better way to do this I'm open for suggestions.
Array([1]=>Array([2] => Array([4] => Array([5] => Array())), [3] => Array()), 6 => Array())
Thanks in advanced!
Well, essentially you are building a tree so one of the ways to go is with recursion:
// This function takes an array for a certain level and inserts all of the
// child nodes into it (then going to build each child node as a parent for
// its respective children):
function addChildren( &$get_pages, &$parentArr, $parentId = 0 )
{
foreach ( $get_pages as $page )
{
// Is the current node a child of the parent we are currently populating?
if ( $page->parent_id == $parentId )
{
// Is there an array for the current parent?
if ( !isset( $parentArr[ $page->id ] ) )
{
// Nop, create one so the current parent's children can
// be inserted into it.
$parentArr[ $page->id ] = array();
}
// Call the function from within itself to populate the next level
// in the array:
addChildren( $get_pages, $parentArr[ $page->id ], $page->id );
}
}
}
$result = array();
addChildren( $get_pages, $result );
print_r($result);
This is not the most efficient way to go but for a small number of pages & hierarchies you should be fine.

Searching for parts of string in multi level array

Is there a function that allows me to search inside a multidimensional array that goes multiple levels deep? An example of an array can be found below.
What I want is to be able to search in the entire array, regardless of how deep it goes (3 levels deep would be the practical limit though). The search must be done in all of the strings inside the array elements, and to make it even more complex, it needs to be able to find parts of a string in the array (preferably case insensitive).
I've searched for a good class or function that can handle this in a fast and efficient way, but haven't found one so far.
Array
(
[0] => Array
(
[OrderReferenceNumber] => 201100196
[OrderCustomerID] => 01239123
[OrderCustomerName] => test
[OrderHistoryItems] => Array
(
[0] => Array
(
[OrderItem] => productID
[OrderItemGroup] => productName
)
)
)
Much appreciated!
This will search all elements on all levels of the array, and the search is case sensitive. Just pass the search term and the array to search.
class mySearcher
{
protected $search = '';
public function search($search, $arr)
{
$this->search = $search;
$this->searchArr($arr);
}
protected function searchArr($arr)
{
if(is_array($arr))
{
foreach($arr as $value)
{
if(is_array($value))
{
$this->searchArr($value); // this element is an array, so recursively search it
}
else
{
if(stripos($value, $this->search) !== false)
{
// found the search term, do something
echo 'found in: ' . $value . '<br />';
}
}
}
}
}
}
$obj = new mySearcher();
$obj->search('test', $arr); // search for 'test' in the array called $arr

Categories