Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 24 additions & 2 deletions lib/ContextStackTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,26 @@ trait ContextStackTrait {
*/
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 = [];

/**
* Backups of previous contexts.
*
Expand All @@ -78,7 +98,8 @@ function pushContext() {
$this->contextStack[] = [
$this->elementMap,
$this->contextUri,
$this->namespaceMap
$this->namespaceMap,
$this->classMap
];

}
Expand All @@ -93,7 +114,8 @@ function popContext() {
list(
$this->elementMap,
$this->contextUri,
$this->namespaceMap
$this->namespaceMap,
$this->classMap
) = array_pop($this->contextStack);

}
Expand Down
21 changes: 21 additions & 0 deletions lib/Service.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,26 @@ class Service {
*/
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
*
Expand All @@ -60,6 +80,7 @@ function getWriter() {

$w = new Writer();
$w->namespaceMap = $this->namespaceMap;
$w->classMap = $this->classMap;
return $w;

}
Expand Down
14 changes: 12 additions & 2 deletions lib/Writer.php
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,14 @@ function write($value) {

if (is_scalar($value)) {
$this->text($value);
} elseif ($value instanceof XmlSerializable) {
} elseif (is_object($value) && $value instanceof XmlSerializable) {

$value->xmlSerialize($this);

} elseif (is_object($value) && isset($this->classMap[get_class($value)])) {
$this->classMap[get_class($value)]($this, $value);
} elseif (is_callable($value)) {
$value($this);
} elseif (is_null($value)) {
// noop
} elseif (is_array($value)) {
Expand Down Expand Up @@ -142,7 +148,11 @@ function write($value) {

} elseif (is_object($value)) {

throw new InvalidArgumentException('The writer cannot serialize objects of type: ' . get_class($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));

}

Expand Down
43 changes: 43 additions & 0 deletions tests/Sabre/Xml/WriterTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,49 @@ function testStartElementSimple() {

$this->assertEquals($output, $this->writer->outputMemory());

}

function testCallback() {

$this->compare([
'{http://sabredav.org/ns}root' => function(Writer $writer) {
$writer->text('deferred writer');
},
], <<<HI
<?xml version="1.0"?>
<s:root xmlns:s="http://sabredav.org/ns">deferred writer</s:root>

HI
);

}

function testClassMap() {

$obj = (object)[
'key1' => 'value1',
'key2' => 'value2',
];

$this->writer->classMap['stdClass'] = function(Writer $writer, $value) {

foreach (get_object_vars($value) as $key => $val) {
$writer->writeElement('{http://sabredav.org/ns}' . $key, $val);
}

};

$this->compare([
'{http://sabredav.org/ns}root' => $obj
], <<<HI
<?xml version="1.0"?>
<s:root xmlns:s="http://sabredav.org/ns">
<s:key1>value1</s:key1>
<s:key2>value2</s:key2>
</s:root>

HI
);

}
}