Completed
Push — master ( 04f450...a0fa0b )
by Tom
02:33
created

Sheet::parse()   A

Complexity

Conditions 4
Paths 6

Size

Total Lines 17
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 4
Bugs 1 Features 0
Metric Value
c 4
b 1
f 0
dl 0
loc 17
rs 9.2
cc 4
eloc 12
nc 6
nop 3
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\Parser;
8
/** Parses a .tss file into individual rules, each rule has a query e,g, `ul li` and a set of rules e.g. `display: none; bind: iteration(id);` */
9
class Sheet {
10
	private $tss;
11
	private $baseDir;
12
	private $prefix;
13
	private $valueParser;
14
15
	public function __construct($tss, $baseDir, Value $valueParser, $prefix = '') {
16
		$this->tss = $this->stripComments($tss);
17
		$this->baseDir = $baseDir;
18
		$this->prefix = $prefix;
19
		$this->valueParser = $valueParser;
20
	}
21
22
	public function parse($pos = 0, $rules = [], $indexStart = 0) {
23
		while ($next = strpos($this->tss, '{', $pos)) {
24
			if ($processing = $this->processingInstructions($this->tss, $pos, $next, count($rules)+$indexStart)) {
25
				$pos = $processing['endPos']+1;
26
				$rules = array_merge($rules, $processing['rules']);
27
			}
28
29
			$selector = trim(substr($this->tss, $pos, $next-$pos));
30
			$pos =  strpos($this->tss, '}', $next)+1;
31
			$newRules = $this->cssToRules($selector, count($rules)+$indexStart, $this->getProperties(trim(substr($this->tss, $next+1, $pos-2-$next))));
32
			$rules = $this->writeRule($rules, $newRules);
33
		}
34
		//there may be processing instructions at the end
35
		if ($processing = $this->processingInstructions($this->tss, $pos, strlen($this->tss), count($rules)+$indexStart)) $rules = array_merge($rules, $processing['rules']);
36
		usort($rules, [$this, 'sortRules']);
37
		return $rules;
38
	}
39
40
	private function CssToRules($selector, $index, $properties) {
41
		$parts = explode(',', $selector);
42
		$rules = [];
43
		foreach ($parts as $part) {
44
			$xPath = new CssToXpath($part, $this->valueParser, $this->prefix);
45
			$rules[$part] = new \Transphporm\Rule($xPath->getXpath(), $xPath->getPseudo(), $xPath->getDepth(), $index++);
46
			$rules[$part]->properties = $properties;
1 ignored issue
show
Documentation introduced by
The property $properties is declared private in Transphporm\Rule. Since you implemented __set(), maybe consider adding a @property or @property-write annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
47
		}		
48
		return $rules;
49
	}
50
51
	private function writeRule($rules, $newRules) {
52
		foreach ($newRules as $selector => $newRule) {
53
			if (isset($rules[$selector])) {
54
				$newRule->properties = array_merge($rules[$selector]->properties, $newRule->properties);
55
			}
56
			$rules[$selector] = $newRule;
57
		}	
58
		
59
		return $rules;
60
	}
61
62
	private function processingInstructions($tss, $pos, $next, $indexStart) {
63
		$rules = [];
64
		while (($atPos = strpos($tss, '@', $pos)) !== false) {
65
			if ($atPos  <= (int) $next) {
66
				$spacePos = strpos($tss, ' ', $atPos);
67
				$funcName = substr($tss, $atPos+1, $spacePos-$atPos-1);
68
				$pos = strpos($tss, ';', $spacePos);
69
				$args = substr($tss, $spacePos+1, $pos-$spacePos-1);
70
				$rules = array_merge($rules, $this->$funcName($args, $indexStart));
71
			}
72
			else {
73
				break;	
74
			} 
75
		}
76
77
		return empty($rules) ? false : ['endPos' => $pos, 'rules' => $rules];
78
	}
79
80
	private function import($args, $indexStart) {
81
		$sheet = new Sheet(file_get_contents($this->baseDir . trim($args, '\'" ')), $this->baseDir, $this->valueParser, $this->prefix);
82
		return $sheet->parse(0, [], $indexStart);
83
	}
84
85
	private function sortRules($a, $b) {
86
		//If they have the same depth, compare on index
87
		if ($a->depth === $b->depth) return $a->index < $b->index ? -1 : 1;
88
89
		return ($a->depth < $b->depth) ? -1 : 1;
90
	}
91
92
	private function stripComments($str) {
93
		$pos = 0;
94
		while (($pos = strpos($str, '/*', $pos)) !== false) {
95
			$end = strpos($str, '*/', $pos);
96
			$str = substr_replace($str, '', $pos, $end-$pos+2);
97
		}
98
99
		return $str;
100
	}
101
102
	private function getProperties($str) {
103
		$stringExtractor = new StringExtractor($str);
104
		$rules = explode(';', $stringExtractor);
105
		$return = [];
106
107
		foreach ($rules as $rule) {
108
			if (trim($rule) === '') continue;
109
			$parts = explode(':', $rule, 2);
110
111
			$parts[1] = $stringExtractor->rebuild($parts[1]);
112
			$return[trim($parts[0])] = isset($parts[1]) ? trim($parts[1]) : '';
113
		}
114
115
		return $return;
116
	}
117
}
118