Skip to content

Commit aa0be35

Browse files
committed
#16 - Draft Templating
1 parent b82e447 commit aa0be35

File tree

6 files changed

+237
-0
lines changed

6 files changed

+237
-0
lines changed
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?php
2+
3+
namespace TgUtils\Templating;
4+
5+
/**
6+
* This formatter takes the currency as a parameter.
7+
*/
8+
class CurrencyFormatter implements Formatter {
9+
10+
public function __construct() {
11+
}
12+
13+
public function format($value, $params, Processor $processor) {
14+
if ($value == NULL) return '';
15+
$currency = count($params) > 0 ? $params[0] : ''
16+
return trim(\TgUtils\FormatUtils::formatPrice($value, $currency, $processor->language, ' '));
17+
}
18+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php
2+
3+
namespace TgUtils\Templating;
4+
5+
/**
6+
* This formatter takes the format as a parameter and assumes
7+
* the value to any form of Date or parseable date.
8+
*/
9+
class DateFormatter implements Formatter {
10+
11+
public function __construct($timezone = 'UTC') {
12+
$this->timezone = $timezone;
13+
}
14+
15+
public function format($value, $params, Processor $processor) {
16+
if ($value == NULL) return '';
17+
if (!is_object($value) && !is_a($value, 'TgUtils\\Date')) {
18+
$value = new \TgUtils\Date($value, $this->timezone);
19+
}
20+
if (count($params) > 0) {
21+
switch ($params[0]) {
22+
case 'unix': return $value->toUnix();
23+
case 'iso8601': return $value->toISO8601(TRUE);
24+
case 'rfc8601': return $value->toRFC822(TRUE);
25+
}
26+
return $value->format(\TgI18n\I18N::_($params[0]), TRUE, TRUE, $processor->language);
27+
}
28+
return $value->__toString();
29+
}
30+
}

src/TgUtils/Templating/Formatter.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
namespace TgUtils\Templating;
4+
5+
/**
6+
* A formatter can format a given value to some software-defined text, using parameters
7+
* and the given processor. The usage of the processor is discouraged but might be required.
8+
*/
9+
interface Formatter {
10+
11+
/**
12+
* Format the given object using the processor and the arguments.
13+
*/
14+
public function format($value, $params, Processor $processor);
15+
16+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?php
2+
3+
namespace TgUtils\Templating;
4+
5+
/**
6+
* This formatter assumes the value to be an array, an object or a i18n key
7+
* that I18N can process.
8+
*/
9+
class I18nFormatter implements Formatter {
10+
11+
public function __construct() {
12+
}
13+
14+
public function format($value, $params, Processor $processor) {
15+
if ($value == NULL) return '';
16+
return \TgI18n\I18n::_($value, $processor->language);
17+
}
18+
}

src/TgUtils/Templating/Processor.php

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
<?php
2+
3+
namespace TgUtils\Templating;
4+
5+
/** Provides some basic templating mechanism */
6+
class Processor {
7+
8+
protected $objects;
9+
protected $snippets;
10+
protected $formatters;
11+
public $language;
12+
13+
/**
14+
* @param array $objects - objects with key => object items
15+
* @param array $snippets - snippets with key => snippet object items
16+
* @param array $formatters - formatters with key => formatter object items
17+
*/
18+
public function __construct($objects = NULL, $snippets = NULL, $formatters = NULL, $language = NULL) {
19+
$this->objects = $objects != NULL ? $objects : array();
20+
$this->snippets = $snippets != NULL ? $snippets : array();
21+
$this->formatters = $formatters != NULL ? $formatters : array();
22+
$this->language = $language != NULL ? $language : \TgI18n\I18N::$defaultLangCode;
23+
}
24+
25+
/**
26+
* Sets the language.
27+
*/
28+
public function setLanguage($language) {
29+
$this->language = $language;
30+
}
31+
32+
/**
33+
* Replace any variables in content with values.
34+
* a variable is a text with {{object.attribute}}
35+
* if attribute is missing, a snippet with this name will be searched
36+
* @param string $s - the content to be processed
37+
*/
38+
protected function process($s) {
39+
$rc = '';
40+
$matches = array();
41+
preg_match_all('/{{(.*?)}}/', $s, $matches, PREG_OFFSET_CAPTURE);
42+
$fullMatches = $matches[0];
43+
$slimMatches = $matches[1];
44+
$lastEnd = 0;
45+
for ($i=0; $i<count($fullMatches); $i++) {
46+
$fMatch = $fullMatches[$i];
47+
$sMatch = $slimMatches[$i];
48+
$newStart = $fMatch[1];
49+
$length = strlen($fMatch[0]);
50+
// Take over the plain text since last match
51+
if ($newStart > $lastEnd) $rc .= substr($s, $lastEnd, $newStart-$lastEnd);
52+
// Take over the replacement
53+
$rc .= $this->getVar($sMatch[0]);
54+
// Prepare next iteration
55+
$lastEnd = $newStart + $length;
56+
}
57+
// Finally take the rest
58+
if ($lastEnd < strlen($s)) $rc .= substr($s, $lastEnd);
59+
return $rc;
60+
}
61+
62+
/** Returns the variable with given content definition.
63+
* A variable is a text with object.attribute
64+
* If attribute is missing, a snippet with this name will be searched
65+
*/
66+
protected function getVar($s) {
67+
$parts = explode('.', $s);
68+
$object = $parts[0];
69+
if (count($parts) > 1) return $this->getAttribute($object, $parts[1]);
70+
else {
71+
$snippet = $this->getSnippet($object);
72+
if ($snippet != NULL) {
73+
return $snippet->getOutput($this);
74+
}
75+
}
76+
return '[Not defined: '.$s.']';
77+
}
78+
79+
/**
80+
* Returns the object with the given key or NULL.
81+
*/
82+
public function getObject($name) {
83+
return isset($this->objects[$name]) ? $this->objects[$name] : NULL;
84+
}
85+
86+
/**
87+
* Returns the formatter with the given key or NULL.
88+
*/
89+
public function getFormatter($name) {
90+
return isset($this->formatter[$name]) ? $this->formatter[$name] : NULL;
91+
}
92+
93+
/**
94+
* Returns the snippet with the given key or NULL.
95+
*/
96+
protected function getSnippet($name) {
97+
return isset($this->snippets[$name]) ? $this->snippets[$name] : NULL;
98+
}
99+
100+
/**
101+
* Returns the value of the attribute in the object.
102+
* An attribute can have a formatter definition attached e.g. created_on:datetime
103+
* The formatter "datetime" will be used then.
104+
* More arguments for the formatter can follow, separated with : again
105+
*/
106+
protected function getAttribute($objName, $attr) {
107+
$object = $this->getObject($objName);
108+
$rc = '';
109+
if ($object != null) {
110+
// Split attributeName from format instructions
111+
$attrDef = explode(':', $attr);
112+
$attrName = array_shift($attrDef);
113+
$attrFormat = count($attrDef) > 0 ? array_shift($attrDef) : 'plain';
114+
if (isset($object->$attrName)) {
115+
$value = $object->$attrName;
116+
$rc = '';
117+
// check formatting
118+
if ($attrFormat != 'plain') {
119+
$formatter = $this->getFormatter($attrFormat);
120+
if ($formatter != NULL) {
121+
$rc = $formatter->format($object->$attrName, $attrDef, $this);
122+
}
123+
} else if (is_object($value)) {
124+
if (is_a($value, 'TgUtils\\Date')) {
125+
$formatter = $this->getFormatter('date');
126+
if ($formatter == NULL) $formatter = new DateFormatter();
127+
$rc = $formatter->format($object->$attrName, $attrDef, $this);
128+
} else {
129+
$rc = $value->__toString();
130+
}
131+
} else {
132+
$rc = $value;
133+
}
134+
}
135+
}
136+
return $rc;
137+
}
138+
139+
}

src/TgUtils/Templating/Snippet.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
namespace TgUtils\Templating;
4+
5+
/**
6+
* A snippet is a fixed, software-defined piece of text that can be inserted in
7+
* templates via the {{template-name}} variable.
8+
*/
9+
interface Snippet {
10+
11+
/**
12+
* Return the output of the template, using the given processor for objects and formatters.
13+
*/
14+
public function getOutput(Processor $processor);
15+
16+
}

0 commit comments

Comments
 (0)