Multi-dimensional array search to preserve parent - php

TL;DR
I have this data: var_export and print_r.
And I need to narrow it down to: http://pastebin.com/EqwgpgAP ($data['Stock Information:'][0][0]);
How would one achieve it? (dynamically)
I'm working with vTiger 5.4.0 CRM and am looking to implement a function that would return a particular field information based on search criteria.
Well, vTiger is pretty weakly written system, looks and feels old, everything comes out from hundreds of tables with multiple joins (that's actually not that bad) etc., but job is job.
The need arose from getting usageunit picklist from Products module, Stock Information block.
Since there is no such function as getField();, I am looking forward to filter it out from Blocks, that is actually gathering the information about fields also.
getBlocks(); then calls something close to getFields();, that again something close to getValues(); and so on.
So...
$focus = new $currentModule(); // Products
$displayView = getView($focus->mode);
$productsBlocks = getBlocks($currentModule, $displayView, $focus->mode, $focus->column_fields); // in theory, $focus->column_fields should/could be narrowed down to my specific field, but vTiger doesn't work that way
echo "<pre>"; print_r($productsBlocks); echo "</pre>"; // = http://pastebin.com/3iTDUUgw (huge dump)
As you can see, the array under the key [Stock Information:], that actually comes out from translations (yada, yada...), under [0][0] contains information for usageunit.
Now, I was trying to array_filter(); the data out from there, but only thing I've managed to get is $productsBlocks stripped down to only contain [Stock Information:] with all the data:
$getUsageUnit = function($value) use (&$getUsageUnit) {
if(is_array($value)) return array_filter($value, $getUsageUnit);
if($value == 'usageunit') return true;
};
$productsUsageUnit = array_filter($productsBlocks, $getUsageUnit);
echo "<pre>"; print_r($productsUsageUnit); echo "</pre>"; // = http://pastebin.com/LU6VRC4h (not that huge of a dump)
And, the result I'm looking forward to is http://pastebin.com/EqwgpgAP, that I've manually got by print_r($productsUsageUnit['Stock Information:'][0][0]);.
How do I achieve this? (dynamically...)

function helper($data, $query) {
$result = array();
$search = function ($data, &$stack) use(&$search, $query) {
foreach ($data as $entry) {
if (is_array($entry) && $search($entry, $stack) || $entry === $query) {
$stack[] = $entry;
return true;
}
}
return false;
};
foreach ($data as $sub) {
$parentStack = array();
if ($search($sub, $parentStack)) {
$result[] = $parentStack[sizeof($parentStack) - 2];
}
}
return $result;
}
$node = helper($data, 'usageunit');
print_r($node);

Related

replace all strings that contains a word in a PHP Array

I'm trying to all URLs that contain http://api.example.com/data/ to https://example.com/data/
in an array from a Database while using the Fat-Free Framework, the code iv tried below gives me
Internal Server Error, Array to string conversion
$f3->route('GET /details/#itemid',
function($f3) {
$arr = array('result' => $f3->get('DBh')->exec('SELECT * FROM DB_table WHERE id=?',$f3->get('PARAMS.itemid')));
str_replace('http://api.example.com/data/', 'https://example.com/data/', $arr);
$f3->mset($arr);
echo \Template::instance()->render('views/details.html');
}
);
Well you've got a couple simple options to help with this. I'm also going to assume you mean to reference $arr['result'] and not just $arr and I'd need to assume you're only looking for one column out of the db column. I'll call this column url.
Option 1
foreach($arr['result'] as $key => $value) {
if(empty($value['url'])) {
continue;
}
$arr['result'][$key]['url'] = str_replace('http://api.example.com/data/', 'https://example.com/data/', $value['url']);
}
Option 2
foreach($arr['result'] as &$value) {
if(empty($value['url'])) {
continue;
}
$value['url'] = str_replace('http://api.example.com/data/', 'https://example.com/data/', $value['url']);
}
Option 3
$arr['result'] = array_map(function($value) {
$value['url'] = str_replace('http://api.example.com/data/', 'https://example.com/data/', $value['url']);
return $value;
}, $arr['result']);
My personal preference for readability and simplicity is Option 2. I believe foreach statements have been optimized to actually run faster than array_map which is......interesting.

PHP getting all files into array issue

I have an small piece of PHP code that needs to put every file in the current directory into an array.
I have done this by making reading the dir with glob() and when it meets another dir it will loop.
My code I have as of now:
<?php
$find = '*';
$result = array();
function find($find)
{
foreach (glob($find) as $entry)
{
$result[] = $entry;
echo $entry.'<br>';
if (is_dir($entry)){
$zoek = ''.$entry.'/*';
find($zoek);
}
}
return $result;
}
print_r(find($find));
?>
When I execute the code the echo print exactly what I want. But the printed array doesn't give me the values I want, it only gives the values in the first dir it will come by then it seems to stop adding the value in the array.
What am I doing wrong?
You need to actually preserve the results you produce in the recursive callings to your function:
<?php
function listNodesInFolder($find) {
$result = [];
foreach (glob($find) as $entry) {
$result[] = $entry;
if (is_dir($entry)) {
$result = array_merge($result, find($entry.'/*'));
}
}
return $result;
}
print_r(find('*'));
Once on it I also fixes a few other issues with your code:
$result should be declared as an array inside your function, that that even if it does not loop you still return an array and not something undefined.
indentation and location of brackets got adjusted to general coding standards, that makes reading your code much easier for others. Get used to those standards, it pays out, you will see.
no need for an extra variable for the search pattern inside the conditional.
a speaking name for the function that tells what it actually does.
you should not name variables and functions alike ("find").
You need to add the result of find() to the array
Edit added array_merge - Cid's idea
<?php
$find = '*';
function find($find)
{
$result = array();
foreach (glob($find) as $entry)
{
$result[] = $entry;
echo $entry.'<br>';
if (is_dir($entry)){
$zoek = ''.$entry.'/*';
$result = array_merge($result, find($zoek));
}
}
return $result;
}
print_r(find($find));
?>

If true use foreach loop, else use while

I'm trying to link the MySQL while loop into foreach loop using something like this :
if($something == true){
foreach($array as $arr){
} else {
while($row = mysql_fetch_array($mysql_query)){
}
// loop instructions
}
It looks so wrong, I know but you see what I am trying to do ?.. I want to grab data from array if $something was true, else then grab data from database
I had another solution idea and its to manually match the array with how $mysql_query works so I can use them both with while only, something like this :
if($something == true){
$mysql_query = array("username" => "$_GET['username']", "password" => "$_GET['password']");
} else {
$mysql_query = mysql_query("SELECT * FROM users WHERE usern......");
}
while($row = mysql_fetch_array($mysql_query)){
...
That's a second way to do it but it looks wrong as well because the first array is normal, I want to match that normal array with how mysql_query builds it so it can fit with the while loop
P.S. : I DO NOT want to repeat writing the loop instructions, I want them both to work with only one like I mentioned above
Put your processing into a function:
function process_data($data) {
// do stuff
}
if($something){
foreach($array as $arr){
process_data($arr);
}
} else {
while($row = mysql_fetch_array($mysql_query)){
process_data($row);
}
}
The other answers here are fine, but you'd be better served just to make sure that $array is a valid array regardless of something ... How about
if (!something){
$array = array();
while($row=mysql_fetch_array($mysql_query)) {$array[] = $row;}
}
foreach($array as $arr){
// do work
}
You'd probably get a better answer if you expanded the scope of what you've explained a bit. Without knowing what the something is and what the data is, plus the ultimate objective then it's hard to tell what kind of structure you should be using.
It seems to me that you could achieve this by just using a function, if the code inside the loop is the same. Like this:
if($something == true)
{
foreach($array as $arr)
{
doWork($arr);
}
}
else
{
while($row = mysql_fetch_array($mysql_query))
{
doWork($row);
}
}
function doWork($arr)
{
//...
}
You cannot nest loop instructions inside a loop like this. You'll need to have two separate loops completely inside the IF statements.
if($something == true){
foreach($array as $arr){
// do work
}
} else {
while($row = mysql_fetch_array($mysql_query)){
// do work
}
}
Maybe you could look at from this viewpoint. And take note that this code uses mysql_fetch_assoc() instead of mysql_fetch_array(). Try both functions and look at the resulting rows with var_dump(). You will see that mysql_fetch_array() has twice as much data. You may want that, but probably not.
if ($something !== true)
{
$array = array();
while($row = mysql_fetch_assoc($mysql_query_result_resource))
{
$array[] = $row;
}
}
foreach($array as $arr)
{
/* PROCESS */
}

Compare differences in Multidimensional array

I have a rather ugly query, and the results from the query are then post-processed using php which turns each row into it's own multidimensional array.
I want to refactor the query but need to make sure I do not change what it returns in any way.
So What I want to do is copy the original query and call that, store the results.
then run the function again with my new query.
Loop over the two arrays of results and compare them for any differences what so ever (keys, values, missing entries, type differences etc).
What is the easiest way to do this?
Essentially I know how to call the two queries etc,
I guess my real question is, at the end once I have my two arrays of the results how do I go through and compare them.
What I would love to end up with is a side by side "print_r" type output with a red line or similar going across highlighting any differences.
First of all, you can use array_uintersect_assoc() like this.
// First get intersecting values
$intersect = array_uintersect_assoc($expected, $results, "checkStructure");
print_r($intersect);
//Then print results that are in intersecting set (e.g. structure of $expected, value of $results
print_r(array_uintersect_assoc($results, $intersect, "checkStructure"));
function checkStructure($x, $y) {
if (!is_array($x) && !is_array($y)) {
return 0;
}
if (is_array($x) && is_array($y)) {
if (count($x) == count($y)) {
foreach ($x as $key => $value) {
if(array_key_exists($key,$y)) {
$x = checkStructure($value, $y[$key]);
if ($x != 0) return -1;
} else {
return -1;
}
}
}
} else {
return -1;
}
return 0;
}
If still not, take help of array_diff()
and array_diff_assoc(). Or try following code.
function multidimensional_array_diff($a1,$a2)
{
$r = array();
foreach ($a2 as $key => $second)
{
foreach ($a1 as $key => $first)
{
if (isset($a2[$key]))
{
foreach ($first as $first_value)
{
foreach ($second as $second_value)
{
if ($first_value == $second_value)
{
$true = true;
break;
}
}
if (!isset($true))
{
$r[$key][] = $first_value;
}
unset($true);
}
}
else
{
$r[$key] = $first;
}
}
}
return $r;
}
Why don't you just make a VIEW that turns an ugly query into something you can just SELECT against? What you're talking about is making a materialized view, something that MySQL doesn't handle as well as other database platforms.
Why not write the results of each query out to a text files then compare the two text files with the diff command?

convert array to object in php

In php I am converting posted data from a form to objects like this:
<?php
...some code...
$post = new stdClass;
foreach ($_POST as $key => $val)
$post->$key = trim(strip_tags($_POST[$key]));
?>
Then in my page I just echo posted data like this :
<?php echo $post->Name; ?>
<?php echo $post->Address; ?>
etc...
This works fine but I have multiple checkboxes that are part of a group and I echo the results of that, like this:
<?php
$colors = $_POST['color_type'];
if(empty($colors))
{
echo("No color Type Selected.");
}
else
{
$N = count($colors);
for($i=0; $i < $N; $i++)
{
echo($colors[$i] . ", ");
}
}
?>
That works when I am just using array, but how do I write this as object syntax?
using your code
function array_to_object($arr) {
$post = new stdClass;
foreach ($arr as $key => $val) {
if(is_array($val)) {
$post->$key = post_object($val);
}else{
$post->$key = trim(strip_tags($arr[$key]));
}
}
return $post;
}
$post = array_to_object($_POST);
or more complex solution
function arrayToObject($array) {
if(!is_array($array)) {
return $array;
}
$object = new stdClass();
if (is_array($array) && count($array) > 0) {
foreach ($array as $name=>$value) {
$name = strtolower(trim($name));
if (!empty($name)) {
$object->$name = arrayToObject($value);
}
}
return $object;
}
else {
return FALSE;
}
}
from http://www.richardcastera.com/blog/php-convert-array-to-object-with-stdclass
why would you want that? What's wrong with an array?
Use Object Oriented Programming, which might be what you are looking for. Treat it as an object, by making a class called Color and doing $colors[$i] = new Color();
This way you can do whatever you want with it, and add functions to it.
Pretty simple -- when you attach the color_type key to your object, it'll become an array that's a property of your object. This is most likely what you want: you probably won't want to turn that array into its own stdClass-based object, because then you won't be able to iterate through all the values (as easily). Here's a snippet:
<?php
// putting in both of these checks prevents you from throwing an E_WARNING
// for a non-existent property. E_WARNINGs aren't dangerous, but it makes
// your error messages cleaner when you don't have to wade through a bunch
// of E_WARNINGS.
if (!isset($post->color_type) || empty($post->color_type)) {
echo 'No colour type selected.'; // apologies for the Canadian spelling!
} else {
// this loop does exactly the same thing as your loop, but it makes it a
// bit more succinct -- you don't have to store the count of array values
// in $N. Bit of syntax that speeds things up!
foreach ($post->color_type as $thisColor) {
echo $thisColor;
}
}
?>
Hope this helps! Of course, in a real-life setting, you'll want to do all sorts of data validation and cleaning -- for instance, you'll want to check that the browser actually passed an array of values for $_POST['color_type'], and you'll want to clean the output in case someone is trying to inject an exploit into your page (by going echo htmlspecialchars($thisColor); -- this turns all characters like < and > into HTML entities so they can't insert JavaScript code).

Categories