diff options
Diffstat (limited to 'vendor/sabre/xml/lib/Service.php')
-rw-r--r-- | vendor/sabre/xml/lib/Service.php | 291 |
1 files changed, 291 insertions, 0 deletions
diff --git a/vendor/sabre/xml/lib/Service.php b/vendor/sabre/xml/lib/Service.php new file mode 100644 index 000000000..b2603a4c7 --- /dev/null +++ b/vendor/sabre/xml/lib/Service.php @@ -0,0 +1,291 @@ +<?php + +namespace Sabre\Xml; + +/** + * XML parsing and writing service. + * + * You are encouraged to make a instance of this for your application and + * potentially extend it, as a central API point for dealing with xml and + * configuring the reader and writer. + * + * @copyright Copyright (C) 2009-2015 fruux GmbH (https://fruux.com/). + * @author Evert Pot (http://evertpot.com/) + * @license http://sabre.io/license/ Modified BSD License + */ +class Service { + + /** + * This is the element map. It contains a list of XML elements (in clark + * notation) as keys and PHP class names as values. + * + * The PHP class names must implement Sabre\Xml\Element. + * + * Values may also be a callable. In that case the function will be called + * directly. + * + * @var array + */ + public $elementMap = []; + + /** + * This is a list of namespaces that you want to give default prefixes. + * + * You must make sure you create this entire list before starting to write. + * They should be registered on the root element. + * + * @var array + */ + public $namespaceMap = []; + + /** + * This is a list of custom serializers for specific classes. + * + * The writer may use this if you attempt to serialize an object with a + * class that does not implement XmlSerializable. + * + * Instead it will look at this classmap to see if there is a custom + * serializer here. This is useful if you don't want your value objects + * to be responsible for serializing themselves. + * + * The keys in this classmap need to be fully qualified PHP class names, + * the values must be callbacks. The callbacks take two arguments. The + * writer class, and the value that must be written. + * + * function (Writer $writer, object $value) + * + * @var array + */ + public $classMap = []; + + /** + * Returns a fresh XML Reader + * + * @return Reader + */ + function getReader() { + + $r = new Reader(); + $r->elementMap = $this->elementMap; + return $r; + + } + + /** + * Returns a fresh xml writer + * + * @return Writer + */ + function getWriter() { + + $w = new Writer(); + $w->namespaceMap = $this->namespaceMap; + $w->classMap = $this->classMap; + return $w; + + } + + /** + * Parses a document in full. + * + * Input may be specified as a string or readable stream resource. + * The returned value is the value of the root document. + * + * Specifying the $contextUri allows the parser to figure out what the URI + * of the document was. This allows relative URIs within the document to be + * expanded easily. + * + * The $rootElementName is specified by reference and will be populated + * with the root element name of the document. + * + * @param string|resource $input + * @param string|null $contextUri + * @param string|null $rootElementName + * @throws ParseException + * @return array|object|string + */ + function parse($input, $contextUri = null, &$rootElementName = null) { + + if (is_resource($input)) { + // Unfortunately the XMLReader doesn't support streams. When it + // does, we can optimize this. + $input = stream_get_contents($input); + } + $r = $this->getReader(); + $r->contextUri = $contextUri; + $r->xml($input); + + $result = $r->parse(); + $rootElementName = $result['name']; + return $result['value']; + + } + + /** + * Parses a document in full, and specify what the expected root element + * name is. + * + * This function works similar to parse, but the difference is that the + * user can specify what the expected name of the root element should be, + * in clark notation. + * + * This is useful in cases where you expected a specific document to be + * passed, and reduces the amount of if statements. + * + * It's also possible to pass an array of expected rootElements if your + * code may expect more than one document type. + * + * @param string|string[] $rootElementName + * @param string|resource $input + * @param string|null $contextUri + * @return void + */ + function expect($rootElementName, $input, $contextUri = null) { + + if (is_resource($input)) { + // Unfortunately the XMLReader doesn't support streams. When it + // does, we can optimize this. + $input = stream_get_contents($input); + } + $r = $this->getReader(); + $r->contextUri = $contextUri; + $r->xml($input); + + $result = $r->parse(); + if (!in_array($result['name'], (array)$rootElementName, true)) { + throw new ParseException('Expected ' . implode(' or ', (array)$rootElementName) . ' but received ' . $result['name'] . ' as the root element'); + } + return $result['value']; + + } + + /** + * Generates an XML document in one go. + * + * The $rootElement must be specified in clark notation. + * The value must be a string, an array or an object implementing + * XmlSerializable. Basically, anything that's supported by the Writer + * object. + * + * $contextUri can be used to specify a sort of 'root' of the PHP application, + * in case the xml document is used as a http response. + * + * This allows an implementor to easily create URI's relative to the root + * of the domain. + * + * @param string $rootElementName + * @param string|array|XmlSerializable $value + * @param string|null $contextUri + */ + function write($rootElementName, $value, $contextUri = null) { + + $w = $this->getWriter(); + $w->openMemory(); + $w->contextUri = $contextUri; + $w->setIndent(true); + $w->startDocument(); + $w->writeElement($rootElementName, $value); + return $w->outputMemory(); + + } + + /** + * Map an xml element to a PHP class. + * + * Calling this function will automatically setup the Reader and Writer + * classes to turn a specific XML element to a PHP class. + * + * For example, given a class such as : + * + * class Author { + * public $firstName; + * public $lastName; + * } + * + * and an XML element such as: + * + * <author xmlns="http://example.org/ns"> + * <firstName>...</firstName> + * <lastName>...</lastName> + * </author> + * + * These can easily be mapped by calling: + * + * $service->mapValueObject('{http://example.org}author', 'Author'); + * + * @param string $elementName + * @param object $className + * @return void + */ + function mapValueObject($elementName, $className) { + list($namespace) = self::parseClarkNotation($elementName); + + $this->elementMap[$elementName] = function(Reader $reader) use ($className, $namespace) { + return \Sabre\Xml\Deserializer\valueObject($reader, $className, $namespace); + }; + $this->classMap[$className] = function(Writer $writer, $valueObject) use ($namespace) { + return \Sabre\Xml\Serializer\valueObject($writer, $valueObject, $namespace); + }; + $this->valueObjectMap[$className] = $elementName; + } + + /** + * Writes a value object. + * + * This function largely behaves similar to write(), except that it's + * intended specifically to serialize a Value Object into an XML document. + * + * The ValueObject must have been previously registered using + * mapValueObject(). + * + * @param object $object + * @param string $contextUri + * @return void + */ + function writeValueObject($object, $contextUri = null) { + + if (!isset($this->valueObjectMap[get_class($object)])) { + throw new \InvalidArgumentException('"' . get_class($object) . '" is not a registered value object class. Register your class with mapValueObject.'); + } + return $this->write( + $this->valueObjectMap[get_class($object)], + $object, + $contextUri + ); + + } + + /** + * Parses a clark-notation string, and returns the namespace and element + * name components. + * + * If the string was invalid, it will throw an InvalidArgumentException. + * + * @param string $str + * @throws InvalidArgumentException + * @return array + */ + static function parseClarkNotation($str) { + static $cache = []; + + if (!isset($cache[$str])) { + + if (!preg_match('/^{([^}]*)}(.*)$/', $str, $matches)) { + throw new \InvalidArgumentException('\'' . $str . '\' is not a valid clark-notation formatted string'); + } + + $cache[$str] = [ + $matches[1], + $matches[2] + ]; + } + + return $cache[$str]; + } + + /** + * A list of classes and which XML elements they map to. + */ + protected $valueObjectMap = []; + +} |