phpunit fails asserting that two arrays are equal, but shows no difference - php

Here is what phpunit says:
1) Asgard\Entity\Tests\EntityTest::testToArray
Failed asserting that two arrays are equal.
--- Expected
+++ Actual
## ##
Array (
'id' => null
'title' => 'Test Title'
'content' => 'Test Content'
'published' => 2015-03-04T11:19:50+0000
'comments' => Array (
0 => Array (
'id' => null
'content' => 'foo'
'published' => 2015-03-04T11:19:50+0000
'another_property' => null
'news' => null
)
1 => Array (
'id' => null
'content' => 'bar'
'published' => 2015-03-04T11:19:50+0000
'another_property' => null
'news' => null
)
2 => Array (
'id' => null
'content' => 'baz'
'published' => 2015-03-04T11:19:50+0000
'another_property' => null
'news' => null
)
)
'another_property' => null
)
https://travis-ci.org/asgardphp/asgard/jobs/53029084
There is no difference between "expected" and "actual". The tests usually pass, but sometimes would fail on this.

Found the issue. Elements were not in the same order. A bit annoying though that the output doesn't show it.
I have replaced assertEquals with:
$this->assertTrue($this->similar_arrays($arr1, $arr2));
protected function similar_arrays($a, $b) {
if(is_array($a) && is_array($b)) {
if(count(array_diff(array_keys($a), array_keys($b))) > 0)
return false;
foreach($a as $k => $v) {
if(!$this->similar_arrays($v, $b[$k]))
return false;
}
return true;
}
else
return $a === $b;
}

Since you're using DateTime in your tests - Are you sure you aren't getting test that start in one second, and finish in another so there is a second difference in the timestamps depending on which stage you look at them? - Using dynamic dates and time in tests is a pretty common reason for occasional failed tests.

Check if you have EOL in your values.
If you have a value like so:
'x' => 'line1
line2'
change it to
'x' => "line1\nline2"
Note: this may not answer direct issue the OP had, but this is what worked for me.

Related

how to turn this function to be recursive with multiple dimensional array?

Hello I am think about how to build this array with a recursive function with a lot of layer.
So the data would like that.
id belongs_to
1a NULL
2a NULL
3a 1a
4a NULL
5a 2a
And non-recursive function like:
foreach ($first_layer as $first_layer_obj) {
$array[$first_layer_obj->id] = [];
$second_layer = /* SELECT id FROM client WHERE belongs_to $first_layer_obj->id */;
foreach ($second_layer as $second_layer_obj) {
$array[$first_layer_obj->id][$second_layer_obj->id] = [];
$third_layer = /* SELECT id FROM client WHERE belongs_to $second_layer_obj->id */;
foreach ($third_layer as $third_layer_obj->id) {
$array[$first_layer_obj->id][$second_layer_obj->id][$third_layer_obj->id] = [];
}
}
I am expecting the output is:
array(3) {
["1a"]=>
array(1){
["3a"]=>[]
}
["2a"]=>
array(1){
["5a"]=>[]
}
["4a"]=>[]
}
Certainly the first piece of advice that I have is, you should avoid performing recursive/iterated calls to your database. You should make a single call to extract all of the desired rows in a single result set and let php do the hard part.
I've decided to try a non-recursive approach. To permit this, the result set must be prepared so that "grander" children are listed first. Now, I realize that it is entirely possible that your sample data doesn't actually represent your project values and sorting cannot be used to prepare the result set adequately -- you'll have to let me know (and perhaps update your question with more accurate sample data).
[see inline comments for what's happening in my script]
*If you aren't using php7+, then my null coalescing operator ($row1['children'] ?? []) will cause issues. You can use: (isset($row1['children']) ? $row1['children'] : []
Code: (Demo)
// use ORDER BY belongs_to DESC, id ASC ... or usort() to prepare result set
$resultset = [
['id' => '6a', 'belongs_to' => '5a'],
['id' => '5a', 'belongs_to' => '3a'],
['id' => '8a', 'belongs_to' => '3a'],
['id' => '3a', 'belongs_to' => '1a'],
['id' => '1a', 'belongs_to' => null],
['id' => '2a', 'belongs_to' => null],
['id' => '4a', 'belongs_to' => null],
['id' => '7a', 'belongs_to' => null]
];
foreach ($resultset as $index1 => &$row1) { // make input array modifiable by reference (not working with a copy)
if ($row1['belongs_to']) { // original belongs_to value is not null (not a top-level parent)
foreach ($resultset as $index2 => $row2) { // search for targeted parent
if ($row2['id'] == $row1['belongs_to']) { // parent found
$resultset[$index2]['children'][] = [$row1['id'] => $row1['children'] ?? []]; // store original row as child
unset($resultset[$index1]); // remove original row (no reason to iterate it again in outer loop)
break; // halt inner loop (no reason to iterate further)
}
}
} else { // original belongs_to value is null (top-level parent)
$output[$row1['id']] = $row1['children'] ?? []; // store children to top
}
}
var_export($output);
Output:
array (
'1a' =>
array (
0 =>
array (
'3a' =>
array (
0 =>
array (
'5a' =>
array (
0 =>
array (
'6a' =>
array (
),
),
),
),
1 =>
array (
'8a' =>
array (
),
),
),
),
),
'2a' =>
array (
),
'4a' =>
array (
),
'7a' =>
array (
),
)

Unset the key in multidimensional array is not working

I am trying to unset the key which is equal to 'null' in my multidimensional array but the codes I've work with is not working so I tried to run it online. But even in online it does not work so I think there is something wrong in my codes.
My link for code is https://eval.in/591584
And this is my array:
$array = array(
'6' => array(
'null' =>array(
'null'=>array(
'11:04'=>array(
'id' => '22'
)
)
),
'1'=>array(
'2'=>array(
'11:04'=>array(
'id' => '22'
)
)
),
)
);
What I want is to remove the key with name null.
The output I want is below where the null key is unset:
$array = array(
'6' => array(
'1'=>array(
'2'=>array(
'11:04'=>array(
'id' => '22'
)
)
),
)
);
The code I've done so far is:
foreach($array as $devp => $dev){
foreach($dev as $comp => $com){
if($comp == null){
unset($array[$devp][$comp]);
}
}
}
But it's not working. I declared this condition ($comp == null) as comparing If $comp is equal to null. It should unset the array. What am I missing please help me.
In PHP null is a special datatype. And your key with value 'null' is a string.
So proper comparison is:
if ($comp == 'null') { // see quotes?
// do something
}

Is it possible to detect key type with json_encode?

Quite a difficult to explain, but for example i have an array:
$lol = array(
'key' => 'value',
'key_1' => 'value 1',
'simple_value',
'0' => 'lol',
'key_array' => array(
'key_in_second' => 'value_with_key_in_second',
'value_in_second_array',
)
);
After json_encode it would be
{"key":"value","key_1":"value 1","0":"lol","key_array":{"key_in_second":"value_with_key_in_second","0":"value_in_second_array"}}
So is it possible somehow detect if in php array had the key or note? In my example elements 'simple_value', '0' => 'lol' have same key.
PHP doesn't care if the number 0 is in quotes or not. It is storing it as numeric 0, same as 'value_in_second_array' will be 0, as it was the first element without a key.
Basically,
array('0'=>'lol') is the same as array(0=>'lol') is the same is array('lol');
You'll see simple_value dissappeared, as it was overwritten with lol.
The JSON accurately reflects the php. For example, if you had this code:
<?php
$lol = array(
'key' => 'value',
'key_1' => 'value 1',
'simple_value',
'0' => 'lol',
'key_array' => array(
'key_in_second' => 'value_with_key_in_second',
'value_in_second_array',
)
);
print_r($lol);
The output would be:
Array
(
[key] => value
[key_1] => value 1
[0] => lol
[key_array] => Array
(
[key_in_second] => value_with_key_in_second
[0] => value_in_second_array
)
)
What happened here is that as simple_value didn't have a key, it was assigned a key of 0, but was then overwritten with lol which came next. You can also see how the value_in_second_array was automatically assigned a key of 0.
So, nothing to do with json_encode, you just never had the data in PHP.

php multidimensional array get first date value

I need help once again. I have an array and I need to extract earliest day weight value.
EDIT - EDIT - EDIT
array (
3 =>
array (
'id' => '20110211',
'Date' => '2011-02-11',
'Weight' => '195',
),
4 =>
array (
'id' => '20110213',
'Date' => '2011-02-13',
'Weight' => '160',
),
6 =>
array (
'id' => '20110310',
'Date' => '2011-03-10',
'Weight' => '200',
),
12 =>
array (
'id' => '20110301',
'Date' => '2011-03-01',
'Weight' => '55',
),
21 =>
array (
'id' => '20110215',
'Date' => '2011-02-15',
'Weight' => '120',
),
25 =>
array (
'id' => '20110322',
'Date' => '2011-03-22',
'Weight' => '250',
),
)
I've edited this and this code works:
function sortByDate ($arr1, $arr2)
{
return strcmp($arr1['Date'], $arr2['Date']);
}
// $arr is your array
usort($weight_tracker, 'sortByDate');
$earliest = $weight_tracker[0]['Weight'];
echo $earliest;
But since I have a form on this page which updates the array when array is updated - I got message Fatal error: Cannot use string offset as an array in
EDIT -> I've re-declared this as string, hence the ERROR ! be careful when using global and includes as everything can become a mess ! PHP is forgiving, but that "forgiveness" can cost a lot of time later on... :)
Thanks,
Peter
You could sort the array with a custom callback using usort() and then take the first element.
// $arr is your array
usort($arr, 'sortByDate');
$earliest = $arr[0];
function sortByDate ($arr1, $arr2)
{
return strcmp($arr1['Date'], $arr2['Date']);
}
This is one way of doing it:
function filter_min($a, $b) {
return ($a['Date'] < $b['date']) ? $a : $b;
}
$result = array_reduce($array, 'filter_min');
echo $result['Weight'];
Another way is to simply iterate over the array and find the smallest date.
$smallest = null; // array index of entry with smallest weight.
foreach ($array as $idx => $data) {
if (($data['Weight'] < $array[$smallest]['Weight']) || (is_null($smallest))) {
$smallest = $idx; // found a small weight, so save the index
}
}
echo $array[$smallest]['Date'];
I noticed that the dates are in reverse order with the latest date being pulled in first, and the earliest date last. Will it always be like that? If so, you can do this:
$index = count($array) - 1;
$earliestdate = $array[$index]['Date'];
You could also use array_reverse() to invert the array and make the first element the formerly last element.
If this is being pulled in from MySQL you could also alter the query to ORDER BY 'Date' DESC (or is it ASC that would get you what you want, can't remember)

PHP / Mongo: how do you update nested data?

I've been playing around with Mongo for about a week now and I still can't work out how to modify nested arrays in Mongo with php.
So here is a sample document...
array (
'_id' => new MongoId("4cb30f560107ae9813000000"),
'email' => 'mo#maurice-campobasso.com',
'firstname' => 'Maurice',
'lastname' => 'Campobasso',
'password' => 'GOD',
'productions' =>
array (
0 =>
array (
'title' => 'a',
'date' => '1286811330.899',
),
1 =>
array (
'title' => 'b',
'date' => '1286811341.183',
),
2 =>
array (
'title' => 'c',
'date' => '1286811350.267',
),
3 =>
array (
'title' => 'd',
'date' => '1286811356.05',
),
),
)
What I wan't to do is delete an array inside the productions array, but I can't work out how. I've been playing with 'update('$pull' => ...etc)' but I haven't been able to make it work.
OK, there are a few ways to do this. In your case, I would do something like
mymongoobject.update( $unset : { "productions.2" : 1 } }
That's basically saying to unset the ".2" element of productions. Some docs here.
Now $pull should also work, but it's a little tougher because "productions" is actually an array of arrays (or objects with sub-objects). So you'd have to match arrays exactly:
mymongoobject.update( $pull : { "productions" : {'title':'d', 'date':'1286811356.05'} }
In the case above, the unset is probably the easiest option (though it will leave a "hole" in the array)
That is actually very easy, unlike traditional sql stuff you just modify the whole data and pass it back.
$cursor = $mongo->yourDB->yourCollection->findOne("_id",4cb30f560107ae9813000000);
//let's remove last item on productions
array_splice($cursor["productions"],2);
//and update the mongo document
echo $mongo->yourDB->yourCollection->update($cursor);
//it echoes 1 if successful
hope it helps.

Categories