Completed
Push — master ( 0c8e25...9b0f13 )
by Drew
01:53
created

Selecta::build_pseudo_class_attribute()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 8
rs 9.4285
cc 2
eloc 4
nc 2
nop 1
1
<?php
2
3
namespace DrewM\Selecta;
4
 
5
class Selecta
6
{
7
	public static $single_tags    = array('img', 'br', 'hr', 'input');
8
	public static $pseudo_classes = array('disabled', 'checked');
9
	public static $meta_map       = array('.'=>'class', '#'=>'id');
10
11
	public static function build($selector, $contents='', $open_tags=true, $close_tags=true)
12
	{
13
		$parts = explode(' ', $selector);
14
		if (count($parts)) {
15
			$parts = array_reverse($parts);
16
			foreach($parts as $part) {
17
				$contents = self::tagify($part, $contents, $open_tags, $close_tags);
18
			}
19
		}
20
		return $contents;
21
	}
22
23
	public static function wrap($selector, $contents='')
24
	{
25
		return self::build($selector, $contents, true, true);
26
	}
27
28
	public static function open($selector)
29
	{
30
		return self::build($selector, '', true, false);
31
	}
32
33
	public static function close($selector)
34
	{
35
		return self::build($selector, '', false, true);
36
	}
37
38
	private static function tagify($selector='', $contents='', $open_tags=true, $close_tags=true)
39
	{
40
		$attrs = array();
41
42
		// replace dots within attribute selectors
43
		$selector = self::sanitise_attribute_dots($selector);
44
45
		$metas   = '\.\#\[\:';
46
		$pattern = '/(['.$metas.'])([^'.$metas.']*)?/';
47
		preg_match_all($pattern, $selector, $matches, PREG_SET_ORDER);
48
49
		if (count($matches)) {
50
			foreach($matches as $match) {
51
				$attrs = self::build_attributes($match[1], $match[2], $attrs);
52
			}
53
54
			// reduce selector to just tag name
55
			$parts    = preg_split('/['.$metas.']/', $selector);
56
			$selector = $parts[0];
57
		}
58
59
		return self::build_tag($selector, $attrs, $contents, $open_tags, $close_tags);
60
	}
61
62
	private static function build_attributes($meta_char, $value, $attrs)
63
	{
64
		$key = false;
65
		if (isset(self::$meta_map[$meta_char])) {
66
			$key = self::$meta_map[$meta_char];
67
		}else{
68
			switch ($meta_char) {
69
				
70
				// Attribute selectors
71
				case '[':
72
					$value = rtrim($value, ']');
73
74
					if (strpos($value, '=')) {
75
						$parts = explode('=', $value, 2);
76
						$key   = $parts[0];
77
						$value = self::unsanitise_attribute_dots($parts[1]);
78
					}else{
79
						$key   = $value;
80
						$value = false;
81
					}
82
					break;
83
84
				// Pseudo-class selectors
85
				case ':':
86
					list($key, $value) = self::build_pseudo_class_attribute($value);
87
					break;
88
			}
89
		}
90
91
		if ($key){
92
			if (isset($attrs[$key])) {
93
				$attrs[$key] .= ' '.$value;
94
			}else{
95
				$attrs[$key] = $value;
96
			}
97
		}
98
99
		return $attrs;
100
	}
101
102
	private static function build_pseudo_class_attribute($pclass='')
103
	{
104
		if (in_array($pclass, self::$pseudo_classes)) {
105
			return array($pclass, false);
106
		}
107
108
		return array(false, false);
109
	}
110
111
	private static function build_tag($name, $attributes=array(), $contents='', $open_tag=true, $close_tag=true)
112
	{
113
		$tag = '';
114
115
		if ($open_tag) {
116
			$tag = self::open_tag($name, $attributes);
117
		}
118
		
119
		if (in_array($name, self::$single_tags)) { 
120
			return $contents.$tag;
121
		}
122
123
		$tag .= $contents;
124
125
		if ($close_tag) {
126
			$tag .= self::close_tag($name);
127
		}
128
129
		return $tag;
130
	}
131
132
	private static function open_tag($name, $attributes=array())
133
	{
134
		$tag = '<'.self::html($name);
135
		if (count($attributes)) {
136
			// do attributes
137
			$attpairs = array();
138
			foreach($attributes as $key=>$val) {
139
				if ($val!='') {
140
					$attpairs[] = self::html($key).'="'.self::html($val, true).'"';
141
				}else{
142
					$attpairs[] = self::html($key);
143
				}
144
			}
145
			$tag .= ' '.implode(' ', $attpairs);
146
		}
147
		$tag .= '>';
148
149
		return $tag;
150
	}
151
152
	private static function close_tag($name)
153
	{
154
		return  '</'.self::html($name).'>';		
155
	}
156
157
	private static function html($s, $quotes=false, $double_encode=false)
158
	{
159
		if ($quotes) {
160
	        $q = ENT_QUOTES;
161
	    }else{
162
	        $q = ENT_NOQUOTES;
163
	    }
164
	    
165
		if ($s || (is_string($s) && strlen($s))) return htmlspecialchars($s, $q, 'UTF-8', $double_encode);
166
	    return '';
167
	}
168
169
	private static function sanitise_attribute_dots($selector)
170
	{
171
		if (strpos($selector, '[')!==false) {
172
			preg_match_all('/\[.*?\]/', $selector, $matches, PREG_SET_ORDER);
173
			if (count($matches)) {
174
				foreach($matches as $match) {
175
					$exact    = $match[0];
176
					$new      = str_replace('.', '__DOT__', $exact);
177
					$selector = str_replace($exact, $new, $selector);
178
				}
179
			}
180
		}
181
		return $selector;
182
	}
183
184
	private static function unsanitise_attribute_dots($string)
185
	{
186
		return str_replace('__DOT__', '.', $string);
187
	}
188
189
}