mirror of
https://gh.wpcy.net/https://github.com/rilustrisimo/freescout-support.git
synced 2026-04-26 14:02:20 +08:00
434 lines
11 KiB
PHP
434 lines
11 KiB
PHP
<?php declare(strict_types=1);
|
|
/**
|
|
* Part of Windwalker project.
|
|
*
|
|
* @copyright Copyright (C) 2019 LYRASOFT.
|
|
* @license LGPL-2.0-or-later
|
|
*/
|
|
|
|
namespace Windwalker\Structure;
|
|
|
|
/**
|
|
* Class StructureHelper
|
|
*
|
|
* @since 2.0
|
|
*/
|
|
class StructureHelper
|
|
{
|
|
/**
|
|
* Property objectStorage.
|
|
*
|
|
* @var \SplObjectStorage
|
|
*/
|
|
private static $objectStorage;
|
|
|
|
/**
|
|
* Load the contents of a file into the structure
|
|
*
|
|
* @param string $file Path to file to load
|
|
* @param string $format Format of the file [optional: defaults to JSON]
|
|
* @param array $options Options used by the formatter
|
|
*
|
|
* @return array Return parsed array.
|
|
*
|
|
* @since 2.1
|
|
*/
|
|
public static function loadFile($file, $format = Format::JSON, $options = [])
|
|
{
|
|
if (!is_file($file)) {
|
|
throw new \InvalidArgumentException('No such file: ' . $file);
|
|
}
|
|
|
|
if (strtolower($format) == Format::PHP) {
|
|
$data = include $file;
|
|
} else {
|
|
$data = file_get_contents($file);
|
|
}
|
|
|
|
return static::loadString($data, $format, $options);
|
|
}
|
|
|
|
/**
|
|
* Load a string into the structure
|
|
*
|
|
* @param string $data String to load into the structure
|
|
* @param string $format Format of the string
|
|
* @param array $options Options used by the formatter
|
|
*
|
|
* @return array Return parsed array.
|
|
*
|
|
* @since 2.1
|
|
*/
|
|
public static function loadString($data, $format = Format::JSON, $options = [])
|
|
{
|
|
// Load a string into the given namespace [or default namespace if not given]
|
|
$class = static::getFormatClass($format);
|
|
|
|
return $class::stringToStruct($data, $options);
|
|
}
|
|
|
|
/**
|
|
* Get a namespace in a given string format
|
|
*
|
|
* @param array|object $data The structure data to convert to markup string.
|
|
* @param string $format Format to return the string in
|
|
* @param mixed $options Parameters used by the formatter, see formatters for more info
|
|
*
|
|
* @return string Namespace in string format
|
|
*
|
|
* @since 2.1
|
|
*/
|
|
public static function toString($data, $format = Format::JSON, $options = [])
|
|
{
|
|
$class = static::getFormatClass($format);
|
|
|
|
return $class::structToString($data, $options);
|
|
}
|
|
|
|
/**
|
|
* getFormatClass
|
|
*
|
|
* @param string $format
|
|
*
|
|
* @return string|\Windwalker\Structure\Format\FormatInterface
|
|
*
|
|
* @throws \DomainException
|
|
*
|
|
* @since 2.1
|
|
*/
|
|
public static function getFormatClass($format)
|
|
{
|
|
// Return a namespace in a given format
|
|
$class = sprintf('%s\Format\%sFormat', __NAMESPACE__, ucfirst(strtolower($format)));
|
|
|
|
if (!class_exists($class)) {
|
|
throw new \DomainException(
|
|
sprintf(
|
|
'Structure format: %s not supported. Class: %s not found.',
|
|
$format,
|
|
$class
|
|
)
|
|
);
|
|
}
|
|
|
|
return $class;
|
|
}
|
|
|
|
/**
|
|
* Method to determine if an array is an associative array.
|
|
*
|
|
* @param array $array An array to test.
|
|
*
|
|
* @return boolean True if the array is an associative array.
|
|
*/
|
|
public static function isAssociativeArray($array)
|
|
{
|
|
if (is_array($array)) {
|
|
foreach (array_keys($array) as $k => $v) {
|
|
if ($k !== $v) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* getValue
|
|
*
|
|
* @param array $array
|
|
* @param string $name
|
|
* @param mixed $default
|
|
*
|
|
* @return mixed
|
|
*/
|
|
public static function getValue(array $array, $name, $default = null)
|
|
{
|
|
return isset($array[$name]) ? $array[$name] : $default;
|
|
}
|
|
|
|
/**
|
|
* Utility function to map an array to a stdClass object.
|
|
*
|
|
* @param array $array The array to map.
|
|
* @param string $class Name of the class to create
|
|
*
|
|
* @return object The object mapped from the given array
|
|
*
|
|
* @since 2.0
|
|
*/
|
|
public static function toObject($array, $class = 'stdClass')
|
|
{
|
|
$object = new $class();
|
|
|
|
foreach ($array as $k => $v) {
|
|
if (is_array($v)) {
|
|
$object->$k = static::toObject($v, $class);
|
|
} else {
|
|
$object->$k = $v;
|
|
}
|
|
}
|
|
|
|
return $object;
|
|
}
|
|
|
|
/**
|
|
* Get data from array or object by path.
|
|
*
|
|
* Example: `StructureHelper::getByPath($array, 'foo.bar.yoo')` equals to $array['foo']['bar']['yoo'].
|
|
*
|
|
* @param mixed $data An array or object to get value.
|
|
* @param mixed $path The key path.
|
|
* @param string $separator Separator of paths.
|
|
*
|
|
* @return mixed Found value, null if not exists.
|
|
*
|
|
* @since 2.1
|
|
*/
|
|
public static function getByPath(array $data, $path, $separator = '.')
|
|
{
|
|
$nodes = static::getPathNodes($path, $separator);
|
|
|
|
if (empty($nodes)) {
|
|
return null;
|
|
}
|
|
|
|
$dataTmp = $data;
|
|
|
|
foreach ($nodes as $arg) {
|
|
if (is_object($dataTmp) && isset($dataTmp->$arg)) {
|
|
$dataTmp = $dataTmp->$arg;
|
|
} elseif ($dataTmp instanceof \ArrayAccess && isset($dataTmp[$arg])) {
|
|
$dataTmp = $dataTmp[$arg];
|
|
} elseif (is_array($dataTmp) && isset($dataTmp[$arg])) {
|
|
$dataTmp = $dataTmp[$arg];
|
|
} else {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
return $dataTmp;
|
|
}
|
|
|
|
/**
|
|
* setByPath
|
|
*
|
|
* @param mixed &$data
|
|
* @param string $path
|
|
* @param mixed $value
|
|
* @param string $separator
|
|
*
|
|
* @return boolean
|
|
*
|
|
* @since 2.1
|
|
*/
|
|
public static function setByPath(array &$data, $path, $value, $separator = '.')
|
|
{
|
|
$nodes = static::getPathNodes($path, $separator);
|
|
|
|
if (empty($nodes)) {
|
|
return false;
|
|
}
|
|
|
|
$dataTmp = &$data;
|
|
|
|
foreach ($nodes as $node) {
|
|
if (is_array($dataTmp)) {
|
|
if (!isset($dataTmp[$node])) {
|
|
$dataTmp[$node] = [];
|
|
}
|
|
|
|
$dataTmp = &$dataTmp[$node];
|
|
} else {
|
|
// If a node is value but path is not go to the end, we replace this value as a new store.
|
|
// Then next node can insert new value to this store.
|
|
$dataTmp = [];
|
|
}
|
|
}
|
|
|
|
// Now, path go to the end, means we get latest node, set value to this node.
|
|
$dataTmp = $value;
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* removeByPath
|
|
*
|
|
* @param array $data
|
|
* @param string $path
|
|
* @param string $separator
|
|
*
|
|
* @return bool
|
|
*/
|
|
public static function removeByPath(array &$data, $path, $separator = '.')
|
|
{
|
|
$nodes = static::getPathNodes($path, $separator);
|
|
|
|
if (empty($nodes)) {
|
|
return false;
|
|
}
|
|
|
|
$previous = null;
|
|
$dataTmp = &$data;
|
|
|
|
foreach ($nodes as $node) {
|
|
if (is_array($dataTmp)) {
|
|
if (empty($dataTmp[$node])) {
|
|
return false;
|
|
}
|
|
|
|
$previous = &$dataTmp;
|
|
$dataTmp = &$dataTmp[$node];
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// Now, path go to the end, means we get latest node, set value to this node.
|
|
unset($previous[$node]);
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Explode the structure path into an array and remove empty
|
|
* nodes that occur as a result of a double dot. ex: windwalker..test
|
|
* Finally, re-key the array so they are sequential.
|
|
*
|
|
* @param string $path
|
|
* @param string $separator
|
|
*
|
|
* @return array
|
|
*/
|
|
public static function getPathNodes($path, $separator = '.')
|
|
{
|
|
return array_values(array_filter(explode($separator, $path), 'strlen'));
|
|
}
|
|
|
|
/**
|
|
* Method to recursively convert data to one dimension array.
|
|
*
|
|
* @param array|object $array The array or object to convert.
|
|
* @param string $separator The key separator.
|
|
* @param string $prefix Last level key prefix.
|
|
*
|
|
* @return array
|
|
*/
|
|
public static function flatten($array, $separator = '.', $prefix = '')
|
|
{
|
|
$return = [];
|
|
|
|
if ($array instanceof \Traversable) {
|
|
$array = iterator_to_array($array);
|
|
} elseif (is_object($array)) {
|
|
$array = get_object_vars($array);
|
|
}
|
|
|
|
foreach ($array as $k => $v) {
|
|
$key = $prefix ? $prefix . $separator . $k : $k;
|
|
|
|
if (is_object($v) || is_array($v)) {
|
|
$return = array_merge($return, static::flatten($v, $separator, $key));
|
|
} else {
|
|
$return[$key] = $v;
|
|
}
|
|
}
|
|
|
|
return $return;
|
|
}
|
|
|
|
/**
|
|
* Utility function to convert all types to an array.
|
|
*
|
|
* @param mixed $data The data to convert.
|
|
* @param bool $recursive Recursive if data is nested.
|
|
*
|
|
* @return array The converted array.
|
|
*/
|
|
public static function toArray($data, $recursive = false)
|
|
{
|
|
if ($data instanceof ValueReference) {
|
|
return $data;
|
|
}
|
|
|
|
// Ensure the input data is an array.
|
|
if ($data instanceof \Traversable) {
|
|
$data = iterator_to_array($data);
|
|
} elseif (is_object($data)) {
|
|
$data = get_object_vars($data);
|
|
} else {
|
|
$data = (array) $data;
|
|
}
|
|
|
|
if ($recursive) {
|
|
foreach ($data as &$value) {
|
|
if (is_array($value) || is_object($value)) {
|
|
$value = static::toArray($value, $recursive);
|
|
}
|
|
}
|
|
}
|
|
|
|
return $data;
|
|
}
|
|
|
|
/**
|
|
* dumpObjectValues
|
|
*
|
|
* @param mixed $object
|
|
*
|
|
* @return array
|
|
*/
|
|
public static function dumpObjectValues($object)
|
|
{
|
|
$data = [];
|
|
|
|
static::$objectStorage = new \SplObjectStorage();
|
|
|
|
static::doDump($data, $object);
|
|
|
|
return $data;
|
|
}
|
|
|
|
/**
|
|
* doDump
|
|
*
|
|
* @param array $data
|
|
* @param mixed $object
|
|
*
|
|
* @return void
|
|
*/
|
|
private static function doDump(&$data, $object)
|
|
{
|
|
if (is_object($object) && static::$objectStorage->contains($object)) {
|
|
$data = null;
|
|
|
|
return;
|
|
}
|
|
|
|
if (is_object($object)) {
|
|
static::$objectStorage->attach($object);
|
|
}
|
|
|
|
if (is_array($object) || $object instanceof \Traversable) {
|
|
foreach ($object as $key => $value) {
|
|
static::doDump($data[$key], $value);
|
|
}
|
|
} elseif (is_object($object)) {
|
|
$ref = new \ReflectionObject($object);
|
|
|
|
$properties = $ref->getProperties();
|
|
|
|
foreach ($properties as $property) {
|
|
$property->setAccessible(true);
|
|
|
|
$value = $property->getValue($object);
|
|
|
|
static::doDump($data[$property->getName()], $value);
|
|
}
|
|
} else {
|
|
$data = $object;
|
|
}
|
|
}
|
|
}
|