snippetphpMinor
Best practice to create XML messages with DOMDocument class in PHP
Viewed 0 times
createpracticewithphpxmldomdocumentmessagesclassbest
Problem
I want to create XML messages for webservice communication. These messages should be created from a pool of reusable elements. Therefore I have created different classes. A "factory" class, that only returns a message class. An element class, that consists of the reusable parts and the message classes that are the blueprints for the desired XML messages.
My code delivers the expected result, but I'm looking for a best practice. Especially a way to get rid of rewriting the same
Update:
I have improved my example and moved the
also changed the name of the method from
there is a
changes I have little less redudant code. I still don't know if it is
good practice, particularly to use the "grandparent" methods in the
message classes.
```
// class to create webservice messages
class Messages{
private function __construct(){}
public static function get($type) {
//some error handling if class not exists
return new $type;
}
}
// message no.1
class Message_1 extends Elements{
public function __construct() {
parent::__construct();
$this->root = $this->createElement("message1");
}
public function add_anotherElement(){
$this->root->appendChild($this->add_anotherElementBlock("foo", "bar"));
}
public function add_element(){
$this->root->appendChild($this->add_someElementBlock("foo", "bar"));
}
}
// message no.2
class Message_2 extends Elements {
public function __construct() {
parent::__construct();
$this->root = $this->createElement("message2");
}
public function add_elements(){
$this->root->appendChild($this->add_anotherElementBlock("foo", "bar"));
$this->root->appendChild($this->add_someElem
My code delivers the expected result, but I'm looking for a best practice. Especially a way to get rid of rewriting the same
save() and __construct method in every of the message classes.Update:
I have improved my example and moved the
root property and thesave() method from the message classes to the Elements class. Ialso changed the name of the method from
save to getMessage asthere is a
DOMDocument method with the same name. Due to thesechanges I have little less redudant code. I still don't know if it is
good practice, particularly to use the "grandparent" methods in the
message classes.
```
// class to create webservice messages
class Messages{
private function __construct(){}
public static function get($type) {
//some error handling if class not exists
return new $type;
}
}
// message no.1
class Message_1 extends Elements{
public function __construct() {
parent::__construct();
$this->root = $this->createElement("message1");
}
public function add_anotherElement(){
$this->root->appendChild($this->add_anotherElementBlock("foo", "bar"));
}
public function add_element(){
$this->root->appendChild($this->add_someElementBlock("foo", "bar"));
}
}
// message no.2
class Message_2 extends Elements {
public function __construct() {
parent::__construct();
$this->root = $this->createElement("message2");
}
public function add_elements(){
$this->root->appendChild($this->add_anotherElementBlock("foo", "bar"));
$this->root->appendChild($this->add_someElem
Solution
Your message classes currently have two responsibilities: representing an application logic message and transforming itself into a representation. If you want to add other ways of serialization you have to modify the message classes itself.
The message classes only should represent the message while some other facility should be responsible for serializing your messages into xml. This keeps the interface of your message classes clean (not inheriting all those methods from
This particular situation wants a strategy pattern: a dedicated
The dedicated serializers are rather simple. Of course they all share a common interface:
And finally the serializer specialized on serializing
So far the basic concept. Now new message types can easily be added and serializiation the messages itself are separated. Of course, as for any pattern, this concept can (should) be extended and adjusted to your needs.
The message classes only should represent the message while some other facility should be responsible for serializing your messages into xml. This keeps the interface of your message classes clean (not inheriting all those methods from
DOMDocument) and allows to easily add other serialization formats. This particular situation wants a strategy pattern: a dedicated
MessageXmlSerializer takes a message, creates the surrogate DOMDocument and itself delegates the serialization of the message further to specialized classes for each message:createDocumentContainer();
foreach ($this->messageSerializers as $serializer) {
if ($serializer->canHandle($message)) {
$node->appendChild($serializer->serialize($message));
}
}
}
protected function createDocumentContainer() {
$node = new DOMDocument();
// Do your intialization here
return $node;
}
}The dedicated serializers are rather simple. Of course they all share a common interface:
interface MessageSerializer {
public function canHandle(Message $message);
public function serialize(Message $message);
}And finally the serializer specialized on serializing
Message_1class MessageOneSerializer implements MessageSerializer {
public function canHandle(Message $message) {
return $message instanceof Message_1;
}
public function serialize(Message $message) {
// create your node here and return it
}
}So far the basic concept. Now new message types can easily be added and serializiation the messages itself are separated. Of course, as for any pattern, this concept can (should) be extended and adjusted to your needs.
Code Snippets
<?php
class MessageXmlSerializer {
private $messageSerializers;
public function serialize(Message $message) {
$node = $this->createDocumentContainer();
foreach ($this->messageSerializers as $serializer) {
if ($serializer->canHandle($message)) {
$node->appendChild($serializer->serialize($message));
}
}
}
protected function createDocumentContainer() {
$node = new DOMDocument();
// Do your intialization here
return $node;
}
}interface MessageSerializer {
public function canHandle(Message $message);
public function serialize(Message $message);
}class MessageOneSerializer implements MessageSerializer {
public function canHandle(Message $message) {
return $message instanceof Message_1;
}
public function serialize(Message $message) {
// create your node here and return it
}
}Context
StackExchange Code Review Q#42327, answer score: 3
Revisions (0)
No revisions yet.