streams/vendor/sabre/xml/lib/Serializer/functions.php

250 lines
7 KiB
PHP
Raw Normal View History

<?php
namespace Sabre\Xml\Serializer;
use InvalidArgumentException;
use Sabre\Xml\Writer;
use Sabre\Xml\XmlSerializable;
/**
* This file provides a number of 'serializer' helper functions.
*
* These helper functions can be used to easily xml-encode common PHP
* data structures, or can be placed in the $classMap.
*/
/**
* The 'enum' serializer writes simple list of elements.
*
* For example, calling:
*
* enum($writer, [
* "{http://sabredav.org/ns}elem1",
* "{http://sabredav.org/ns}elem2",
* "{http://sabredav.org/ns}elem3",
* "{http://sabredav.org/ns}elem4",
* "{http://sabredav.org/ns}elem5",
* ]);
*
* Will generate something like this (if the correct namespace is declared):
*
* <s:elem1 />
* <s:elem2 />
* <s:elem3 />
* <s:elem4>content</s:elem4>
* <s:elem5 attr="val" />
*
* @param Writer $writer
* @param string[] $values
* @return void
*/
function enum(Writer $writer, array $values) {
foreach ($values as $value) {
$writer->writeElement($value);
}
}
/**
* The valueObject serializer turns a simple PHP object into a classname.
*
* Every public property will be encoded as an xml element with the same
* name, in the XML namespace as specified.
*
* Values that are set to null or an empty array are not serialized. To
* serialize empty properties, you must specify them as an empty string.
*
* @param Writer $writer
* @param object $valueObject
* @param string $namespace
*/
function valueObject(Writer $writer, $valueObject, $namespace) {
foreach (get_object_vars($valueObject) as $key => $val) {
if (is_array($val)) {
// If $val is an array, it has a special meaning. We need to
// generate one child element for each item in $val
foreach ($val as $child) {
$writer->writeElement('{' . $namespace . '}' . $key, $child);
}
} elseif ($val !== null) {
$writer->writeElement('{' . $namespace . '}' . $key, $val);
}
}
}
/**
* This serializer helps you serialize xml structures that look like
* this:
*
* <collection>
* <item>...</item>
* <item>...</item>
* <item>...</item>
* </collection>
*
* In that previous example, this serializer just serializes the item element,
* and this could be called like this:
*
* repeatingElements($writer, $items, '{}item');
*
* @param Writer $writer
* @param array $items A list of items sabre/xml can serialize.
* @param string $childElementName Element name in clark-notation
* @return void
*/
function repeatingElements(Writer $writer, array $items, $childElementName) {
foreach ($items as $item) {
$writer->writeElement($childElementName, $item);
}
}
/**
* This function is the 'default' serializer that is able to serialize most
* things, and delegates to other serializers if needed.
*
* The standardSerializer supports a wide-array of values.
*
* $value may be a string or integer, it will just write out the string as text.
* $value may be an instance of XmlSerializable or Element, in which case it
* calls it's xmlSerialize() method.
* $value may be a PHP callback/function/closure, in case we call the callback
* and give it the Writer as an argument.
* $value may be a an object, and if it's in the classMap we automatically call
* the correct serializer for it.
* $value may be null, in which case we do nothing.
*
* If $value is an array, the array must look like this:
*
* [
* [
* 'name' => '{namespaceUri}element-name',
* 'value' => '...',
* 'attributes' => [ 'attName' => 'attValue' ]
* ]
* [,
* 'name' => '{namespaceUri}element-name2',
* 'value' => '...',
* ]
* ]
*
* This would result in xml like:
*
* <element-name xmlns="namespaceUri" attName="attValue">
* ...
* </element-name>
* <element-name2>
* ...
* </element-name2>
*
* The value property may be any value standardSerializer supports, so you can
* nest data-structures this way. Both value and attributes are optional.
*
* Alternatively, you can also specify the array using this syntax:
*
* [
* [
* '{namespaceUri}element-name' => '...',
* '{namespaceUri}element-name2' => '...',
* ]
* ]
*
* This is excellent for simple key->value structures, and here you can also
* specify anything for the value.
*
* You can even mix the two array syntaxes.
*
* @param Writer $writer
* @param string|int|float|bool|array|object
* @return void
*/
function standardSerializer(Writer $writer, $value) {
if (is_scalar($value)) {
// String, integer, float, boolean
$writer->text($value);
} elseif ($value instanceof XmlSerializable) {
// XmlSerializable classes or Element classes.
$value->xmlSerialize($writer);
} elseif (is_object($value) && isset($writer->classMap[get_class($value)])) {
// It's an object which class appears in the classmap.
$writer->classMap[get_class($value)]($writer, $value);
} elseif (is_callable($value)) {
// A callback
$value($writer);
} elseif (is_null($value)) {
// nothing!
} elseif (is_array($value) && array_key_exists('name', $value)) {
// if the array had a 'name' element, we assume that this array
// describes a 'name' and optionally 'attributes' and 'value'.
$name = $value['name'];
$attributes = isset($value['attributes']) ? $value['attributes'] : [];
$value = isset($value['value']) ? $value['value'] : null;
$writer->startElement($name);
$writer->writeAttributes($attributes);
$writer->write($value);
$writer->endElement();
} elseif (is_array($value)) {
foreach ($value as $name => $item) {
if (is_int($name)) {
// This item has a numeric index. We just loop through the
// array and throw it back in the writer.
standardSerializer($writer, $item);
} elseif (is_string($name) && is_array($item) && isset($item['attributes'])) {
// The key is used for a name, but $item has 'attributes' and
// possibly 'value'
$writer->startElement($name);
$writer->writeAttributes($item['attributes']);
if (isset($item['value'])) {
$writer->write($item['value']);
}
$writer->endElement();
} elseif (is_string($name)) {
// This was a plain key-value array.
$writer->startElement($name);
$writer->write($item);
$writer->endElement();
} else {
throw new InvalidArgumentException('The writer does not know how to serialize arrays with keys of type: ' . gettype($name));
}
}
} elseif (is_object($value)) {
throw new InvalidArgumentException('The writer cannot serialize objects of class: ' . get_class($value));
} else {
throw new InvalidArgumentException('The writer cannot serialize values of type: ' . gettype($value));
}
}