&$v) { static::normalize($v); } unset($v); } if (is_object($value)) { $sorted = (array) $value; // foreign baskets might not sort as we do: ksort($sorted); foreach ($sorted as $k => &$v) { static::normalize($v); } unset($v); $value = $sorted; // foreign baskets might not sort those lists correctly: if (isset($value->list_name) && isset($value->entries)) { static::sortListBy('entry_name', $value->entries); } if (isset($value->fields)) { static::sortListBy('datafield_id', $value->fields); } } } protected static function sortListBy($key, &$list) { usort($list, function ($a, $b) use ($key) { return $a->$key > $b->$key ? -1 : 1; }); } public static function equals($a, $b) { if (is_scalar($a)) { return $a === $b; } if ($a === null) { return $b === null; } // Well... this is annoying :-/ $a = Json::decode(Json::encode($a, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE)); $b = Json::decode(Json::encode($b, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE)); if (is_array($a)) { // Empty arrays VS empty objects :-( This is a fallback, not needed unless en/decode takes place if (empty($a) && is_object($b) && (array) $b === []) { return true; } if (! is_array($b)) { return false; } if (array_keys($a) !== array_keys($b)) { return false; } foreach ($a as $k => $v) { if (array_key_exists($k, $b) && static::equals($b[$k], $v)) { continue; } return false; } return true; } if (is_object($a)) { // Well... empty arrays VS empty objects :-( if ($b === [] && (array) $a === []) { return true; } if (! is_object($b)) { return false; } // Workaround, same as above if (isset($a->list_name) && isset($a->entries)) { if (! isset($b->entries)) { return false; } static::sortListBy('entry_name', $a->entries); static::sortListBy('entry_name', $b->entries); } if (isset($a->fields) && isset($b->fields)) { static::sortListBy('datafield_id', $a->fields); static::sortListBy('datafield_id', $b->fields); } foreach ((array) $a as $k => $v) { if (property_exists($b, $k) && static::equals($v, $b->$k)) { continue; } if (! property_exists($b, $k)) { if ($v === null) { continue; } // Deal with two special defaults: if ($k === 'set_if_format' && $v === 'string') { continue; } if ($k === 'disabled' && $v === false) { continue; } } return false; } foreach ((array) $b as $k => $v) { if (! property_exists($a, $k)) { if ($v === null) { continue; } // Once again: if ($k === 'set_if_format' && $v === 'string') { continue; } if ($k === 'disabled' && $v === false) { continue; } return false; } } return true; } throw new RuntimeException("Cannot compare " . Error::getPhpTypeName($a)); } }