Skip to content

Commit

Permalink
decompose array compare logic, so that it can be used independently f…
Browse files Browse the repository at this point in the history
…rom json
  • Loading branch information
tiger-seo committed Oct 7, 2016
1 parent b43fce2 commit b843f3c
Show file tree
Hide file tree
Showing 4 changed files with 416 additions and 376 deletions.
148 changes: 148 additions & 0 deletions src/Codeception/Util/ArrayContainsComparator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
<?php
namespace Codeception\Util;

class ArrayContainsComparator
{
/**
* @var array
*/
protected $haystack = [];

public function __construct($haystack)
{
$this->haystack = $haystack;
}

/**
* @return array
*/
public function getHaystack()
{
return $this->haystack;
}

public function containsArray(array $needle)
{
return $needle == $this->arrayIntersectRecursive($needle, $this->haystack);
}

/**
* @author nleippe@integr8ted.com
* @author tiger.seo@gmail.com
* @link http://www.php.net/manual/en/function.array-intersect-assoc.php#39822
*
* @param mixed $arr1
* @param mixed $arr2
*
* @return array|bool
*/
private function arrayIntersectRecursive($arr1, $arr2)
{
if (!is_array($arr1) || !is_array($arr2)) {
return false;
}
// if it is not an associative array we do not compare keys
if ($this->arrayIsSequential($arr1) && $this->arrayIsSequential($arr2)) {
return $this->sequentialArrayIntersect($arr1, $arr2);
}
return $this->associativeArrayIntersect($arr1, $arr2);
}

/**
* This array has sequential keys?
*
* @param array $array
*
* @return bool
*/
private function arrayIsSequential(array $array)
{
return array_keys($array) === range(0, count($array) - 1);
}

/**
* @param array $arr1
* @param array $arr2
* @return array
*/
private function sequentialArrayIntersect(array $arr1, array $arr2)
{
$ret = [];

// Do not match the same item of $arr2 against multiple items of $arr1
$matchedKeys = [];
foreach ($arr1 as $key1 => $value1) {
foreach ($arr2 as $key2 => $value2) {
if (isset($matchedKeys[$key2])) {
continue;
}

$return = $this->arrayIntersectRecursive($value1, $value2);
if ($return !== false && $return == $value1) {
$ret[$key1] = $return;
$matchedKeys[$key2] = true;
break;
}

if ($this->isEqualValue($value1, $value2)) {
$ret[$key1] = $value1;
$matchedKeys[$key2] = true;
break;
}
}
}

return $ret;
}

/**
* @param array $arr1
* @param array $arr2
*
* @return array|bool|null
*/
private function associativeArrayIntersect(array $arr1, array $arr2)
{
$commonKeys = array_intersect(array_keys($arr1), array_keys($arr2));

$ret = [];
foreach ($commonKeys as $key) {
$return = $this->arrayIntersectRecursive($arr1[$key], $arr2[$key]);
if ($return) {
$ret[$key] = $return;
continue;
}
if ($this->isEqualValue($arr1[$key], $arr2[$key])) {
$ret[$key] = $arr1[$key];
}
}

if (empty($commonKeys)) {
foreach ($arr2 as $arr) {
$return = $this->arrayIntersectRecursive($arr1, $arr);
if ($return && $return == $arr1) {
return $return;
}
}
}

if (count($ret) < min(count($arr1), count($arr2))) {
return null;
}

return $ret;
}

private function isEqualValue($val1, $val2)
{
if (is_numeric($val1)) {
$val1 = (string) $val1;
}

if (is_numeric($val2)) {
$val2 = (string) $val2;
}

return $val1 === $val2;
}
}
122 changes: 1 addition & 121 deletions src/Codeception/Util/JsonArray.php
Original file line number Diff line number Diff line change
Expand Up @@ -88,114 +88,7 @@ public function getXmlString()

public function containsArray(array $needle)
{
return $needle == $this->arrayIntersectRecursive($needle, $this->jsonArray);
}

/**
* @author nleippe@integr8ted.com
* @author tiger.seo@gmail.com
* @link http://www.php.net/manual/en/function.array-intersect-assoc.php#39822
*
* @param mixed $arr1
* @param mixed $arr2
*
* @return array|bool
*/
private function arrayIntersectRecursive($arr1, $arr2)
{
if (!is_array($arr1) || !is_array($arr2)) {
return false;
}
// if it is not an associative array we do not compare keys
if ($this->arrayIsSequential($arr1) && $this->arrayIsSequential($arr2)) {
return $this->sequentialArrayIntersect($arr1, $arr2);
}
return $this->associativeArrayIntersect($arr1, $arr2);
}

/**
* This array has sequential keys?
*
* @param array $array
*
* @return bool
*/
private function arrayIsSequential(array $array)
{
return array_keys($array) === range(0, count($array) - 1);
}

/**
* @param array $arr1
* @param array $arr2
* @return array
*/
private function sequentialArrayIntersect(array $arr1, array $arr2)
{
$ret = [];

// Do not match the same item of $arr2 against multiple items of $arr1
$matchedKeys = [];
foreach ($arr1 as $key1 => $value1) {
foreach ($arr2 as $key2 => $value2) {
if (isset($matchedKeys[$key2])) {
continue;
}

$return = $this->arrayIntersectRecursive($value1, $value2);
if ($return !== false && $return == $value1) {
$ret[$key1] = $return;
$matchedKeys[$key2] = true;
break;
}

if ($this->isEqualValue($value1, $value2)) {
$ret[$key1] = $value1;
$matchedKeys[$key2] = true;
break;
}
}
}

return $ret;
}

/**
* @param array $arr1
* @param array $arr2
*
* @return array|bool|null
*/
private function associativeArrayIntersect(array $arr1, array $arr2)
{
$commonKeys = array_intersect(array_keys($arr1), array_keys($arr2));

$ret = [];
foreach ($commonKeys as $key) {
$return = $this->arrayIntersectRecursive($arr1[$key], $arr2[$key]);
if ($return) {
$ret[$key] = $return;
continue;
}
if ($this->isEqualValue($arr1[$key], $arr2[$key])) {
$ret[$key] = $arr1[$key];
}
}

if (empty($commonKeys)) {
foreach ($arr2 as $arr) {
$return = $this->arrayIntersectRecursive($arr1, $arr);
if ($return && $return == $arr1) {
return $return;
}
}
}

if (count($ret) < min(count($arr1), count($arr2))) {
return null;
}

return $ret;
return (new ArrayContainsComparator($this->jsonArray))->containsArray($needle);
}

private function arrayToXml(\DOMDocument $doc, \DOMNode $node, $array)
Expand All @@ -221,19 +114,6 @@ private function arrayToXml(\DOMDocument $doc, \DOMNode $node, $array)
}
}

private function isEqualValue($val1, $val2)
{
if (is_numeric($val1)) {
$val1 = (string) $val1;
}

if (is_numeric($val2)) {
$val2 = (string) $val2;
}

return $val1 === $val2;
}

private function getValidTagNameForInvalidKey($key)
{
static $map = [];
Expand Down
Loading

0 comments on commit b843f3c

Please sign in to comment.