I'm creating templating engine for a software we are building. I have an abstract class,Template
, with 3 extended classes Header
, Body
, Footer
. Each of the 3 children contain the same constructor code which is bothering me just looking at as far as duplication in code, the constuctors all have this:
public function __construct($file, array $kvp)
{
$this->templates[] = array(
'context' => $this->getClass($this),
'file' => $file,
'kvp' => $kvp
);
}
Is there a way to move this code into the parent class or cut down on duplication? Below is the full code:
<?php
Interface iTemplate
{
protected function add(Template $template);
protected function remove(Template $template);
}
abstract class Template implements iTemplate
{
protected $html = array();
protected $templates = array();
public function add($template)
{
array_push($this->templates, $template);
}
public function remove($template)
{
if(in_array($template, $this->templates)) {
$key = array_search($template, $this->templates);
$this->templates[$key] = null;
$this->templates = array_filter($this->templates);
}
}
protected function getClass($context)
{
return get_class($context);
}
public function render()
{
foreach($this->templates as $template)
{
$output = file_get_contents($template->file);
foreach ($this->template->kvp as $key => $value) {
$tagToReplace = "[@$key]";
$output = str_replace($tagToReplace, $value, $output);
}
$html[] = $output;
}
return implode("\n", $html);
}
}
class Header extends Template
{
public function __construct($file, array $kvp)
{
$this->templates[] = array(
'context' => $this->getClass($this),
'file' => $file,
'kvp' => $kvp
);
}
}
class Body extends Template
{
public function __construct($file, array $kvp)
{
$this->templates[] = array(
'context' => $this->getClass($this),
'file' => $file,
'kvp' => $kvp
);
}
}
class Footer extends Template
{
public function __construct($file, array $kvp)
{
$this->templates[] = array(
'context' => $this->getClass($this),
'file' => $file,
'kvp' => $kvp
);
}
}
/* Example */
$Template = new Template();
$Template->add(new Header($header_file, $header_kvp));
$Template->add(new Body($body_file, $body_kvp));
$Template->add(new Footer($footer_file, $footer_kvp));
echo $Template->render();
Simple solution is using trait:
interface iTemplate
{
public function add(Template $template);
public function remove(Template $template);
}
class Template implements iTemplate
{
protected $html = array();
protected $templates = array();
public function add(Template $template)
{
//...
}
public function remove(Template $template)
{
//...
}
protected function getClass()
{
return get_class($this);
}
public function render()
{
//...
}
}
class Header extends Template
{ use ConstructTrait;
}
class Body extends Template
{ use ConstructTrait;
}
class Footer extends Template
{ use ConstructTrait;
}
trait ConstructTrait
{
public function __construct($file, $kvp)
{
$this->templates[] = array(
'context' => $this->getClass(),
'file' => $file,
'kvp' => $kvp
);
}
}