Completed
Push — master ( 73e1e5...4f3b07 )
by Tom
02:36
created

Builder   A

Complexity

Total Complexity 22

Size/Duplication

Total Lines 113
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 10

Importance

Changes 36
Bugs 2 Features 2
Metric Value
wmc 22
c 36
b 2
f 2
lcom 1
cbo 10
dl 0
loc 113
rs 10

11 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 8 3
A setTime() 0 3 1
A loadModule() 0 3 1
A output() 0 21 3
A processRules() 0 6 3
A doPostProcessing() 0 4 1
A executeTssRule() 0 10 1
A loadTemplate() 0 7 3
A getRules() 0 14 3
A setCache() 0 3 1
A isValidDoc() 0 3 2
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 $baseDir;
13
	private $cache;
14
	private $time;
15
	private $modules = [];
16
	private $defaultModules = [
17
		'\\Transphporm\\Module\\Basics',
18
		'\\Transphporm\\Module\\Pseudo',
19
		'\\Transphporm\\Module\\Format'
20
	];
21
22
	public function __construct($template, $tss = '', $modules = null) {
23
		$this->template = $template;
24
		$this->tss = $tss;
25
		$this->cache = new Cache(new \ArrayObject());
26
27
		$modules = is_array($modules) ? $modules : $this->defaultModules;
28
		foreach ($modules as $module) $this->loadModule(new $module);
29
	}
30
31
	//Allow setting the time used by Transphporm for caching. This is for testing purposes
32
	//Would be better if PHP allowed setting the script clock, but this is the simplest way of overriding it
33
	public function setTime($time) {
34
		$this->time = $time;
35
	}
36
37
	public function loadModule(Module $module) {
38
		$this->modules[get_class($module)] = $module;
39
	}
40
41
	public function output($data = null, $document = false) {
42
		$headers = [];
43
		
44
		$data = new Hook\DataFunction(new \SplObjectStorage(), $data, $this->baseDir);
45
		$featureSet = new FeatureSet($data, new Hook\Formatter(), $headers);
46
47
		foreach ($this->modules as $module) $module->load($featureSet);
48
		//$locale = $this->getLocale();
0 ignored issues
show
Unused Code Comprehensibility introduced by
60% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
49
		
50
		$cachedOutput = $this->loadTemplate();
51
		//To be a valid XML document it must have a root element, automatically wrap it in <template> to ensure it does
52
		$template = new Template($this->isValidDoc($cachedOutput['body']) ? str_ireplace('<!doctype', '<!DOCTYPE', $cachedOutput['body']) : '<template>' . $cachedOutput['body'] . '</template>' );
53
54
		$this->processRules($template, $data, $featureSet);
55
		
56
		$result = ['body' => $template->output($document), 'headers' => array_merge($cachedOutput['headers'], $headers)];
57
		$this->cache->write($this->template, $result);		
58
		$result['body'] = $this->doPostProcessing($template)->output($document);
59
60
		return (object) $result;
61
	}
62
63
	private function processRules($template, $data, $featureSet) {
64
		$valueParser = new Parser\Value($data);
65
		foreach ($this->getRules($template, $valueParser) as $rule) {
66
			if ($rule->shouldRun($this->time)) $this->executeTssRule($rule, $template, $valueParser, $featureSet);
67
		}
68
	}
69
70
	//Add a postprocessing hook. This cleans up anything transphporm has added to the markup which needs to be removed
71
	private function doPostProcessing($template) {
72
		$template->addHook('//*[@transphporm]', new Hook\PostProcess());
73
		return $template;
74
	}
75
76
	//Process a TSS rule e.g. `ul li {content: "foo"; format: bar}
77
	private function executeTssRule($rule, $template, $valueParser, $featureSet) {
78
		$rule->touch();
79
		$pseudoMatcher = new Hook\PseudoMatcher($rule->pseudo);
0 ignored issues
show
Unused Code introduced by
$pseudoMatcher is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
80
		$pseudoMatcher = $featureSet->createPseudoMatcher($rule->pseudo);
81
82
		$hook = new Hook\PropertyHook($rule->properties, $pseudoMatcher, $valueParser);
83
		// foreach ($this->featureSetas $name => $property) $hook->registerProperty($name, $property);
0 ignored issues
show
Unused Code Comprehensibility introduced by
64% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
84
		$featureSet->loadProperties($hook);
85
		$template->addHook($rule->query, $hook);
86
	}
87
88
	//Load a template, firstly check if it's a file or a valid string
89
	private function loadTemplate() {
90
		if (trim($this->template)[0] !== '<') {			
91
			$xml = $this->cache->load($this->template, filemtime($this->template));
92
			return $xml ? $xml : ['body' => file_get_contents($this->template), 'headers' => []];
93
		}
94
		else return ['body' => $this->template, 'headers' => []];	
95
	}
96
97
	//Load the TSS rules either from a file or as a string
98
	//N.b. only files can be cached
99
	private function getRules($template, $valueParser) {		
100
		if (is_file($this->tss)) {
101
			$this->baseDir = dirname(realpath($this->tss)) . DIRECTORY_SEPARATOR;
102
			//The cache for the key: the filename and template prefix
103
			//Each template may have a different prefix which changes the parsed TSS,
104
			//Because of this the cache needs to be generated for each template prefix.
105
			$key = $this->tss . $template->getPrefix() . $this->baseDir;
106
			//Try to load the cached rules, if not set in the cache (or expired) parse the supplied sheet
107
			$rules = $this->cache->load($key, filemtime($this->tss));
108
			if (!$rules) return $this->cache->write($key, (new Parser\Sheet(file_get_contents($this->tss), $this->baseDir, $valueParser, $template->getPrefix()))->parse());
109
			else return $rules;
110
		}
111
		else return (new Parser\Sheet($this->tss, $this->baseDir, $valueParser, $template->getPrefix()))->parse();
112
	}
113
114
	public function setCache(\ArrayAccess $cache) {
115
		$this->cache = new Cache($cache);
116
	}
117
118
	private function isValidDoc($xml) {
119
		return strpos($xml, '<!') === 0 || strpos($xml, '<?') === 0;
120
	}
121
}
122