/src/Converter.php
PHP | 322 lines | 171 code | 39 blank | 112 comment | 77 complexity | 6d76a34839d1a8f8480d61fa49c119ec MD5 | raw file
- <?php
- /**
- * @copyright 2014 - 2019 Xibalba Lab.
- * @license http://opensource.org/licenses/bsd-license.php
- * @link https://gitlab.com/xibalba/ocelote
- */
- namespace xibalba\ocelote;
- use \JsonSerializable;
- use \Serializable;
- use \SimpleXmlElement;
- /**
- * A class that handles the detection and conversion of certain resource formats / content types into other formats.
- * The current formats are supported: XML, JSON, Array, Object, Serialized
- *
- * @author Yeshua Rodas <yrodas@upnfm.edu.hn> ☭
- * @package alpaca\ocelote
- */
- class Converter {
- /** Disregard XML attributes and only return the value */
- const XML_NONE = 0;
- /** Merge attributes and the value into a single dimension; the values key will be "value" */
- const XML_MERGE = 1;
- /** Group the attributes into a key "attributes" and the value into a key of "value" */
- const XML_GROUP = 2;
- /** Attributes will only be returned */
- const XML_ATTRIBS = 3;
- /**
- * Autobox a value by type casting it.
- *
- * @param mixed $value
- * @return mixed
- */
- public static function autobox($value) {
- if (is_numeric($value)) {
- if (strpos($value, '.') !== false) return (float) $value;
- else return (int) $value;
- } else if (is_bool($value)) return (bool) $value;
- else if ($value === 'true' || $value === 'false') return ($value === 'true');
- return (string) $value;
- }
- /**
- * Unbox values by type casting to a string equivalent.
- *
- * @param mixed $value
- * @return string
- */
- public static function unbox($value) : string {
- if (is_bool($value)) return $value ? 'true' : 'false';
- return (string) $value;
- }
- /**
- * Turn an object into an array. Alternative to array_map magic.
- *
- * @param object|array $object
- * @return array
- */
- public static function buildArray($object) : array {
- $array = [];
- foreach ($object as $key => $value) {
- if (is_object($value) || is_array($value)) $array[$key] = static::buildArray($value);
- else $array[$key] = static::autobox($value);
- }
- return $array;
- }
- /**
- * Turn an array into an object. Alternative to array_map magic.
- *
- * @param array|object $array
- * @return object
- */
- public static function buildObject($array) : \stdClass {
- $obj = new \stdClass();
- foreach ($array as $key => $value) {
- if (is_array($value) || is_object($value)) $obj->{$key} = static::buildObject($value);
- else $obj->{$key} = static::autobox($value);
- }
- return $obj;
- }
- /**
- * Turn an array into an XML document. Alternative to array_map magic.
- *
- * @param \SimpleXMLElement $xml
- * @param array $array
- * @return \SimpleXMLElement
- */
- public static function buildXml(SimpleXMLElement &$xml, $array) : \SimpleXMLElement {
- if (is_array($array)) {
- foreach ($array as $key => $value) {
- // XML_NONE
- if (!is_array($value)) {
- $xml->addChild($key, static::unbox($value));
- continue;
- }
- // Multiple nodes of the same name
- if (Checker::isIndexed($value)) {
- foreach ($value as $kValue) {
- if (is_array($kValue)) static::buildXml($xml, [$key => $kValue]);
- else $xml->addChild($key, static::unbox($kValue));
- }
- }
- // XML_GROUP
- else if (isset($value['attributes'])) {
- if (!isset($value['value'])) $value['value'] = null;
- if (is_array($value['value'])) {
- $node = $xml->addChild($key);
- static::buildXml($node, $value['value']);
- } else $node = $xml->addChild($key, static::unbox($value['value']));
- if (!empty($value['attributes'])) {
- foreach ($value['attributes'] as $aKey => $aValue) {
- $node->addAttribute($aKey, static::unbox($aValue));
- }
- }
- }
- // XML_MERGE
- else if (isset($value['value'])) {
- $node = $xml->addChild($key, $value['value']);
- unset($value['value']);
- if (!empty($value)) {
- foreach ($value as $aKey => $aValue) {
- if (is_array($aValue)) static::buildXml($node, array($aKey => $aValue));
- else $node->addAttribute($aKey, static::unbox($aValue));
- }
- }
- }
- // XML_ATTRIBS
- else {
- $node = $xml->addChild($key);
- if (!empty($value)) {
- foreach ($value as $aKey => $aValue) {
- if (is_array($aValue)) static::buildXml($node, array($aKey => $aValue));
- else $node->addChild($aKey, static::unbox($aValue));
- }
- }
- }
- }
- }
- return $xml;
- }
- /**
- * Transforms a resource into an array.
- *
- * @param mixed $resource
- * @param bool $recursive
- * @return array
- */
- public static function toArray($resource, $recursive = false) : array {
- if (Checker::isArray($resource)) return $recursive ? static::buildArray($resource) : $resource;
- else if (Checker::isObject($resource)) return static::buildArray($resource);
- else if (Checker::isJson($resource)) $resource = json_decode($resource, true);
- else if (Checker::isSerialized($resource)) $resource = unserialize($resource);
- else if (Checker::isXml($resource)) $resource = static::xmlToArray(simplexml_load_string($resource));
- else if (Checker::isBag($resource)) return $resource->toArray();
- return (array) $resource;
- }
- /**
- * Transform a resource into an array and put in into a ocelote Bag instance.
- *
- * @param mixed $resource
- * @param bool $recursive
- * @return ocelote\Bag
- */
- public static function toBag($resource, $recursive = false) : Bag {
- $bag = new Bag();
- $bag->add(static::toArray($resource, $recursive));
- return $bag;
- }
- /**
- * Transforms a resource into a JSON object.
- *
- * @param mixed $resource
- * @param int $options
- * @return string
- */
- public static function toJson($resource, $options = 0) : string {
- if (Checker::isJson($resource)) return $resource;
- else if (Checker::isObject($resource)) $resource = static::buildArray($resource);
- else if (Checker::isXml($resource)) $resource = static::xmlToArray(simplexml_load_string($resource));
- else if (Checker::isSerialized($resource)) $resource = unserialize($resource);
- else if (Checker::isBag($resource)) return json_encode($resource->toArray(), $options);
- return json_encode($resource, $options);
- }
- /**
- * Transforms a resource into an object.
- *
- * @param mixed $resource
- * @param bool $recursive
- * @return object
- */
- public static function toObject($resource, $recursive = false) : \stdClass {
- if (Checker::isObject($resource)) {
- if (!$recursive) return $resource;
- }
- else if (Checker::isJson($resource)) $resource = json_decode($resource, true);
- else if (Checker::isSerialized($resource)) $resource = unserialize($resource);
- else if (Checker::isXml($resource)) $resource = static::xmlToArray(simplexml_load_string($resource));
- return static::buildObject($resource);
- }
- /**
- * Transforms a resource into a serialized form.
- *
- * @param mixed $resource
- * @return string
- */
- public static function toSerialize($resource) : string {
- if ($resource instanceof Serializable) {
- // pass-through
- } else $resource = static::toArray($resource);
- return serialize($resource);
- }
- /**
- * Transforms a resource into an XML document.
- *
- * @param mixed $resource
- * @param string $root
- * @return string
- */
- public static function toXml($resource, $root = 'root') : string {
- if ($array = static::toArray($resource, true)) {
- $xml = simplexml_load_string('<?xml version="1.0" encoding="utf-8"?><' . $root . '></' . $root . '>');
- $response = static::buildXml($xml, $array);
- return trim($response->asXML());
- }
- return null;
- }
- /**
- * Transform a Query String into an Array.
- * Bassically this method is a wrapper to `parse_str()` funcion.
- *
- * @see http://php.net/manual/en/function.parse-str.php `parse_str()` official documentation.
- *
- * @param string $str Query string to parse.
- * @return array The array result.
- */
- public static function queryStringToArray(string $str) : array {
- $result = [];
- parse_str($str, $result);
- return $result;
- }
- /**
- * Convert a SimpleXML object into an array.
- *
- * @param SimpleXMLElement $xml
- * @param int $format
- * @return array
- */
- public static function xmlToArray(SimpleXMLElement $xml, $format = self::XML_GROUP) {
- if (count($xml->children()) <= 0) return static::autobox((string) $xml);
- $array = [];
- /** @type SimpleXMLElement $node */
- foreach ($xml->children() as $element => $node) {
- $data = [];
- $children = $node->children();
- if (!isset($array[$element])) $array[$element] = '';
- if (!$node->attributes() || $format === static::XML_NONE) $data = static::xmlToArray($node, $format);
- else {
- switch ($format) {
- case static::XML_GROUP:
- $data = [
- 'value' => static::autobox((string) $node),
- 'attributes' => []
- ];
- if (count($children) > 0) $data['value'] = static::xmlToArray($node, $format);
- foreach ($node->attributes() as $attr => $value) {
- $data['attributes'][$attr] = static::autobox((string) $value);
- }
- break;
- case static::XML_MERGE:
- if (count($children) > 0) $data = $data + static::xmlToArray($node, $format);
- else $data['value'] = static::autobox((string) $node);
- /* fall-through */
- case static::XML_ATTRIBS:
- foreach ($node->attributes() as $attr => $value) {
- $data[$attr] = static::autobox((string) $value);
- }
- break;
- }
- }
- if (count($xml->{$element}) > 1) $array[$element][] = $data;
- else $array[$element] = $data;
- }
- return $array;
- }
- }