Completed
Push — master ( 9b1df4...0c8e25 )
by Drew
04:08
created

Selecta::tagify()   B

Complexity

Conditions 5
Paths 4

Size

Total Lines 30
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 4
Bugs 0 Features 0
Metric Value
c 4
b 0
f 0
dl 0
loc 30
rs 8.439
cc 5
eloc 17
nc 4
nop 4
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
		preg_match_all('/\[.*?\]/', $selector, $matches, PREG_SET_ORDER);
44
		if (count($matches)) {
45
			foreach($matches as $match) {
46
				$exact = $match[0];
47
				$new = str_replace('.', '__DOT__', $exact);
48
				$selector = str_replace($exact, $new, $selector);
49
			}
50
		}
51
52
		$metas   = '\.\#\[\:';
53
		$pattern = '/(['.$metas.'])([^'.$metas.']*)?/';
54
		preg_match_all($pattern, $selector, $matches, PREG_SET_ORDER);
55
56
		if (count($matches)) {
57
			foreach($matches as $match) {
58
				$attrs = self::build_attributes($match[1], $match[2], $attrs);
59
			}
60
61
			// reduce selector to just tag name
62
			$parts    = preg_split('/['.$metas.']/', $selector);
63
			$selector = $parts[0];
64
		}
65
66
		return self::build_tag($selector, $attrs, $contents, $open_tags, $close_tags);
67
	}
68
69
	private static function build_attributes($meta_char, $value, $attrs)
70
	{
71
		$key = false;
72
		if (isset(self::$meta_map[$meta_char])) {
73
			$key = self::$meta_map[$meta_char];
74
		}else{
75
			switch ($meta_char) {
76
				
77
				// Attribute selectors
78
				case '[':
79
					$value = rtrim($value, ']');
80
81
					if (strpos($value, '=')) {
82
						$parts = explode('=', $value, 2);
83
						$key   = $parts[0];
84
						$value = str_replace('__DOT__', '.', $parts[1]);
85
					}else{
86
						$key   = $value;
87
						$value = false;
88
					}
89
					break;
90
91
				// Pseudo-class selectors
92
				case ':':
93
					list($key, $value) = self::build_pseudo_class_attribute($value);
94
					break;
95
			}
96
		}
97
98
		if ($key){
99
			if (isset($attrs[$key])) {
100
				$attrs[$key] .= ' '.$value;
101
			}else{
102
				$attrs[$key] = $value;
103
			}
104
		}
105
106
		return $attrs;
107
	}
108
109
	private static function build_pseudo_class_attribute($pclass='')
110
	{
111
		if (in_array($pclass, self::$pseudo_classes)) {
112
			return array($pclass, false);
113
		}
114
115
		return array(false, false);
116
	}
117
118
	private static function build_tag($name, $attributes=array(), $contents='', $open_tag=true, $close_tag=true)
119
	{
120
		$tag = '';
121
122
		if ($open_tag) {
123
			$tag = self::open_tag($name, $attributes);
124
		}
125
		
126
		if (in_array($name, self::$single_tags)) { 
127
			return $contents.$tag;
128
		}
129
130
		$tag .= $contents;
131
132
		if ($close_tag) {
133
			$tag .= self::close_tag($name);
134
		}
135
136
		return $tag;
137
	}
138
139
	private static function open_tag($name, $attributes=array())
140
	{
141
		$tag = '<'.self::html($name);
142
		if (count($attributes)) {
143
			// do attributes
144
			$attpairs = array();
145
			foreach($attributes as $key=>$val) {
146
				if ($val!='') {
147
					$attpairs[] = self::html($key).'="'.self::html($val, true).'"';
148
				}else{
149
					$attpairs[] = self::html($key);
150
				}
151
			}
152
			$tag .= ' '.implode(' ', $attpairs);
153
		}
154
		$tag .= '>';
155
156
		return $tag;
157
	}
158
159
	private static function close_tag($name)
160
	{
161
		return  '</'.self::html($name).'>';		
162
	}
163
164
	private static function html($s, $quotes=false, $double_encode=false)
165
	{
166
		if ($quotes) {
167
	        $q = ENT_QUOTES;
168
	    }else{
169
	        $q = ENT_NOQUOTES;
170
	    }
171
	    
172
		if ($s || (is_string($s) && strlen($s))) return htmlspecialchars($s, $q, 'UTF-8', $double_encode);
173
	    return '';
174
	}
175
176
}