Completed
Push — master ( 609c6a...23e35e )
by Tom
02:19
created

Builder::createAndProcessTemplate()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 12
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 12
rs 9.4285
cc 3
eloc 8
nc 2
nop 3
1
<?php
2
/* @description     Transformation Style Sheets - Revolutionising PHP templating    *
3
 * @author          Tom Butler [email protected]                                             *
4
 * @copyright       2017 Tom Butler <[email protected]> | https://r.je/                      *
5
 * @license         http://www.opensource.org/licenses/bsd-license.php  BSD License *
6
 * @version         1.2                                                             */
7
namespace Transphporm;
8
/** Builds a Transphorm instance from the 3 constituent parts. XML template string, TSS string and data */
9
class Builder {
10
	private $template;
11
	private $tss;
12
	private $cache;
13
	private $time;
14
	private $modules = [];
15
	private $config;
16
	private $filePath;
17
	private $defaultModules = [
18
		'\\Transphporm\\Module\\Basics',
19
		'\\Transphporm\\Module\\Pseudo',
20
		'\\Transphporm\\Module\\Format',
21
		'\\Transphporm\\Module\\Functions'
22
	];
23
24
	public function __construct($template, $tss = '', $modules = null) {
25
		$this->template = $template;
26
		$this->tss = $tss;
27
		$this->cache = new Cache(new \ArrayObject());
28
		$this->filePath = new FilePath();
29
		$modules = is_array($modules) ? $modules : $this->defaultModules;
30
		foreach ($modules as $module) $this->loadModule(new $module);
31
	}
32
33
	//Allow setting the time used by Transphporm for caching. This is for testing purposes
34
	//Would be better if PHP allowed setting the script clock, but this is the simplest way of overriding it
35
	public function setTime($time) {
36
		$this->time = $time;
37
	}
38
39
	public function loadModule(Module $module) {
40
		$this->modules[get_class($module)] = $module;
41
	}
42
43
	public function setLocale($locale) {
44
                $format = new \Transphporm\Module\Format($locale);
45
                $this->modules[get_class($format)] = $format;
46
        }
47
48
	public function addPath($dir) {
49
		$this->filePath->addPath($dir);
50
	}
51
52
	public function output($data = null, $document = false) {
53
		$headers = [];
54
		$result = $this->loadTemplate();
55
		$tssCache = new SheetLoader($this->cache,  $this->filePath, $this->tss, $this->time);
56
57
		//If an update is required, run any rules that need to be run. Otherwise, return the result from cache
58
		//without creating any further objects, loading a DomDocument, etc
59
		if ($tssCache->updateRequired($data) === true) {
60
			$template = $this->createAndProcessTemplate($data, $result['cache'], $headers);
61
			$tssCache->processRules($template, $this->config);
62
63
			$result = ['cache' => $template->output($document),
64
			   'headers' => array_merge($result['headers'], $headers),
65
			   'body' => $this->doPostProcessing($template)->output($document)
66
			];
67
			$this->cache->write($this->template, $result);
68
		}
69
70
		unset($result['cache']);
71
		return (object) $result;
72
	}
73
74
	private function createAndProcessTemplate($data, $body, &$headers) {
75
		$elementData = new \Transphporm\Hook\ElementData(new \SplObjectStorage(), $data);
76
		$functionSet = new FunctionSet($elementData);
77
		//To be a valid XML document it must have a root element, automatically wrap it in <template> to ensure it does
78
		$template = new Template($this->isValidDoc($body) ? str_ireplace('<!doctype', '<!DOCTYPE', $body) : '<template>' . $body . '</template>' );
79
80
		$valueParser = new Parser\Value($functionSet);
81
		$this->config = new Config($functionSet, $valueParser, $elementData, new Hook\Formatter(), new Parser\CssToXpath($functionSet, $template->getPrefix(), md5($this->tss)), $this->filePath, $headers);
82
83
		foreach ($this->modules as $module) $module->load($this->config);
84
		return $template;
85
	}
86
87
	//Add a postprocessing hook. This cleans up anything transphporm has added to the markup which needs to be removed
88
	private function doPostProcessing($template) {
89
		$template->addHook('//*[@transphporm]', new Hook\PostProcess());
90
		return $template;
91
	}
92
93
94
	//Load a template, firstly check if it's a file or a valid string
95
	private function loadTemplate() {
96
        $result = ['cache' => $this->template, 'headers' => []];
97
		if (strpos($this->template, "\n") === false && is_file($this->template)) $result = $this->loadTemplateFromFile($this->template);
98
		return $result;
99
	}
100
101
    private function loadTemplateFromFile($file) {
0 ignored issues
show
Unused Code introduced by
The parameter $file is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
102
        $xml = $this->cache->load($this->template, filemtime($this->template));
103
        return $xml ? $xml : ['cache' => file_get_contents($this->template) ?: "", 'headers' => []];
104
    }
105
106
	public function setCache(\ArrayAccess $cache) {
107
		$this->cache = new Cache($cache);
108
	}
109
110
	private function isValidDoc($xml) {
111
		return (strpos($xml, '<!') === 0 && strpos($xml, '<!--') !== 0) || strpos($xml, '<?') === 0 || strpos($xml, '<html') === 0;
112
	}
113
114
	public function __destruct() {
115
		//Required hack as DomXPath can only register static functions clear the statically stored instance to avoid memory leaks
116
		if (isset($this->config)) $this->config->getCssToXpath()->cleanup();
117
	}
118
}
119