1<?php
2
3/**
4* @package   s9e\TextFormatter
5* @copyright Copyright (c) 2010-2021 The s9e authors
6* @license   http://www.opensource.org/licenses/mit-license.php The MIT License
7*/
8namespace s9e\TextFormatter\Configurator\Items;
9
10use DOMDocument;
11use s9e\TextFormatter\Configurator\Helpers\NodeLocator;
12use s9e\TextFormatter\Configurator\Helpers\TemplateHelper;
13use s9e\TextFormatter\Configurator\Helpers\TemplateInspector;
14use s9e\TextFormatter\Configurator\Helpers\TemplateModifier;
15use s9e\TextFormatter\Configurator\TemplateNormalizer;
16
17class Template
18{
19	/**
20	* @var TemplateInspector Instance of TemplateInspector based on the content of this template
21	*/
22	protected $inspector;
23
24	/**
25	* @var bool Whether this template has been normalized
26	*/
27	protected $isNormalized = false;
28
29	/**
30	* @var string This template's content
31	*/
32	protected $template;
33
34	/**
35	* Constructor
36	*
37	* @param  string $template This template's content
38	*/
39	public function __construct($template)
40	{
41		$this->template = $template;
42	}
43
44	/**
45	* Handle calls to undefined methods
46	*
47	* Forwards calls to this template's TemplateInspector instance
48	*
49	* @return mixed
50	*/
51	public function __call($methodName, $args)
52	{
53		return call_user_func_array([$this->getInspector(), $methodName], $args);
54	}
55
56	/**
57	* Return this template's content
58	*
59	* @return string
60	*/
61	public function __toString()
62	{
63		return $this->template;
64	}
65
66	/**
67	* Return the content of this template as a DOMDocument
68	*
69	* NOTE: the content is wrapped in an <xsl:template/> node
70	*
71	* @return DOMDocument
72	*/
73	public function asDOM()
74	{
75		$xml = '<xsl:template xmlns:xsl="http://www.w3.org/1999/XSL/Transform">'
76		     . $this->__toString()
77		     . '</xsl:template>';
78
79		$dom = new TemplateDocument($this);
80		$dom->loadXML($xml);
81
82		return $dom;
83	}
84
85	/**
86	* Return all the nodes in this template whose content type is CSS
87	*
88	* @return array
89	*/
90	public function getCSSNodes()
91	{
92		return NodeLocator::getCSSNodes($this->asDOM());
93	}
94
95	/**
96	* Return an instance of TemplateInspector based on this template's content
97	*
98	* @return TemplateInspector
99	*/
100	public function getInspector()
101	{
102		if (!isset($this->inspector))
103		{
104			$this->inspector = new TemplateInspector($this->__toString());
105		}
106
107		return $this->inspector;
108	}
109
110	/**
111	* Return all the nodes in this template whose content type is JavaScript
112	*
113	* @return array
114	*/
115	public function getJSNodes()
116	{
117		return NodeLocator::getJSNodes($this->asDOM());
118	}
119
120	/**
121	* Return all the nodes in this template whose value is an URL
122	*
123	* @return array
124	*/
125	public function getURLNodes()
126	{
127		return NodeLocator::getURLNodes($this->asDOM());
128	}
129
130	/**
131	* Return a list of parameters in use in this template
132	*
133	* @return array Alphabetically sorted list of unique parameter names
134	*/
135	public function getParameters()
136	{
137		return TemplateHelper::getParametersFromXSL($this->__toString());
138	}
139
140	/**
141	* Set and/or return whether this template has been normalized
142	*
143	* @param  bool $bool If present, the new value for this template's isNormalized flag
144	* @return bool       Whether this template has been normalized
145	*/
146	public function isNormalized($bool = null)
147	{
148		if (isset($bool))
149		{
150			$this->isNormalized = $bool;
151		}
152
153		return $this->isNormalized;
154	}
155
156	/**
157	* Normalize this template's content
158	*
159	* @param  TemplateNormalizer $templateNormalizer
160	* @return void
161	*/
162	public function normalize(TemplateNormalizer $templateNormalizer)
163	{
164		$this->inspector    = null;
165		$this->template     = $templateNormalizer->normalizeTemplate($this->template);
166		$this->isNormalized = true;
167	}
168
169	/**
170	* Replace parts of this template that match given regexp
171	*
172	* @param  string   $regexp Regexp for matching parts that need replacement
173	* @param  callback $fn     Callback used to get the replacement
174	* @return void
175	*/
176	public function replaceTokens($regexp, $fn)
177	{
178		$this->inspector    = null;
179		$this->template     = TemplateModifier::replaceTokens($this->template, $regexp, $fn);
180		$this->isNormalized = false;
181	}
182
183	/**
184	* Replace this template's content
185	*
186	* @param  string $template New content
187	* @return void
188	*/
189	public function setContent($template)
190	{
191		$this->inspector    = null;
192		$this->template     = (string) $template;
193		$this->isNormalized = false;
194	}
195}