Please check following class that I've create to build few XML frames..
class CommandBuilder
{
public function __construct()
{
//
}
public function login($username, $password)
{
$frame = $this->frame();
$command = $frame->addChild('command');
$login = $command->addChild('login');
$login->addChild('username', $username);
$login->addChild('password', $password);
$command->addChild('authKey', 'authkey');
return $frame->asXML();
}
public function info($id)
{
$frame = $this->frame();
$command = $frame->addChild('command');
$login = $command->addChild('product');
$login->addChild('id', $id);
$command->addChild('authKey', 'authkey');
return $frame->asXML();
}
protected function frame()
{
return new SimpleXMLElement(
'<app/>'
);
}
}
What's the best way to avoid duplication of $frame->addChild('command')
and $command->addChild('authKey', 'authkey')
without changing order of elements?
Please help to improve the code. Thanks
How about something like this, where you create a separate builder class:
class CommandBuilder
{
private $commandName;
private $params = [];
public function __construct( $commandName ) {
$this->commandName = $commandName;
}
// convenience method, to allow for cleaner fluent interface usage
public static function create( $commandName ) {
return new self( $commandName );
}
public function addParam( $paramName, $paramValue ) {
$this->params[] = [ 'name' => $paramName, 'value' => $paramValue ];
return $this;
}
public function build() {
$app = new SimpleXMLElement( '<app/>' );
$commandContainer = $app->addChild( 'command' );
$command = $commandContainer->addChild( $this->commandName );
foreach( $this->params as $param ) {
$command->addChild( $param[ 'name' ], $param[ 'value' ] );
}
$commandContainer->addChild( 'authKey', 'authKey' );
return $app->asXML();
}
}
and then have a separate class that builds the specific application commands:
class AppCommands
{
public function login( $username, $password ) {
return CommandBuilder::create( 'login' )->addParam( 'username', $username )
->addParam( 'password', $password )
->build();
}
public function info( $id ) {
return CommandBuilder::create( 'product' )->addParam( 'id', $id )
->build();
}
}
Usage stays the same, except you instantiate AppCommands
, in stead of CommandBuilder
:
$ac = new AppCommands;
echo $ac->login( 'MyUsername', 'MyPassword' );
echo PHP_EOL;
echo $ac->info( 5 );
View this example on eval.in
If you wanted, you could of course also dynamically pass the authKey
to the CommandBuilder
instead of hard-coding it inside, with something like:
class CommandBuilder
{
private $commandName;
private $authKey;
private $params = [];
public function __construct( $commandName, $authKey ) {
$this->commandName = $commandName;
$this->authKey = $authKey;
}
public static function create( $commandName, $authKey ) {
return new self( $commandName, $authKey );
}
/* ... */
public function build() {
/* ... */
$commandContainer->addChild( 'authKey', $this->authKey );
return $app->asXML();
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With