Completed
Push — master ( a09952...25a05b )
by Richard
12s
created

Builder::setLocale()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 4
rs 10
cc 1
eloc 3
nc 1
nop 1
1
<?php
2
/* @description     Transformation Style Sheets - Revolutionising PHP templating    *
3
 * @author          Tom Butler [email protected]                                             *
4
 * @copyright       2015 Tom Butler <[email protected]> | https://r.je/                      *
5
 * @license         http://www.opensource.org/licenses/bsd-license.php  BSD License *
6
 * @version         1.0                                                             */
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
55
		$elementData = new \Transphporm\Hook\ElementData(new \SplObjectStorage(), $data);
56
		$functionSet = new FunctionSet($elementData);
57
58
		$cachedOutput = $this->loadTemplate();
59
		//To be a valid XML document it must have a root element, automatically wrap it in <template> to ensure it does
60
		$template = new Template($this->isValidDoc($cachedOutput['body']) ? str_ireplace('<!doctype', '<!DOCTYPE', $cachedOutput['body']) : '<template>' . $cachedOutput['body'] . '</template>' );
61
		$valueParser = new Parser\Value($functionSet);
62
		$this->config = new Config($functionSet, $valueParser, $elementData, new Hook\Formatter(), new Parser\CssToXpath($functionSet, $template->getPrefix(), md5($this->tss)), $this->filePath, $headers);
63
64
		foreach ($this->modules as $module) $module->load($this->config);
65
66
		$this->processRules($template, $this->config);
67
68
		$result = ['body' => $template->output($document), 'headers' => array_merge($cachedOutput['headers'], $headers)];
69
		$this->cache->write($this->template, $result);
70
		$result['body'] = $this->doPostProcessing($template)->output($document);
71
		return (object) $result;
72
	}
73
74
	private function processRules($template, $config) {
75
		$rules = $this->getRules($template, $config);
76
77
		foreach ($rules as $rule) {
78
			if ($rule->shouldRun($this->time)) $this->executeTssRule($rule, $template, $config);
79
		}
80
	}
81
82
	//Add a postprocessing hook. This cleans up anything transphporm has added to the markup which needs to be removed
83
	private function doPostProcessing($template) {
84
		$template->addHook('//*[@transphporm]', new Hook\PostProcess());
85
		return $template;
86
	}
87
88
	//Process a TSS rule e.g. `ul li {content: "foo"; format: bar}
89
	private function executeTssRule($rule, $template, $config) {
90
		$rule->touch();
91
92
		$pseudoMatcher = $config->createPseudoMatcher($rule->pseudo);
93
		$hook = new Hook\PropertyHook($rule->properties, $config->getLine(), $rule->file, $rule->line, $pseudoMatcher, $config->getValueParser(), $config->getFunctionSet(), $config->getFilePath());
0 ignored issues
show
Bug introduced by
$config->getLine() cannot be passed to __construct() as the parameter $configLine expects a reference.
Loading history...
94
		$config->loadProperties($hook);
95
		$template->addHook($rule->query, $hook);
96
	}
97
98
	//Load a template, firstly check if it's a file or a valid string
99
	private function loadTemplate() {
100
        $result = ['body' => $this->template, 'headers' => []];
101
		if (file_exists($this->template)) $result = $this->loadTemplateFromFile($this->template);
102
		return $result;
103
	}
104
105
    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...
106
        $xml = $this->cache->load($this->template, filemtime($this->template));
107
        return $xml ? $xml : ['body' => file_get_contents($this->template) ?: "", 'headers' => []];
108
    }
109
110
	//Load the TSS rules either from a file or as a string
111
	//N.b. only files can be cached
112
	private function getRules($template, $config) {
113
		$cache = new TSSCache($this->cache, $template->getPrefix());
114
		return (new Parser\Sheet($this->tss, $config->getCssToXpath(), $config->getValueParser(), $cache, $config->getFilePath()))->parse();
115
	}
116
117
	public function setCache(\ArrayAccess $cache) {
118
		$this->cache = new Cache($cache);
119
	}
120
121
	private function isValidDoc($xml) {
122
		return (strpos($xml, '<!') === 0 && strpos($xml, '<!--') !== 0) || strpos($xml, '<?') === 0;
123
	}
124
125
	public function __destruct() {
126
		//Required hack as DomXPath can only register static functions clear, the statically stored instance to avoid memory leaks
127
		if (isset($this->config)) $this->config->getCssToXpath()->cleanup();
128
	}
129
}
130