Vous êtes connecté en tant que anonymous Se Deconnecter
vendor/windwalker/structure/StructureHelper.php
4f5a31d2
 <?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;
         }
     }
 }