I know this is asked a lot, but I can't get it to work correctly.
What I have
A PHP function that get's the page id (fk_page).
Inside this function the same function is called to look for child pages.
My Database looks like this:
The PHP Code looks like this:
private function createNav($parent = 0, $sub = false) {
// *!* Create Nav
$getNavPage = $this->model->loadNav($parent); // array of menu items (fk_page) that have $parent as parent.
$NavPage = 0;
foreach ($getNavPage as $getPage) {
$NavPage = intval($getPage["fk_page"]);
$subnav = $this->createNav($NavPage, true); // get childs (recursive loop) and save fk_page in $subnav
if($sub === false) $this->navArr[$parent][] = $NavPage;
else $this->navArr[$parent][][] = $NavPage;
}
return $NavPage;
}
The model does the following
public function loadNav($parent) {
$stmt = $this->pdo->prepare("SELECT fk_page FROM nav WHERE fk_parentpage = " . $parent . ";");
$stmt->execute();
return $stmt->fetchAll();
}
Now the result is an array that looks like this
array(3) {
[0]=>
array(3) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
int(3)
}
[2]=>
array(1) {
[0]=>
array(1) {
[0]=>
int(4)
}
}
[3]=>
array(2) {
[0]=>
array(1) {
[0]=>
int(5)
}
[1]=>
array(1) {
[0]=>
int(6)
}
}
}
What I would like to have as a result:
array(3) {
[0]=>
array(3) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
array(1) {
[0]=>
array(1) {
[0]=>
int(4)
}
}
[3]=>
array(2) {
[0]=>
array(1) {
[0]=>
int(5)
}
[1]=>
array(1) {
[0]=>
int(6)
}
}
}
}
I believe that the createNav() must run before the array element is written (or even inside the array $this->NavArr), but I wasn't really succesfull.
Here is an example that uses local data but mimics what you're trying to do:
$data_array = array(
0 => array(1, 2, 3)
, 2 => array(4)
, 3 => array(5, 6)
);
function get_kids($id = 0) {
global $data_array;
if(isset($data_array[$id])) {
return $data_array[$id];
}
else {
return array();
}
}
function create_navigation($parent_id = 0) {
// Check for children
$children_array = get_kids($parent_id);
// No children - just return the parent
if (empty($children_array)) {
return $parent_id;
}
// Children!
foreach ($children_array as $key => $child_id) {
$children_array[$key] = create_navigation($child_id);
}
return array($parent_id => $children_array);
}
echo '<pre>';
$nav = create_navigation(0);
var_dump($nav);
print_r($nav);
echo '</pre>';
The $data_array is used instead of your database.
The get_kids function is your loadNav method.
The create_navigation function is your createNav method.
This produces a var_dump:
array(1) {
[0]=>
array(3) {
[0]=>
int(1)
[1]=>
array(1) {
[2]=>
array(1) {
[0]=>
int(4)
}
}
[2]=>
array(1) {
[3]=>
array(2) {
[0]=>
int(5)
[1]=>
int(6)
}
}
}
}
And a print_r:
Array
(
[0] => Array
(
[0] => 1
[1] => Array
(
[2] => Array
(
[0] => 4
)
)
[2] => Array
(
[3] => Array
(
[0] => 5
[1] => 6
)
)
)
)
The problem with your original code is you were assigning IDs to the class variable $this->navArr instead of using recursion to return the child elements ($subnav).
Related
I wrote a regular expression that parses a JS file and returns all the named functions and breaks it up into 3 parts, you can see it in action here: https://regex101.com/r/sXrHLI/1
I am analyzing the results and hoping to sort by the string length of the functionBody but I can't figure out how to do it.
Here is how I am capturing it:
$js = file_get_contents('scripts.js');
$regex = "/function\s+(?<functionName>\w+)\s*\((?<functionArguments>(?:[^()]+)*)?\s*\)\s*(?<functionBody>{(?:[^{}]+|(?-1))*+})/";
preg_match_all($regex, $js, $jsFunctions);
dd($jsFunctions);
This spits out an array like this:
array(7) {
[0]=>
array(3) {
[0]=>
string(54) "function smallFunction(arg) {
BodyofSmallFunction
}"
[1]=>
string(62) "function mediumFunction(arg, arg2) {
BodyofMediumFunction
}"
[2]=>
string(80) "function largeFunction(arg, arg2, arg3=4) {
BodyofLargeFunction, extra text
}"
}
["functionName"]=>
array(3) {
[0]=>
string(13) "smallFunction"
[1]=>
string(14) "mediumFunction"
[2]=>
string(13) "largeFunction"
}
[1]=>
array(3) {
[0]=>
string(13) "smallFunction"
[1]=>
string(14) "mediumFunction"
[2]=>
string(13) "largeFunction"
}
["functionArguments"]=>
array(3) {
[0]=>
string(3) "arg"
[1]=>
string(9) "arg, arg2"
[2]=>
string(17) "arg, arg2, arg3=4"
}
[2]=>
array(3) {
[0]=>
string(3) "arg"
[1]=>
string(9) "arg, arg2"
[2]=>
string(17) "arg, arg2, arg3=4"
}
["functionBody"]=>
array(3) {
[0]=>
string(26) "{
BodyofSmallFunction
}"
[1]=>
string(27) "{
BodyofMediumFunction
}"
[2]=>
string(38) "{
BodyofLargeFunction, extra text
}"
}
[3]=>
array(3) {
[0]=>
string(26) "{
BodyofSmallFunction
}"
[1]=>
string(27) "{
BodyofMediumFunction
}"
[2]=>
string(38) "{
BodyofLargeFunction, extra text
}"
}
}
Now I want to sort by the functionBody size (they already appear sorted, but are really just in the order I had them in) but none of the code examples I can find using array_multisort or array_map seems to quite fit my array that PHP automatically builds. I would have loved to have had them in more of a consolidated tree format, but that wasn't my choice.
function sort_by_length($arrays) {
$lengths = array_map('count', $arrays);
asort($lengths);
$return = array();
foreach(array_keys($lengths) as $k)
$return[$k] = $arrays[$k];
return $return;
}
I was able to figure it out using a method described here: https://www.codepunker.com/blog/3-solutions-for-multidimensional-array-sorting-by-child-keys-or-values-in-PHP
$js = file_get_contents('scripts.js');
$regex = "/function\s+(?<functionName>\w+)\s*\((?<functionArguments>(?:[^()]+)*)?\s*\)\s*(?<functionBody>{(?:[^{}]+|(?-1))*+})/";
preg_match_all($regex, $js, $jsFunctions);
$num_results = count($jsFunctions[3]);
function sortRegex(){
global $jsFunctions, $num_results;
for( $j=0; $j <= $num_results; $j++){
unset($jsFunctions[$j]);
if ( strlen($jsFunctions["functionBody"][$j]) < strlen($jsFunctions["functionBody"][$j-1]) ){
$functionBody = $jsFunctions["functionBody"][$j];
$jsFunctions["functionBody"][$j] = $jsFunctions["functionBody"][$j-1];
$jsFunctions["functionBody"][$j-1]=$functionBody;
$functionName = $jsFunctions["functionName"][$j];
$jsFunctions["functionName"][$j] = $jsFunctions["functionName"][$j-1];
$jsFunctions["functionName"][$j-1]=$functionName;
$functionArguments = $jsFunctions["functionArguments"][$j];
$jsFunctions["functionArguments"][$j] = $jsFunctions["functionArguments"][$j-1];
$jsFunctions["functionArguments"][$j-1]=$functionArguments;
sortRegex();
}
}
}
sortRegex();
You could now loop over it again and combine the items into a nested tree format if you wanted to.
$refinedJS = array();
for( $j=0; $j < $num_results; $j++){
$refinedJS[$j]= array(
"functionName"=>$jsFunctions["functionName"][$j],
"functionArguments"=>$jsFunctions["functionArguments"][$j],
"functionBody"=>$jsFunctions["functionBody"][$j]
);
}
print_r($refinedJS);
This will bring back the results like this:
Array
(
[0] => Array
(
[functionName] => smallFunction
[functionArguments] => arg
[functionBody] => {
BodyofSmallFunction
}
)
[1] => Array
(
[functionName] => mediumFunction
[functionArguments] => arg, arg2
[functionBody] => {
BodyofMediumFunction
}
)
[2] => Array
(
[functionName] => largeFunction
[functionArguments] => arg, arg2, arg3=4
[functionBody] => {
BodyofLargeFunction, extra text
}
)
)
I have a big array which looks like this:
array(2) {
["Final Fantasy VII"]=>
array(5) {
["rows"]=>
array(2) {
[0]=>
array(6) {
["price"]=>
string(5) "11.69"
["price_old"]=>
string(4) "4.66"
["currency"]=>
string(4) "euro"
["portal"]=>
string(0) ""
["link"]=>
string(77) "https://de.gamesplanet.com/game/final-fantasy-vii-download--1001-1?ref=gmkeys"
["shop"]=>
string(4) "9507"
}
[1]=>
array(6) {
["price"]=>
string(5) "14.99"
["price_old"]=>
...
}
}
}
["Battlefield 1"]=>
array(3) {
["rows"]=>
array(2) {
[0]=>
array(6) {
["price"]=>
...
}
[1]=>
array(6) {
["price"]=>
...
}
}
}
}
And I want to get only certain parts of this array where the name is matching my searched title. So, I use this code for that:
function createACFRepeater($title){
$repeater = array();
if(searchForGameXML($title)){
$count = count($GLOBALS["productsXML"][$title]['rows']);
for($i = 0; $i < $count; $i++){
array_push($repeater, $GLOBALS["productsXML"][$title]['rows'][$i]);
}
return $repeater;
}else{
return $repeater;
}
}
My problem now is that the the $repeater array looks like this:
array(2) {
[0]=>
array(6) {
["price"]=>
string(5) "19.98"
["price_old"]=>
...
}
[1]=>
array(6) {
["price"]=>
string(4) "7.99"
["price_old"]=>
...
}
}
There is a numeric key which is pointing to the array [0] => .... But what I want is simply an array in a array without any associative relations...
How can I create an array which looks like this:?
array(2) {
array(6) {
["price"]=>
string(5) "19.98"
["price_old"]=>
...
}
array(6) {
["price"]=>
string(4) "7.99"
["price_old"]=>
...
}
}
Greetings and Thank You!
According to the array definition it is impossible. Any array item must have key and value, documentation for array starts from:
An array in PHP is actually an ordered map. A map is a type that associates values to keys
You will always have numeric keys. As #lubart already said: it's impossible to have an array without keys. Btw., all of the the follwing arrays are completely equal:
$array1 = array([0] => array([0] => 'hi', [1] => array([0] => '23.5')));
$array2 = array(array('hi', array('23.5')));
$array3 = [['hi', ['23.5']]];
$array4 = [ [0] => [ [0] => 'hi', [1] => [ [0] => '23.5' ] ] ];
i got an Array like:
array(127) {
[0]=>
array(2) {
[0]=>
string(14) "Info"
[1]=>
int(9) "28491231"
}
[1]=>
array(2) {
[0]=>
string(16) "description"
[1]=>
string(9) "Webserver"
}
[2]=>
array(2) {
[0]=>
string(11) "server_type"
[1]=>
string(9) "HOST"
}
[3]=>
array(2) {
[0]=>
string(2) "os"
[1]=>
string(7) "Windows"
}
....
What would the fastest way to search for "Info" in this Array and get the Value "28491231" ?
Thanks
I assume you have an array like this:
$sourceArray = array(
array('Info', '28491231'),
array('description', 'webserver'),
array('server_type', 'HOST'),
array('os', 'Windows'),
);
i.e.
If you want to get something specific from it, you can create a helper function like this:
// Helper Function
function getData($targetKey, $sourceArray) {
foreach ($sourceArray as $arrayItem) {
list ($key, $val) = $arrayItem;
if ($key == $targetKey)
return $val;
}
return false;
}
// Usage
var_dump(getData('Info', $sourceArray));
Ouputs:
I have array like the following
Array ( [0] => Array ( [0] => 5 ) [1] => Array ( [0] => 6 [1] => 7 ) )
Now I want only values of this two dimensional array
The result should be array(5,6,7)
Bit of a hack/neat trick depending on how you look at it ;)
$result = call_user_func_array('array_merge', $a);
You're looking for array_values() which returns an array of all array values, sans-keys.
http://php.net/manual/en/function.array-values.php
Update:
Alternatively for an already multi-dimensional array, you can use the following recursive function (borrowed from http://davidwalsh.name/flatten-nested-arrays-php):
function array_flatten($array,$return)
{
for($x = 0; $x <= count($array); $x++)
{
if(is_array($array[$x]))
{
$return = array_flatten($array[$x],$return);
}
else
{
if($array[$x])
{
$return[] = $array[$x];
}
}
}
return $return;
}
Something like this
array_merge($a[0], $a[1]);
function flattenArray($array) {
$flattened = array();
foreach($array as $value) {
if (is_array($value)) {
$flattened = array_merge($flattened, flattenArray($value));
} else {
$flattened[] = $value;
}
}
return $flattened;
}
$array = array(1, array(2, 3), array(4, array(5, 6)));
var_dump($array, flattenArray($array));
Output
array(3) {
[0]=>
int(1)
[1]=>
array(2) {
[0]=>
int(2)
[1]=>
int(3)
}
[2]=>
array(2) {
[0]=>
int(4)
[1]=>
array(2) {
[0]=>
int(5)
[1]=>
int(6)
}
}
}
array(6) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
int(3)
[3]=>
int(4)
[4]=>
int(5)
[5]=>
int(6)
}
CodePad.
$result = array();
foreach($parentArray as $pa)
{
if(is_array($pa))
$result= array_merge($result, $pa);
else
$result[] = $pa;
}
Use $result.
I need to split the following
$str = 'min(5,6,7,88),email'
$str= 'min(5,6,7,88),!email,max(6,5),alpha_numeric,required'//other possibilities
so it returns an array like so:
array(
[0]=>array(
[0]=>'min',
[1]=>array(5,6,7,88)
)
[1]=>array(
[0]=>'email'
)
)
is this possible ? btw email and min could be anything really , aswell as 5 6 7 88
I think preg_match is best suited for this particular case. However, preg_match alone cannot format the output as you want it.
preg_match('/(\w+)\(([0-9,]+)\),(\w+)+/', $str, $values);
$output = array(
array($values[1], explode(',', $values[2])),
array($values[3]),
);
Given the following:
$test = "min(5,6,7,88),email";
$_ = null;
if (preg_match('/^(?<first>\w+)\((?<array>(?:[0-9]+\x2C*)+)\)\x2C(?<last>\w+)$/',$test,$_))
{
$result = Array(
Array($_['first'],explode(',',$_['array'])),
Array($_['last'])
);
print_r($result);
}
Renders the following result:
Array
(
[0] => Array
(
[0] => min
[1] => Array
(
[0] => 5
[1] => 6
[2] => 7
[3] => 88
)
)
[1] => Array
(
[0] => email
)
)
function parse($str) {
$str = str_replace(array('(',')'),"0x00",$str);
$strArray = explode("0x00",$str);
$tokens = array();
$tokenRef = 0;
foreach($strArray as $tokenID => $tokenValue) {
if (($tokenID % 2) == 1) {
--$tokenRef;
$tokens[$tokenRef++][1] = '('.$tokenValue.')';
} else {
$tokenList = explode(",",$tokenValue);
foreach($tokenList as $token) {
if ($token != '') {
$tokens[$tokenRef++][0] = $token;
}
}
}
}
return $tokens;
}
$str = 'min(5,6,7,88),email';
$split = parse($str);
echo '<pre>';
var_dump($split);
echo '</pre>';
echo '<br />';
$str = 'min(5,6,7,88),!email,max(6,5),alpha_numeric,required';
$split = parse($str);
echo '<pre>';
var_dump($split);
echo '</pre>';
echo '<br />';
Gives
array(2) {
[0]=>
array(2) {
[0]=>
string(3) "min"
[1]=>
string(10) "(5,6,7,88)"
}
[1]=>
array(1) {
[0]=>
string(5) "email"
}
}
and
array(5) {
[0]=>
array(2) {
[0]=>
string(3) "min"
[1]=>
string(10) "(5,6,7,88)"
}
[1]=>
array(1) {
[0]=>
string(6) "!email"
}
[2]=>
array(2) {
[0]=>
string(3) "max"
[1]=>
string(5) "(6,5)"
}
[3]=>
array(1) {
[0]=>
string(13) "alpha_numeric"
}
[4]=>
array(1) {
[0]=>
string(8) "required"
}
}