Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 946 lines (793 sloc) 30.663 kB
4a5d9b0 @Hayden Moved Sapphire module to open source path
Hayden authored
1 <?php
7189208 @hafriedlander ENHANCEMENT: Add Up support
hafriedlander authored
2
3 /**
4 * This tracks the current scope for an SSViewer instance. It has three goals:
5 * - Handle entering & leaving sub-scopes in loops and withs
6 * - Track Up and Top
7 * - (As a side effect) Inject data that needs to be available globally (used to live in ViewableData)
8 *
9 * In order to handle up, rather than tracking it using a tree, which would involve constructing new objects
10 * for each step, we use indexes into the itemStack (which already has to exist).
11 *
12 * Each item has three indexes associated with it
13 *
14 * - Pop. Which item should become the scope once the current scope is popped out of
15 * - Up. Which item is up from this item
16 * - Current. Which item is the first time this object has appeared in the stack
17 *
18 * We also keep the index of the current starting point for lookups. A lookup is a sequence of obj calls -
19 * when in a loop or with tag the end result becomes the new scope, but for injections, we throw away the lookup
20 * and revert back to the original scope once we've got the value we're after
21 *
22 */
0b7d396 @hafriedlander ENHANCEMENT: Add old-style _t and sprintf(_t) tags back into new SSVi…
hafriedlander authored
23 class SSViewer_Scope {
7189208 @hafriedlander ENHANCEMENT: Add Up support
hafriedlander authored
24
25 // The stack of previous "global" items
ab34688 @simonwelsh BUGFIX: Looping over a PaginatedList in the template caused a seg fau…
simonwelsh authored
26 // And array of item, itemIterator, itemIteratorTotal, pop_index, up_index, current_index
7189208 @hafriedlander ENHANCEMENT: Add Up support
hafriedlander authored
27 private $itemStack = array();
28
28bb835 @hafriedlander API-CHANGE: moving iterator support from ViewableData to SSViewer. Ne…
hafriedlander authored
29 protected $item; // The current "global" item (the one any lookup starts from)
30 protected $itemIterator; // If we're looping over the current "global" item, here's the iterator that tracks with item we're up to
31 protected $itemIteratorTotal; //Total number of items in the iterator
7189208 @hafriedlander ENHANCEMENT: Add Up support
hafriedlander authored
32
33 private $popIndex; // A pointer into the item stack for which item should be scope on the next pop call
5c33632 @hafriedlander MINOR: When Up called and we are at the top of the scope, throw a use…
hafriedlander authored
34 private $upIndex = null; // A pointer into the item stack for which item is "up" from this one
35 private $currentIndex = null; // A pointer into the item stack for which item is this one (or null if not in stack yet)
7189208 @hafriedlander ENHANCEMENT: Add Up support
hafriedlander authored
36
37 private $localIndex;
28bb835 @hafriedlander API-CHANGE: moving iterator support from ViewableData to SSViewer. Ne…
hafriedlander authored
38
39
7189208 @hafriedlander ENHANCEMENT: Add Up support
hafriedlander authored
40 function __construct($item){
41 $this->item = $item;
42 $this->localIndex=0;
ab34688 @simonwelsh BUGFIX: Looping over a PaginatedList in the template caused a seg fau…
simonwelsh authored
43 $this->itemStack[] = array($this->item, null, 0, null, null, 0);
7189208 @hafriedlander ENHANCEMENT: Add Up support
hafriedlander authored
44 }
45
46 function getItem(){
47 return $this->itemIterator ? $this->itemIterator->current() : $this->item;
48 }
49
50 function resetLocalScope(){
ab34688 @simonwelsh BUGFIX: Looping over a PaginatedList in the template caused a seg fau…
simonwelsh authored
51 list($this->item, $this->itemIterator, $this->itemIteratorTotal, $this->popIndex, $this->upIndex, $this->currentIndex) = $this->itemStack[$this->localIndex];
7189208 @hafriedlander ENHANCEMENT: Add Up support
hafriedlander authored
52 array_splice($this->itemStack, $this->localIndex+1);
53 }
54
acdd07a @sminnee BUGFIX: Allow template globals to be used in both object and value co…
sminnee authored
55 function getObj($name, $arguments = null, $forceReturnedObject = true, $cache = false, $cacheName = null) {
56 $on = $this->itemIterator ? $this->itemIterator->current() : $this->item;
57 return $on->obj($name, $arguments, $forceReturnedObject, $cache, $cacheName);
58 }
59
60 function obj($name, $arguments = null, $forceReturnedObject = true, $cache = false, $cacheName = null){
82ef236 @AngryPHPNerd Reset ...
AngryPHPNerd authored
61
7189208 @hafriedlander ENHANCEMENT: Add Up support
hafriedlander authored
62 switch ($name) {
63 case 'Up':
5c33632 @hafriedlander MINOR: When Up called and we are at the top of the scope, throw a use…
hafriedlander authored
64 if ($this->upIndex === null) user_error('Up called when we\'re already at the top of the scope', E_USER_ERROR);
65
ab34688 @simonwelsh BUGFIX: Looping over a PaginatedList in the template caused a seg fau…
simonwelsh authored
66 list($this->item, $this->itemIterator, $this->itemIteratorTotal, $unused2, $this->upIndex, $this->currentIndex) = $this->itemStack[$this->upIndex];
7189208 @hafriedlander ENHANCEMENT: Add Up support
hafriedlander authored
67 break;
68
69 case 'Top':
ab34688 @simonwelsh BUGFIX: Looping over a PaginatedList in the template caused a seg fau…
simonwelsh authored
70 list($this->item, $this->itemIterator, $this->itemIteratorTotal, $unused2, $this->upIndex, $this->currentIndex) = $this->itemStack[0];
7189208 @hafriedlander ENHANCEMENT: Add Up support
hafriedlander authored
71 break;
72
73 default:
acdd07a @sminnee BUGFIX: Allow template globals to be used in both object and value co…
sminnee authored
74 $this->item = $this->getObj($name, $arguments, $forceReturnedObject, $cache, $cacheName);
82ef236 @AngryPHPNerd Reset ...
AngryPHPNerd authored
75
7189208 @hafriedlander ENHANCEMENT: Add Up support
hafriedlander authored
76 $this->itemIterator = null;
77 $this->upIndex = $this->currentIndex ? $this->currentIndex : count($this->itemStack)-1;
78 $this->currentIndex = count($this->itemStack);
79 break;
80 }
81
ab34688 @simonwelsh BUGFIX: Looping over a PaginatedList in the template caused a seg fau…
simonwelsh authored
82 $this->itemStack[] = array($this->item, $this->itemIterator, $this->itemIteratorTotal, null, $this->upIndex, $this->currentIndex);
7189208 @hafriedlander ENHANCEMENT: Add Up support
hafriedlander authored
83 return $this;
84 }
85
86 function pushScope(){
87 $newLocalIndex = count($this->itemStack)-1;
88
ab34688 @simonwelsh BUGFIX: Looping over a PaginatedList in the template caused a seg fau…
simonwelsh authored
89 $this->popIndex = $this->itemStack[$newLocalIndex][3] = $this->localIndex;
7189208 @hafriedlander ENHANCEMENT: Add Up support
hafriedlander authored
90 $this->localIndex = $newLocalIndex;
91
92 // We normally keep any previous itemIterator around, so local $Up calls reference the right element. But
93 // once we enter a new global scope, we need to make sure we use a new one
94 $this->itemIterator = $this->itemStack[$newLocalIndex][1] = null;
95
96 return $this;
97 }
98
99 function popScope(){
100 $this->localIndex = $this->popIndex;
101 $this->resetLocalScope();
102
103 return $this;
104 }
105
106 function next(){
107 if (!$this->item) return false;
108
28bb835 @hafriedlander API-CHANGE: moving iterator support from ViewableData to SSViewer. Ne…
hafriedlander authored
109 if (!$this->itemIterator) {
7189208 @hafriedlander ENHANCEMENT: Add Up support
hafriedlander authored
110 if (is_array($this->item)) $this->itemIterator = new ArrayIterator($this->item);
111 else $this->itemIterator = $this->item->getIterator();
112
113 $this->itemStack[$this->localIndex][1] = $this->itemIterator;
28bb835 @hafriedlander API-CHANGE: moving iterator support from ViewableData to SSViewer. Ne…
hafriedlander authored
114 $this->itemIteratorTotal = iterator_count($this->itemIterator); //count the total number of items
ab34688 @simonwelsh BUGFIX: Looping over a PaginatedList in the template caused a seg fau…
simonwelsh authored
115 $this->itemStack[$this->localIndex][2] = $this->itemIteratorTotal;
7189208 @hafriedlander ENHANCEMENT: Add Up support
hafriedlander authored
116 $this->itemIterator->rewind();
117 }
118 else {
119 $this->itemIterator->next();
120 }
121
122 $this->resetLocalScope();
28bb835 @hafriedlander API-CHANGE: moving iterator support from ViewableData to SSViewer. Ne…
hafriedlander authored
123
7189208 @hafriedlander ENHANCEMENT: Add Up support
hafriedlander authored
124 if (!$this->itemIterator->valid()) return false;
125 return $this->itemIterator->key();
126 }
127
128 function __call($name, $arguments) {
129 $on = $this->itemIterator ? $this->itemIterator->current() : $this->item;
130 $retval = call_user_func_array(array($on, $name), $arguments);
131
132 $this->resetLocalScope();
133 return $retval;
134 }
135 }
136
28bb835 @hafriedlander API-CHANGE: moving iterator support from ViewableData to SSViewer. Ne…
hafriedlander authored
137 class SSViewer_BasicIteratorSupport implements TemplateIteratorProvider {
138
139 protected $iteratorPos;
140 protected $iteratorTotalItems;
141
374ed19 @hafriedlander API CHANGE: Change variable expose method in TemplateGlobalProvider a…
hafriedlander authored
142 public static function get_template_iterator_variables() {
28bb835 @hafriedlander API-CHANGE: moving iterator support from ViewableData to SSViewer. Ne…
hafriedlander authored
143 return array(
144 'First',
145 'Last',
146 'FirstLast',
147 'Middle',
148 'MiddleString',
149 'Even',
150 'Odd',
151 'EvenOdd',
152 'Pos',
153 'TotalItems',
154 'Modulus',
155 'MultipleOf',
156 );
157 }
158
159 /**
160 * Set the current iterator properties - where we are on the iterator.
161 *
162 * @param int $pos position in iterator
163 * @param int $totalItems total number of items
164 */
165 public function iteratorProperties($pos, $totalItems) {
166 $this->iteratorPos = $pos;
167 $this->iteratorTotalItems = $totalItems;
168 }
169
170 /**
171 * Returns true if this object is the first in a set.
172 *
173 * @return bool
174 */
175 public function First() {
176 return $this->iteratorPos == 0;
177 }
178
179 /**
180 * Returns true if this object is the last in a set.
181 *
182 * @return bool
183 */
184 public function Last() {
185 return $this->iteratorPos == $this->iteratorTotalItems - 1;
186 }
187
188 /**
189 * Returns 'first' or 'last' if this is the first or last object in the set.
190 *
191 * @return string|null
192 */
193 public function FirstLast() {
194 if($this->First() && $this->Last()) return 'first last';
195 if($this->First()) return 'first';
196 if($this->Last()) return 'last';
197 }
198
199 /**
200 * Return true if this object is between the first & last objects.
201 *
202 * @return bool
203 */
204 public function Middle() {
205 return !$this->First() && !$this->Last();
206 }
207
208 /**
209 * Return 'middle' if this object is between the first & last objects.
210 *
211 * @return string|null
212 */
213 public function MiddleString() {
214 if($this->Middle()) return 'middle';
215 }
216
217 /**
218 * Return true if this object is an even item in the set.
219 * The count starts from $startIndex, which defaults to 1.
220 *
221 * @param int $startIndex Number to start count from.
222 * @return bool
223 */
224 public function Even($startIndex = 1) {
225 return !$this->Odd($startIndex);
226 }
227
228 /**
229 * Return true if this is an odd item in the set.
230 *
231 * @param int $startIndex Number to start count from.
232 * @return bool
233 */
234 public function Odd($startIndex = 1) {
235 return (bool) (($this->iteratorPos+$startIndex) % 2);
236 }
237
238 /**
239 * Return 'even' or 'odd' if this object is in an even or odd position in the set respectively.
240 *
241 * @param int $startIndex Number to start count from.
242 * @return string
243 */
244 public function EvenOdd($startIndex = 1) {
245 return ($this->Even($startIndex)) ? 'even' : 'odd';
246 }
247
248 /**
249 * Return the numerical position of this object in the container set. The count starts at $startIndex.
250 * The default is the give the position using a 1-based index.
251 *
252 * @param int $startIndex Number to start count from.
253 * @return int
254 */
255 public function Pos($startIndex = 1) {
256 return $this->iteratorPos + $startIndex;
257 }
258
259 /**
260 * Return the total number of "sibling" items in the dataset.
261 *
262 * @return int
263 */
264 public function TotalItems() {
265 return $this->iteratorTotalItems;
266 }
267
268 /**
269 * Returns the modulus of the numerical position of the item in the data set.
270 * The count starts from $startIndex, which defaults to 1.
271 * @param int $Mod The number to perform Mod operation to.
272 * @param int $startIndex Number to start count from.
273 * @return int
274 */
275 public function Modulus($mod, $startIndex = 1) {
276 return ($this->iteratorPos + $startIndex) % $mod;
277 }
278
279 /**
280 * Returns true or false depending on if the pos of the iterator is a multiple of a specific number.
281 * So, <% if MultipleOf(3) %> would return true on indexes: 3,6,9,12,15, etc.
282 * The count starts from $offset, which defaults to 1.
283 * @param int $factor The multiple of which to return
284 * @param int $offset Number to start count from.
285 * @return bool
286 */
287 public function MultipleOf($factor, $offset = 1) {
288 return (bool) ($this->Modulus($factor, $offset) == 0);
289 }
290
291
292
293 }
7d13ba7 @madmatt Reverted geoffm's accidental commit to /open
madmatt authored
294 /**
0b7d396 @hafriedlander ENHANCEMENT: Add old-style _t and sprintf(_t) tags back into new SSVi…
hafriedlander authored
295 * This extends SSViewer_Scope to mix in data on top of what the item provides. This can be "global"
296 * data that is scope-independant (like BaseURL), or type-specific data that is layered on top cross-cut like
297 * (like $FirstLast etc).
298 *
299 * It's separate from SSViewer_Scope to keep that fairly complex code as clean as possible.
300 */
301 class SSViewer_DataPresenter extends SSViewer_Scope {
302
e4675d7 @hafriedlander BUGFIX: Restore ability to pass injected variables right into SSViewe…
hafriedlander authored
303 private static $globalProperties = null;
304 private static $iteratorProperties = null;
927dbbe @hafriedlander API-CHANGE: Global template variables can now be called directly usin…
hafriedlander authored
305
521742a @hafriedlander ENHANCEMENT: Split arguments passed to SSViewer into underlay and ove…
hafriedlander authored
306 /** @var array|null Overlay variables. Take precedence over anything from the current scope */
307 protected $overlay;
308 /** @var array|null Underlay variables. Concede precedence to overlay variables or anything from the current scope */
309 protected $underlay;
e4675d7 @hafriedlander BUGFIX: Restore ability to pass injected variables right into SSViewe…
hafriedlander authored
310
521742a @hafriedlander ENHANCEMENT: Split arguments passed to SSViewer into underlay and ove…
hafriedlander authored
311 function __construct($item, $overlay = null, $underlay = null){
0b7d396 @hafriedlander ENHANCEMENT: Add old-style _t and sprintf(_t) tags back into new SSVi…
hafriedlander authored
312 parent::__construct($item);
927dbbe @hafriedlander API-CHANGE: Global template variables can now be called directly usin…
hafriedlander authored
313
e4675d7 @hafriedlander BUGFIX: Restore ability to pass injected variables right into SSViewe…
hafriedlander authored
314 // Build up global property providers array only once per request
315 if (self::$globalProperties === null) {
316 self::$globalProperties = array();
317 // Get all the exposed variables from all classes that implement the TemplateGlobalProvider interface
374ed19 @hafriedlander API CHANGE: Change variable expose method in TemplateGlobalProvider a…
hafriedlander authored
318 $this->createCallableArray(self::$globalProperties, "TemplateGlobalProvider", "get_template_global_variables");
28bb835 @hafriedlander API-CHANGE: moving iterator support from ViewableData to SSViewer. Ne…
hafriedlander authored
319 }
320
e4675d7 @hafriedlander BUGFIX: Restore ability to pass injected variables right into SSViewe…
hafriedlander authored
321 // Build up iterator property providers array only once per request
322 if (self::$iteratorProperties === null) {
323 self::$iteratorProperties = array();
324 // Get all the exposed variables from all classes that implement the TemplateIteratorProvider interface
374ed19 @hafriedlander API CHANGE: Change variable expose method in TemplateGlobalProvider a…
hafriedlander authored
325 $this->createCallableArray(self::$iteratorProperties, "TemplateIteratorProvider", "get_template_iterator_variables", true); //call non-statically
28bb835 @hafriedlander API-CHANGE: moving iterator support from ViewableData to SSViewer. Ne…
hafriedlander authored
326 }
e4675d7 @hafriedlander BUGFIX: Restore ability to pass injected variables right into SSViewe…
hafriedlander authored
327
521742a @hafriedlander ENHANCEMENT: Split arguments passed to SSViewer into underlay and ove…
hafriedlander authored
328 $this->overlay = $overlay ? $overlay : array();
329 $this->underlay = $underlay ? $underlay : array();
28bb835 @hafriedlander API-CHANGE: moving iterator support from ViewableData to SSViewer. Ne…
hafriedlander authored
330 }
331
374ed19 @hafriedlander API CHANGE: Change variable expose method in TemplateGlobalProvider a…
hafriedlander authored
332 protected function createCallableArray(&$extraArray, $interfaceToQuery, $variableMethod, $createObject = false) {
28bb835 @hafriedlander API-CHANGE: moving iterator support from ViewableData to SSViewer. Ne…
hafriedlander authored
333 $implementers = ClassInfo::implementorsOf($interfaceToQuery);
2c65d3a @hafriedlander BUGFIX: Add casting support to global and iterator variable injection
hafriedlander authored
334 if($implementers) foreach($implementers as $implementer) {
335
336 // Create a new instance of the object for method calls
337 if ($createObject) $implementer = new $implementer();
338
339 // Get the exposed variables
68d83d1 @stojg BUGFIX PHP 5.2 doesn't allow calling a static method like $className:…
stojg authored
340 $exposedVariables = call_user_func(array($implementer, $variableMethod));
2c65d3a @hafriedlander BUGFIX: Add casting support to global and iterator variable injection
hafriedlander authored
341
342 foreach($exposedVariables as $varName => $details) {
ccb941e @halkyon BUGFIX Fixed places where Object::get_static() was being used. Replace
halkyon authored
343 if (!is_array($details)) $details = array('method' => $details, 'casting' => Config::inst()->get('ViewableData', 'default_cast', Config::FIRST_SET));
2c65d3a @hafriedlander BUGFIX: Add casting support to global and iterator variable injection
hafriedlander authored
344
345 // If just a value (and not a key => value pair), use it for both key and value
346 if (is_numeric($varName)) $varName = $details['method'];
347
348 // Add in a reference to the implementing class (might be a string class name or an instance)
349 $details['implementer'] = $implementer;
350
351 // And a callable array
352 if (isset($details['method'])) $details['callable'] = array($implementer, $details['method']);
353
354 // Save with both uppercase & lowercase first letter, so either works
1535ce6 @sminnee BUGFIX: Removed used of lcfirst, as it's PHP 5.3 only
sminnee authored
355 $lcFirst = strtolower($varName[0]) . substr($varName,1);
356 $extraArray[$lcFirst] = $details;
2c65d3a @hafriedlander BUGFIX: Add casting support to global and iterator variable injection
hafriedlander authored
357 $extraArray[ucfirst($varName)] = $details;
927dbbe @hafriedlander API-CHANGE: Global template variables can now be called directly usin…
hafriedlander authored
358 }
359 }
0b7d396 @hafriedlander ENHANCEMENT: Add old-style _t and sprintf(_t) tags back into new SSVi…
hafriedlander authored
360 }
f55c575 @hafriedlander BUGFIX: allowing ssviewer to be called without function arguments
hafriedlander authored
361
2c65d3a @hafriedlander BUGFIX: Add casting support to global and iterator variable injection
hafriedlander authored
362 function getInjectedValue($property, $params, $cast = true) {
28bb835 @hafriedlander API-CHANGE: moving iterator support from ViewableData to SSViewer. Ne…
hafriedlander authored
363 $on = $this->itemIterator ? $this->itemIterator->current() : $this->item;
927dbbe @hafriedlander API-CHANGE: Global template variables can now be called directly usin…
hafriedlander authored
364
2c65d3a @hafriedlander BUGFIX: Add casting support to global and iterator variable injection
hafriedlander authored
365 // Find the source of the value
366 $source = null;
28bb835 @hafriedlander API-CHANGE: moving iterator support from ViewableData to SSViewer. Ne…
hafriedlander authored
367
e4675d7 @hafriedlander BUGFIX: Restore ability to pass injected variables right into SSViewe…
hafriedlander authored
368 // Check for a presenter-specific override
521742a @hafriedlander ENHANCEMENT: Split arguments passed to SSViewer into underlay and ove…
hafriedlander authored
369 if (array_key_exists($property, $this->overlay)) {
370 $source = array('value' => $this->overlay[$property]);
371 }
372 // Check if the method to-be-called exists on the target object - if so, don't check any further injection locations
373 else if (isset($on->$property) || method_exists($on, $property)) {
374 $source = null;
375 }
376 // Check for a presenter-specific override
377 else if (array_key_exists($property, $this->underlay)) {
378 $source = array('value' => $this->underlay[$property]);
e4675d7 @hafriedlander BUGFIX: Restore ability to pass injected variables right into SSViewe…
hafriedlander authored
379 }
380 // Then for iterator-specific overrides
381 else if (array_key_exists($property, self::$iteratorProperties)) {
2c65d3a @hafriedlander BUGFIX: Add casting support to global and iterator variable injection
hafriedlander authored
382 $source = self::$iteratorProperties[$property];
e4675d7 @hafriedlander BUGFIX: Restore ability to pass injected variables right into SSViewe…
hafriedlander authored
383
384 if ($this->itemIterator) {
385 // Set the current iterator position and total (the object instance is the first item in the callable array)
2c65d3a @hafriedlander BUGFIX: Add casting support to global and iterator variable injection
hafriedlander authored
386 $source['implementer']->iteratorProperties($this->itemIterator->key(), $this->itemIteratorTotal);
e4675d7 @hafriedlander BUGFIX: Restore ability to pass injected variables right into SSViewe…
hafriedlander authored
387 } else {
388 // If we don't actually have an iterator at the moment, act like a list of length 1
2c65d3a @hafriedlander BUGFIX: Add casting support to global and iterator variable injection
hafriedlander authored
389 $source['implementer']->iteratorProperties(0, 1);
28bb835 @hafriedlander API-CHANGE: moving iterator support from ViewableData to SSViewer. Ne…
hafriedlander authored
390 }
e4675d7 @hafriedlander BUGFIX: Restore ability to pass injected variables right into SSViewe…
hafriedlander authored
391 }
392 // And finally for global overrides
393 else if (array_key_exists($property, self::$globalProperties)) {
2c65d3a @hafriedlander BUGFIX: Add casting support to global and iterator variable injection
hafriedlander authored
394 $source = self::$globalProperties[$property]; //get the method call
e4675d7 @hafriedlander BUGFIX: Restore ability to pass injected variables right into SSViewe…
hafriedlander authored
395 }
396
2c65d3a @hafriedlander BUGFIX: Add casting support to global and iterator variable injection
hafriedlander authored
397 if ($source) {
398 $res = array();
399
400 // Look up the value - either from a callable, or from a directly provided value
401 if (isset($source['callable'])) $res['value'] = call_user_func_array($source['callable'], $params);
402 elseif (isset($source['value'])) $res['value'] = $source['value'];
403 else throw new InvalidArgumentException("Injected property $property does't have a value or callable value source provided");
404
405 // If we want to provide a casted object, look up what type object to use
406 if ($cast) {
acdd07a @sminnee BUGFIX: Allow template globals to be used in both object and value co…
sminnee authored
407 // If the handler returns an object, then we don't need to cast.
408 if(is_object($res['value'])) {
409 $res['obj'] = $res['value'];
410 } else {
411 // Get the object to cast as
412 $casting = isset($source['casting']) ? $source['casting'] : null;
927dbbe @hafriedlander API-CHANGE: Global template variables can now be called directly usin…
hafriedlander authored
413
acdd07a @sminnee BUGFIX: Allow template globals to be used in both object and value co…
sminnee authored
414 // If not provided, use default
e5e8f48 @halkyon Merge branch (pull request #247) 'template-global-fixes' of https://g…
halkyon authored
415 if (!$casting) $casting = Config::inst()->get('ViewableData', 'default_cast', Config::FIRST_SET);
2c65d3a @hafriedlander BUGFIX: Add casting support to global and iterator variable injection
hafriedlander authored
416
acdd07a @sminnee BUGFIX: Allow template globals to be used in both object and value co…
sminnee authored
417 $obj = new $casting($property);
418 $obj->setValue($res['value']);
419
420 $res['obj'] = $obj;
421 }
927dbbe @hafriedlander API-CHANGE: Global template variables can now be called directly usin…
hafriedlander authored
422 }
423
2c65d3a @hafriedlander BUGFIX: Add casting support to global and iterator variable injection
hafriedlander authored
424 return $res;
425 }
426 }
427
acdd07a @sminnee BUGFIX: Allow template globals to be used in both object and value co…
sminnee authored
428 function getObj($name, $arguments = null, $forceReturnedObject = true, $cache = false, $cacheName = null) {
429 $result = $this->getInjectedValue($name, (array)$arguments);
430 if($result) return $result['obj'];
431 else return parent::getObj($name, $arguments, $forceReturnedObject, $cache, $cacheName);
432 }
433
2c65d3a @hafriedlander BUGFIX: Add casting support to global and iterator variable injection
hafriedlander authored
434 function __call($name, $arguments) {
435 //extract the method name and parameters
436 $property = $arguments[0]; //the name of the function being called
437
438 if (isset($arguments[1]) && $arguments[1] != null) $params = $arguments[1]; //the function parameters in an array
439 else $params = array();
440
441 $hasInjected = $res = null;
442
443 if ($name == 'hasValue') {
444 if ($val = $this->getInjectedValue($property, $params, false)) {
445 $hasInjected = true; $res = (bool)$val['value'];
446 }
447 }
448 else { // XML_val
449 if ($val = $this->getInjectedValue($property, $params)) {
4d4f9e0 @halkyon MINOR Code formatting in SSViewer
halkyon authored
450 $hasInjected = true;
451 $obj = $val['obj'];
452 $res = ($obj->hasMethod('forTemplate')) ? $obj->forTemplate() : '';
0b7d396 @hafriedlander ENHANCEMENT: Add old-style _t and sprintf(_t) tags back into new SSVi…
hafriedlander authored
453 }
454 }
927dbbe @hafriedlander API-CHANGE: Global template variables can now be called directly usin…
hafriedlander authored
455
2c65d3a @hafriedlander BUGFIX: Add casting support to global and iterator variable injection
hafriedlander authored
456 if ($hasInjected) {
457 $this->resetLocalScope();
458 return $res;
459 }
460 else {
461 return parent::__call($name, $arguments);
462 }
0b7d396 @hafriedlander ENHANCEMENT: Add old-style _t and sprintf(_t) tags back into new SSVi…
hafriedlander authored
463 }
464 }
465
466
467 /**
72abcd0 @chillu MINOR Documentation (from r105009)
chillu authored
468 * Parses a template file with an *.ss file extension.
469 *
470 * In addition to a full template in the templates/ folder, a template in
471 * templates/Content or templates/Layout will be rendered into $Content and
4a5d9b0 @Hayden Moved Sapphire module to open source path
Hayden authored
472 * $Layout, respectively.
4b3fa8f @chillu MINOR Documentation (from r104483)
chillu authored
473 *
72abcd0 @chillu MINOR Documentation (from r105009)
chillu authored
474 * A single template can be parsed by multiple nested {@link SSViewer} instances
475 * through $Layout/$Content placeholders, as well as <% include MyTemplateFile %> template commands.
476 *
477 * <b>Themes</b>
478 *
479 * See http://doc.silverstripe.org/themes and http://doc.silverstripe.org/themes:developing
480 *
4b3fa8f @chillu MINOR Documentation (from r104483)
chillu authored
481 * <b>Caching</b>
4a5d9b0 @Hayden Moved Sapphire module to open source path
Hayden authored
482 *
72abcd0 @chillu MINOR Documentation (from r105009)
chillu authored
483 * Compiled templates are cached via {@link SS_Cache}, usually on the filesystem.
484 * If you put ?flush=all on your URL, it will force the template to be recompiled.
02865a1 @maetl adding ?flush=all option which clears all cached templates from the L…
maetl authored
485 *
4b3fa8f @chillu MINOR Documentation (from r104483)
chillu authored
486 * @see http://doc.silverstripe.org/themes
487 * @see http://doc.silverstripe.org/themes:developing
488 *
f07258f @simonwelsh MINOR Update @package values to match renaming sapphire
simonwelsh authored
489 * @package framework
7d13ba7 @madmatt Reverted geoffm's accidental commit to /open
madmatt authored
490 * @subpackage view
4a5d9b0 @Hayden Moved Sapphire module to open source path
Hayden authored
491 */
b595074 @ajshort API CHANGE: SSViewer and SQLQuery no longer inherit from Object, sinc…
ajshort authored
492 class SSViewer {
60f75c5 @ajoneil Merged changes from 2.3 branch
ajoneil authored
493
494 /**
495 * @var boolean $source_file_comments
496 */
1063e50 MINOR: set template comments to be off by default. Ticket #3726
Will Rossiter authored
497 protected static $source_file_comments = false;
d26f08b @chillu MINOR merged branches/2.3 into trunk
chillu authored
498
499 /**
500 * Set whether HTML comments indicating the source .SS file used to render this page should be
501 * included in the output. This is enabled by default
60f75c5 @ajoneil Merged changes from 2.3 branch
ajoneil authored
502 *
503 * @param boolean $val
d26f08b @chillu MINOR merged branches/2.3 into trunk
chillu authored
504 */
60f75c5 @ajoneil Merged changes from 2.3 branch
ajoneil authored
505 static function set_source_file_comments($val) {
d26f08b @chillu MINOR merged branches/2.3 into trunk
chillu authored
506 self::$source_file_comments = $val;
507 }
6878171 @chillu ENHANCEMENT Added SSViewer->getTemplateFileByType() and SSViewer->set…
chillu authored
508
509 /**
60f75c5 @ajoneil Merged changes from 2.3 branch
ajoneil authored
510 * @return boolean
511 */
512 static function get_source_file_comments() {
513 return self::$source_file_comments;
514 }
515
516 /**
6878171 @chillu ENHANCEMENT Added SSViewer->getTemplateFileByType() and SSViewer->set…
chillu authored
517 * @var array $chosenTemplates Associative array for the different
72abcd0 @chillu MINOR Documentation (from r105009)
chillu authored
518 * template containers: "main" and "Layout". Values are absolute file paths to *.ss files.
6878171 @chillu ENHANCEMENT Added SSViewer->getTemplateFileByType() and SSViewer->set…
chillu authored
519 */
520 private $chosenTemplates = array();
521
522 /**
523 * @var boolean
524 */
4a5d9b0 @Hayden Moved Sapphire module to open source path
Hayden authored
525 protected $rewriteHashlinks = true;
526
6878171 @chillu ENHANCEMENT Added SSViewer->getTemplateFileByType() and SSViewer->set…
chillu authored
527 /**
528 * @var string
529 */
4a5d9b0 @Hayden Moved Sapphire module to open source path
Hayden authored
530 protected static $current_theme = null;
531
532 /**
49496e5 @sminnee BUGFIX: static publishing now uses the last non-null theme, OR the va…
sminnee authored
533 * @var string
534 */
535 protected static $current_custom_theme = null;
e4a043a @hafriedlander ENHANCEMENT: Allow arguments to be passed to templates via an array p…
hafriedlander authored
536
49496e5 @sminnee BUGFIX: static publishing now uses the last non-null theme, OR the va…
sminnee authored
537 /**
4a5d9b0 @Hayden Moved Sapphire module to open source path
Hayden authored
538 * Create a template from a string instead of a .ss file
bf5493d @sminnee #2997 - Added <% require %> tag to SSViewer
sminnee authored
539 *
540 * @return SSViewer
4a5d9b0 @Hayden Moved Sapphire module to open source path
Hayden authored
541 */
542 static function fromString($content) {
543 return new SSViewer_FromString($content);
544 }
545
6878171 @chillu ENHANCEMENT Added SSViewer->getTemplateFileByType() and SSViewer->set…
chillu authored
546 /**
4b3fa8f @chillu MINOR Documentation (from r104483)
chillu authored
547 * @param string $theme The "base theme" name (without underscores).
6878171 @chillu ENHANCEMENT Added SSViewer->getTemplateFileByType() and SSViewer->set…
chillu authored
548 */
4a5d9b0 @Hayden Moved Sapphire module to open source path
Hayden authored
549 static function set_theme($theme) {
550 self::$current_theme = $theme;
49496e5 @sminnee BUGFIX: static publishing now uses the last non-null theme, OR the va…
sminnee authored
551 //Static publishing needs to have a theme set, otherwise it defaults to the content controller theme
552 if(!is_null($theme))
553 self::$current_custom_theme=$theme;
4a5d9b0 @Hayden Moved Sapphire module to open source path
Hayden authored
554 }
6878171 @chillu ENHANCEMENT Added SSViewer->getTemplateFileByType() and SSViewer->set…
chillu authored
555
556 /**
557 * @return string
558 */
0a4d5ca @chillu BUGFIX: Updated SiteConfig-based theme selection to remove inappropri…
chillu authored
559 static function current_theme() {
560 return self::$current_theme;
4a5d9b0 @Hayden Moved Sapphire module to open source path
Hayden authored
561 }
562
563 /**
ac851e6 FEATURE: added get_theme_folder() to return the full path to the them…
Will Rossiter authored
564 * Returns the path to the theme folder
565 *
566 * @return String
567 */
568 static function get_theme_folder() {
569 return self::current_theme() ? THEMES_DIR . "/" . self::current_theme() : project();
570 }
571
572 /**
5c972b2 @ajshort API CHANGE: Moved ManifestBuilder::get_themes() to SSViewer::get_them…
ajshort authored
573 * Returns an array of theme names present in a directory.
574 *
575 * @param string $path
576 * @param bool $subthemes Include subthemes (default false).
577 * @return array
578 */
579 public static function get_themes($path = null, $subthemes = false) {
580 $path = rtrim($path ? $path : THEMES_PATH, '/');
581 $themes = array();
582
583 if (!is_dir($path)) return $themes;
584
585 foreach (scandir($path) as $item) {
586 if ($item[0] != '.' && is_dir("$path/$item")) {
587 if ($subthemes || !strpos($item, '_')) {
588 $themes[$item] = $item;
589 }
590 }
591 }
592
593 return $themes;
594 }
595
596 /**
49496e5 @sminnee BUGFIX: static publishing now uses the last non-null theme, OR the va…
sminnee authored
597 * @return string
598 */
599 static function current_custom_theme(){
600 return self::$current_custom_theme;
601 }
602
603 /**
72abcd0 @chillu MINOR Documentation (from r105009)
chillu authored
604 * @param string|array $templateList If passed as a string with .ss extension, used as the "main" template.
605 * If passed as an array, it can be used for template inheritance (first found template "wins").
606 * Usually the array values are PHP class names, which directly correlate to template names.
607 * <code>
608 * array('MySpecificPage', 'MyPage', 'Page')
609 * </code>
4a5d9b0 @Hayden Moved Sapphire module to open source path
Hayden authored
610 */
611 public function __construct($templateList) {
6878171 @chillu ENHANCEMENT Added SSViewer->getTemplateFileByType() and SSViewer->set…
chillu authored
612 // flush template manifest cache if requested
02865a1 @maetl adding ?flush=all option which clears all cached templates from the L…
maetl authored
613 if (isset($_GET['flush']) && $_GET['flush'] == 'all') {
6dc8146 @chillu BUGFIX: SSViewer now allows cli to do a flush on non-dev environments
chillu authored
614 if(Director::isDev() || Director::is_cli() || Permission::check('ADMIN')) {
08a5a7c @sminnee Merged from branches/2.3
sminnee authored
615 self::flush_template_cache();
616 } else {
5708f79 @chillu BUGFIX Consistently returning from a Security::permissionFailure() to…
chillu authored
617 return Security::permissionFailure(null, 'Please log in as an administrator to flush the template cache.');
08a5a7c @sminnee Merged from branches/2.3
sminnee authored
618 }
02865a1 @maetl adding ?flush=all option which clears all cached templates from the L…
maetl authored
619 }
6878171 @chillu ENHANCEMENT Added SSViewer->getTemplateFileByType() and SSViewer->set…
chillu authored
620
840343f @simonwelsh Checks for array to string conversion (E_NOTICE as of PHP5.4)
simonwelsh authored
621 if(!is_array($templateList) && substr((string) $templateList,-3) == '.ss') {
4a5d9b0 @Hayden Moved Sapphire module to open source path
Hayden authored
622 $this->chosenTemplates['main'] = $templateList;
623 } else {
c341054 @ajshort FEATURE: Replaced the template manifest with SS_TemplateLoader, which…
ajshort authored
624 $this->chosenTemplates = SS_TemplateLoader::instance()->findTemplates(
625 $templateList, self::current_theme()
626 );
4a5d9b0 @Hayden Moved Sapphire module to open source path
Hayden authored
627 }
628
0a3de45 @frankmullenger MINOR User error was assuming $templateList is always an array when i…
frankmullenger authored
629 if(!$this->chosenTemplates) {
630 $templateList = (is_array($templateList)) ? $templateList : array($templateList);
631
632 user_error("None of these templates can be found in theme '"
0a4d5ca @chillu BUGFIX: Updated SiteConfig-based theme selection to remove inappropri…
chillu authored
633 . self::current_theme() . "': ". implode(".ss, ", $templateList) . ".ss", E_USER_WARNING);
0a3de45 @frankmullenger MINOR User error was assuming $templateList is always an array when i…
frankmullenger authored
634 }
4a5d9b0 @Hayden Moved Sapphire module to open source path
Hayden authored
635 }
636
637 /**
638 * Returns true if at least one of the listed templates exists
639 */
c341054 @ajshort FEATURE: Replaced the template manifest with SS_TemplateLoader, which…
ajshort authored
640 public static function hasTemplate($templates) {
641 $manifest = SS_TemplateLoader::instance()->getManifest();
642
643 foreach ((array) $templates as $template) {
644 if ($manifest->getTemplate($template)) return true;
4a5d9b0 @Hayden Moved Sapphire module to open source path
Hayden authored
645 }
c341054 @ajshort FEATURE: Replaced the template manifest with SS_TemplateLoader, which…
ajshort authored
646
4a5d9b0 @Hayden Moved Sapphire module to open source path
Hayden authored
647 return false;
648 }
649
650 /**
651 * Set a global rendering option.
652 * The following options are available:
653 * - rewriteHashlinks: If true (the default), <a href="#..."> will be rewritten to contain the
654 * current URL. This lets it play nicely with our <base> tag.
c418702 @chillu BUGFIX: Added rewriteHashlinks = 'php' option to SSViewer so that sta…
chillu authored
655 * - If rewriteHashlinks = 'php' then, a piece of PHP script will be inserted before the hash
656 * links: "<?php echo $_SERVER['REQUEST_URI']; ?>". This is useful if you're generating a
657 * page that will be saved to a .php file and may be accessed from different URLs.
4a5d9b0 @Hayden Moved Sapphire module to open source path
Hayden authored
658 */
659 public static function setOption($optionName, $optionVal) {
660 SSViewer::$options[$optionName] = $optionVal;
661 }
2ce1882 @chillu ENHANCEMENT Added SSViewer::getOption() as a logical counterpart to S…
chillu authored
662
663 /**
664 * @param String
665 * @return Mixed
666 */
667 static function getOption($optionName) {
668 return SSViewer::$options[$optionName];
669 }
670
4a5d9b0 @Hayden Moved Sapphire module to open source path
Hayden authored
671 protected static $options = array(
672 'rewriteHashlinks' => true,
673 );
674
b89328e @chillu (merged from branches/roa. use "svn log -c <changeset> -g <module-svn…
chillu authored
675 protected static $topLevel = array();
676 public static function topLevel() {
677 if(SSViewer::$topLevel) {
678 return SSViewer::$topLevel[sizeof(SSViewer::$topLevel)-1];
679 }
680 }
4a5d9b0 @Hayden Moved Sapphire module to open source path
Hayden authored
681
682 /**
683 * Call this to disable rewriting of <a href="#xxx"> links. This is useful in Ajax applications.
684 * It returns the SSViewer objects, so that you can call new SSViewer("X")->dontRewriteHashlinks()->process();
685 */
686 public function dontRewriteHashlinks() {
687 $this->rewriteHashlinks = false;
016cff2 @chillu (merged from branches/roa. use "svn log -c <changeset> -g <module-svn…
chillu authored
688 self::$options['rewriteHashlinks'] = false;
4a5d9b0 @Hayden Moved Sapphire module to open source path
Hayden authored
689 return $this;
690 }
691
692 public function exists() {
693 return $this->chosenTemplates;
694 }
2d4fe27 @ajshort API CHANGE: Removed unused SSViewer::getTemplateFile() and getTemplat…
ajshort authored
695
6878171 @chillu ENHANCEMENT Added SSViewer->getTemplateFileByType() and SSViewer->set…
chillu authored
696 /**
697 * @param string $identifier A template name without '.ss' extension or path
698 * @param string $type The template type, either "main", "Includes" or "Layout"
699 * @return string Full system path to a template file
700 */
701 public static function getTemplateFileByType($identifier, $type) {
2d4fe27 @ajshort API CHANGE: Removed unused SSViewer::getTemplateFile() and getTemplat…
ajshort authored
702 $loader = SS_TemplateLoader::instance();
703 $found = $loader->findTemplates("$type/$identifier", self::current_theme());
d62b330 @chillu API CHANGE Fixed i18n _t() calls without namespaces in template inclu…
chillu authored
704
2d4fe27 @ajshort API CHANGE: Removed unused SSViewer::getTemplateFile() and getTemplat…
ajshort authored
705 if ($found) {
706 return $found['main'];
0a13923 @ajoneil BUGFIX: UTF-8 byte order mark gets propagated from template files (#4…
ajoneil authored
707 }
4a5d9b0 @Hayden Moved Sapphire module to open source path
Hayden authored
708 }
2d4fe27 @ajshort API CHANGE: Removed unused SSViewer::getTemplateFile() and getTemplat…
ajshort authored
709
4a5d9b0 @Hayden Moved Sapphire module to open source path
Hayden authored
710 /**
02865a1 @maetl adding ?flush=all option which clears all cached templates from the L…
maetl authored
711 * @ignore
712 */
713 static private $flushed = false;
714
715 /**
716 * Clears all parsed template files in the cache folder.
717 *
718 * Can only be called once per request (there may be multiple SSViewer instances).
719 */
f1f76b2 @sminnee FEATURE: Flush template cache before running tests
sminnee authored
720 static function flush_template_cache() {
02865a1 @maetl adding ?flush=all option which clears all cached templates from the L…
maetl authored
721 if (!self::$flushed) {
722 $dir = dir(TEMP_FOLDER);
723 while (false !== ($file = $dir->read())) {
724 if (strstr($file, '.cache')) { unlink(TEMP_FOLDER.'/'.$file); }
725 }
726 self::$flushed = true;
727 }
728 }
e4a043a @hafriedlander ENHANCEMENT: Allow arguments to be passed to templates via an array p…
hafriedlander authored
729
730 /**
731 * @var Zend_Cache_Core
732 */
733 protected $partialCacheStore = null;
734
735 /**
736 * Set the cache object to use when storing / retrieving partial cache blocks.
737 * @param Zend_Cache_Core $cache
738 */
739 public function setPartialCacheStore($cache) {
740 $this->partialCacheStore = $cache;
741 }
742
743 /**
744 * Get the cache object to use when storing / retrieving partial cache blocks
745 * @return Zend_Cache_Core
746 */
747 public function getPartialCacheStore() {
748 return $this->partialCacheStore ? $this->partialCacheStore : SS_Cache::factory('cacheblock');
749 }
750
751 /**
752 * An internal utility function to set up variables in preparation for including a compiled
753 * template, then do the include
754 *
755 * Effectively this is the common code that both SSViewer#process and SSViewer_FromString#process call
756 *
757 * @param string $cacheFile - The path to the file that contains the template compiled to PHP
758 * @param Object $item - The item to use as the root scope for the template
521742a @hafriedlander ENHANCEMENT: Split arguments passed to SSViewer into underlay and ove…
hafriedlander authored
759 * @param array|null $overlay - Any variables to layer on top of the scope
760 * @param array|null $underlay - Any variables to layer underneath the scope
e4a043a @hafriedlander ENHANCEMENT: Allow arguments to be passed to templates via an array p…
hafriedlander authored
761 * @return string - The result of executing the template
762 */
521742a @hafriedlander ENHANCEMENT: Split arguments passed to SSViewer into underlay and ove…
hafriedlander authored
763 protected function includeGeneratedTemplate($cacheFile, $item, $overlay, $underlay) {
e4a043a @hafriedlander ENHANCEMENT: Allow arguments to be passed to templates via an array p…
hafriedlander authored
764 if(isset($_GET['showtemplate']) && $_GET['showtemplate']) {
765 $lines = file($cacheFile);
766 echo "<h2>Template: $cacheFile</h2>";
767 echo "<pre>";
768 foreach($lines as $num => $line) {
769 echo str_pad($num+1,5) . htmlentities($line, ENT_COMPAT, 'UTF-8');
770 }
771 echo "</pre>";
772 }
773
774 $cache = $this->getPartialCacheStore();
521742a @hafriedlander ENHANCEMENT: Split arguments passed to SSViewer into underlay and ove…
hafriedlander authored
775 $scope = new SSViewer_DataPresenter($item, $overlay, $underlay);
e4a043a @hafriedlander ENHANCEMENT: Allow arguments to be passed to templates via an array p…
hafriedlander authored
776 $val = '';
777
778 include($cacheFile);
779
780 return $val;
781 }
782
02865a1 @maetl adding ?flush=all option which clears all cached templates from the L…
maetl authored
783 /**
4a5d9b0 @Hayden Moved Sapphire module to open source path
Hayden authored
784 * The process() method handles the "meat" of the template processing.
72abcd0 @chillu MINOR Documentation (from r105009)
chillu authored
785 * It takes care of caching the output (via {@link SS_Cache}),
786 * as well as replacing the special "$Content" and "$Layout"
787 * placeholders with their respective subtemplates.
788 * The method injects extra HTML in the header via {@link Requirements::includeInHTML()}.
789 *
790 * Note: You can call this method indirectly by {@link ViewableData->renderWith()}.
791 *
792 * @param ViewableData $item
793 * @param SS_Cache $cache Optional cache backend
794 * @return String Parsed template output.
4a5d9b0 @Hayden Moved Sapphire module to open source path
Hayden authored
795 */
e4a043a @hafriedlander ENHANCEMENT: Allow arguments to be passed to templates via an array p…
hafriedlander authored
796 public function process($item, $arguments = null) {
b89328e @chillu (merged from branches/roa. use "svn log -c <changeset> -g <module-svn…
chillu authored
797 SSViewer::$topLevel[] = $item;
e4a043a @hafriedlander ENHANCEMENT: Allow arguments to be passed to templates via an array p…
hafriedlander authored
798
799 if ($arguments && $arguments instanceof Zend_Cache_Core) {
800 Deprecation::notice('3.0', 'Use setPartialCacheStore to override the partial cache storage backend, the second argument to process is now an array of variables.');
801 $this->setPartialCacheStore($arguments);
802 $arguments = null;
803 }
804
4a5d9b0 @Hayden Moved Sapphire module to open source path
Hayden authored
805 if(isset($this->chosenTemplates['main'])) {
806 $template = $this->chosenTemplates['main'];
807 } else {
142a073 @ajoneil MINOR: Fix E_STRICT warning in SSViewer
ajoneil authored
808 $keys = array_keys($this->chosenTemplates);
809 $key = reset($keys);
810 $template = $this->chosenTemplates[$key];
4a5d9b0 @Hayden Moved Sapphire module to open source path
Hayden authored
811 }
812
813 if(isset($_GET['debug_profile'])) Profiler::mark("SSViewer::process", " for $template");
0200c75 @sminnee ENHANCEMENT #6023 Shorten SSViewer cached template path for readabili…
sminnee authored
814 $cacheFile = TEMP_FOLDER . "/.cache" . str_replace(array('\\','/',':'), '.', Director::makeRelative(realpath($template)));
4a5d9b0 @Hayden Moved Sapphire module to open source path
Hayden authored
815
816 $lastEdited = filemtime($template);
817
818 if(!file_exists($cacheFile) || filemtime($cacheFile) < $lastEdited || isset($_GET['flush'])) {
819 if(isset($_GET['debug_profile'])) Profiler::mark("SSViewer::process - compile", " for $template");
820
821 $content = file_get_contents($template);
408c8d6 @chillu bfojcapell: better i18n support and more flexibility allowed in templ…
chillu authored
822 $content = SSViewer::parseTemplateContent($content, $template);
4a5d9b0 @Hayden Moved Sapphire module to open source path
Hayden authored
823
824 $fh = fopen($cacheFile,'w');
825 fwrite($fh, $content);
826 fclose($fh);
827
828 if(isset($_GET['debug_profile'])) Profiler::unmark("SSViewer::process - compile", " for $template");
02865a1 @maetl adding ?flush=all option which clears all cached templates from the L…
maetl authored
829 }
e4a043a @hafriedlander ENHANCEMENT: Allow arguments to be passed to templates via an array p…
hafriedlander authored
830
521742a @hafriedlander ENHANCEMENT: Split arguments passed to SSViewer into underlay and ove…
hafriedlander authored
831 $underlay = array('I18NNamespace' => basename($template));
e4a043a @hafriedlander ENHANCEMENT: Allow arguments to be passed to templates via an array p…
hafriedlander authored
832
352d308 @chillu MINOR Documentation (from r105005)
chillu authored
833 // Makes the rendered sub-templates available on the parent item,
834 // through $Content and $Layout placeholders.
4a5d9b0 @Hayden Moved Sapphire module to open source path
Hayden authored
835 foreach(array('Content', 'Layout') as $subtemplate) {
836 if(isset($this->chosenTemplates[$subtemplate])) {
837 $subtemplateViewer = new SSViewer($this->chosenTemplates[$subtemplate]);
e4a043a @hafriedlander ENHANCEMENT: Allow arguments to be passed to templates via an array p…
hafriedlander authored
838 $subtemplateViewer->setPartialCacheStore($this->getPartialCacheStore());
839
521742a @hafriedlander ENHANCEMENT: Split arguments passed to SSViewer into underlay and ove…
hafriedlander authored
840 $underlay[$subtemplate] = $subtemplateViewer->process($item, $arguments);
4a5d9b0 @Hayden Moved Sapphire module to open source path
Hayden authored
841 }
842 }
e4675d7 @hafriedlander BUGFIX: Restore ability to pass injected variables right into SSViewe…
hafriedlander authored
843
521742a @hafriedlander ENHANCEMENT: Split arguments passed to SSViewer into underlay and ove…
hafriedlander authored
844 $val = $this->includeGeneratedTemplate($cacheFile, $item, $arguments, $underlay);
7189208 @hafriedlander ENHANCEMENT: Add Up support
hafriedlander authored
845 $output = Requirements::includeInHTML($template, $val);
4a5d9b0 @Hayden Moved Sapphire module to open source path
Hayden authored
846
b89328e @chillu (merged from branches/roa. use "svn log -c <changeset> -g <module-svn…
chillu authored
847 array_pop(SSViewer::$topLevel);
4a5d9b0 @Hayden Moved Sapphire module to open source path
Hayden authored
848
849 if(isset($_GET['debug_profile'])) Profiler::unmark("SSViewer::process", " for $template");
b8262b6 @sminnee Merged revisions 50783 via svnmerge from
sminnee authored
850
851 // If we have our crazy base tag, then fix # links referencing the current page.
b9e72a8 @halkyon BUGFIX Don't attempt to rewrite hash links in SSViewer if rewriteHash…
halkyon authored
852 if($this->rewriteHashlinks && self::$options['rewriteHashlinks']) {
853 if(strpos($output, '<base') !== false) {
c418702 @chillu BUGFIX: Added rewriteHashlinks = 'php' option to SSViewer so that sta…
chillu authored
854 if(SSViewer::$options['rewriteHashlinks'] === 'php') {
e2bf21b @chillu BUGFIX Escaping base URLs for anchor links rewritten by SSViewer::pro…
chillu authored
855 $thisURLRelativeToBase = "<?php echo strip_tags(\$_SERVER['REQUEST_URI']); ?>";
c418702 @chillu BUGFIX: Added rewriteHashlinks = 'php' option to SSViewer so that sta…
chillu authored
856 } else {
e2bf21b @chillu BUGFIX Escaping base URLs for anchor links rewritten by SSViewer::pro…
chillu authored
857 $thisURLRelativeToBase = strip_tags($_SERVER['REQUEST_URI']);
c418702 @chillu BUGFIX: Added rewriteHashlinks = 'php' option to SSViewer so that sta…
chillu authored
858 }
f71bf7d @chillu BUGFIX: Fixed regexp in anchor link rewriting (from r92077)
chillu authored
859 $output = preg_replace('/(<a[^>]+href *= *)"#/i', '\\1"' . $thisURLRelativeToBase . '#', $output);
b9e72a8 @halkyon BUGFIX Don't attempt to rewrite hash links in SSViewer if rewriteHash…
halkyon authored
860 }
b8262b6 @sminnee Merged revisions 50783 via svnmerge from
sminnee authored
861 }
4a5d9b0 @Hayden Moved Sapphire module to open source path
Hayden authored
862
863 return $output;
864 }
865
fa016ed @sminnee ENHANCEMENT: Parse template includes at runtime, so that recursive te…
sminnee authored
866 /**
867 * Execute the given template, passing it the given data.
868 * Used by the <% include %> template tag to process templates.
869 */
e4a043a @hafriedlander ENHANCEMENT: Allow arguments to be passed to templates via an array p…
hafriedlander authored
870 static function execute_template($template, $data, $arguments = null) {
fa016ed @sminnee ENHANCEMENT: Parse template includes at runtime, so that recursive te…
sminnee authored
871 $v = new SSViewer($template);
e4a043a @hafriedlander ENHANCEMENT: Allow arguments to be passed to templates via an array p…
hafriedlander authored
872 return $v->process($data, $arguments);
fa016ed @sminnee ENHANCEMENT: Parse template includes at runtime, so that recursive te…
sminnee authored
873 }
874
408c8d6 @chillu bfojcapell: better i18n support and more flexibility allowed in templ…
chillu authored
875 static function parseTemplateContent($content, $template="") {
f6587c4 @hafriedlander ENHANCEMENT: Use the new SSTemplateParser class to compile the templates
hafriedlander authored
876 return SSTemplateParser::compileString($content, $template, Director::isDev() && self::$source_file_comments);
4a5d9b0 @Hayden Moved Sapphire module to open source path
Hayden authored
877 }
878
879 /**
880 * Returns the filenames of the template that will be rendered. It is a map that may contain
881 * 'Content' & 'Layout', and will have to contain 'main'
882 */
883 public function templates() {
884 return $this->chosenTemplates;
885 }
6878171 @chillu ENHANCEMENT Added SSViewer->getTemplateFileByType() and SSViewer->set…
chillu authored
886
887 /**
888 * @param string $type "Layout" or "main"
889 * @param string $file Full system path to the template file
890 */
891 public function setTemplateFile($type, $file) {
892 $this->chosenTemplates[$type] = $file;
893 }
bd452e1 @sminnee BUGFIX #4063: Corrected base tag for IE6
sminnee authored
894
895 /**
896 * Return an appropriate base tag for the given template.
897 * It will be closed on an XHTML document, and unclosed on an HTML document.
898 *
899 * @param $contentGeneratedSoFar The content of the template generated so far; it should contain
900 * the DOCTYPE declaration.
901 */
902 static function get_base_tag($contentGeneratedSoFar) {
903 $base = Director::absoluteBaseURL();
904
905 // Is the document XHTML?
906 if(preg_match('/<!DOCTYPE[^>]+xhtml/i', $contentGeneratedSoFar)) {
a588ae3 @sminnee BUGFIX #5855 SSViewer::get_base_tag() should produce a properly close…
sminnee authored
907 return "<base href=\"$base\" />";
bd452e1 @sminnee BUGFIX #4063: Corrected base tag for IE6
sminnee authored
908 } else {
909 return "<base href=\"$base\"><!--[if lte IE 6]></base><![endif]-->";
910 }
911 }
4a5d9b0 @Hayden Moved Sapphire module to open source path
Hayden authored
912 }
913
7d13ba7 @madmatt Reverted geoffm's accidental commit to /open
madmatt authored
914 /**
915 * Special SSViewer that will process a template passed as a string, rather than a filename.
f07258f @simonwelsh MINOR Update @package values to match renaming sapphire
simonwelsh authored
916 * @package framework
7d13ba7 @madmatt Reverted geoffm's accidental commit to /open
madmatt authored
917 * @subpackage view
918 */
4a5d9b0 @Hayden Moved Sapphire module to open source path
Hayden authored
919 class SSViewer_FromString extends SSViewer {
920 protected $content;
921
922 public function __construct($content) {
923 $this->content = $content;
924 }
925
e4a043a @hafriedlander ENHANCEMENT: Allow arguments to be passed to templates via an array p…
hafriedlander authored
926 public function process($item, $arguments = null) {
927 if ($arguments && $arguments instanceof Zend_Cache_Core) {
928 Deprecation::notice('3.0', 'Use setPartialCacheStore to override the partial cache storage backend, the second argument to process is now an array of variables.');
929 $this->setPartialCacheStore($arguments);
930 $arguments = null;
931 }
932
2969a7e @chillu FEATURE: Add partial caching support to SSViewer. (from r97391)
chillu authored
933 $template = SSViewer::parseTemplateContent($this->content, "string sha1=".sha1($this->content));
4a5d9b0 @Hayden Moved Sapphire module to open source path
Hayden authored
934
935 $tmpFile = tempnam(TEMP_FOLDER,"");
936 $fh = fopen($tmpFile, 'w');
937 fwrite($fh, $template);
938 fclose($fh);
939
521742a @hafriedlander ENHANCEMENT: Split arguments passed to SSViewer into underlay and ove…
hafriedlander authored
940 $val = $this->includeGeneratedTemplate($tmpFile, $item, $arguments, null);
4a5d9b0 @Hayden Moved Sapphire module to open source path
Hayden authored
941
942 unlink($tmpFile);
943 return $val;
944 }
945 }
Something went wrong with that request. Please try again.