Skip to content

Commit 3a04072

Browse files
committed
Releasing 1.1.2
2 parents 03b90dc + 4140b2d commit 3a04072

File tree

10 files changed

+363
-6
lines changed

10 files changed

+363
-6
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@ composer.phar
55
# You may choose to ignore a library lock file http://getcomposer.org/doc/02-libraries.md#lock-file
66
# composer.lock
77
/composer.lock
8+
/nbproject/private/

README.md

Lines changed: 45 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ This is a collection of useful classes and functions for every day PHP life. It
1010
* Slugifying strings for usage in URLs
1111
* Generating random strings
1212
* Formatting prices and units
13+
* Simple text templating
1314

1415
These classes are no rocket science, just simple helpers that prevent from wiriting the
1516
same code in various flavours over and over again.
@@ -44,7 +45,7 @@ It is possible to create an object yourself, but it is recommend to use the sing
4445
$request = \TgUtils\Request::getRequest();
4546
```
4647

47-
Inspect the [source code](https://github.com/technicalguru/php-utils/blob/src/TgUtils/Request.php) to find out about the various methods available.
48+
Inspect the [source code](https://github.com/technicalguru/php-utils/blob/main/src/TgUtils/Request.php) to find out about the various methods available.
4849

4950
## Date class
5051

@@ -74,7 +75,7 @@ $iso8601 = $date->toISO8601();
7475
$someString = $date->format('d.m.Y H:i:s');
7576
```
7677

77-
Inspect the [source code](https://github.com/technicalguru/php-utils/blob/src/TgUtils/Date.php) to find out about the various methods available.
78+
Inspect the [source code](https://github.com/technicalguru/php-utils/blob/main/src/TgUtils/Date.php) to find out about the various methods available.
7879

7980
## Logging
8081

@@ -174,8 +175,8 @@ Log::clean();
174175
## Authentication Helper
175176
A simple authentication helper interface along with a default implementation is provided:
176177

177-
* [TgUtils\Auth\CredentialsProvider](https://github.com/technicalguru/php-utils/blob/src/TgUtils/Auth/CredentialsProvider.php) - Interface to provide username and password to other objects
178-
* [TgUtils\Auth\DefaultCredentialsProvider](https://github.com/technicalguru/php-utils/blob/src/TgUtils/Auth/DefaultCredentialsProvider.php) - Simple default implementation of the interface
178+
* [TgUtils\Auth\CredentialsProvider](https://github.com/technicalguru/php-utils/blob/main/src/TgUtils/Auth/CredentialsProvider.php) - Interface to provide username and password to other objects
179+
* [TgUtils\Auth\DefaultCredentialsProvider](https://github.com/technicalguru/php-utils/blob/main/src/TgUtils/Auth/DefaultCredentialsProvider.php) - Simple default implementation of the interface
179180

180181
## Sensitive Data Obfuscation
181182

@@ -220,7 +221,45 @@ $emailJavascript = Obfuscation::obfuscateEmail('[email protected]', $id);
220221

221222
Please notice that not all characters are supported in the default character map. It covers mainly
222223
e-mail addresses and phone numbers. However, you can pass your own character set to the obfuscate methods
223-
as third argument. Please consult the [source code](https://github.com/technicalguru/php-utils/blob/src/TgUtils/Obfuscation.php) for more details.
224+
as third argument. Please consult the [source code](https://github.com/technicalguru/php-utils/blob/main/src/TgUtils/Obfuscation.php) for more details.
225+
226+
## Text Templating
227+
228+
To ease the generation of dynamic texts, a template processor is provided. This processor can work on texts that contain variables in
229+
curly brackets `{{variable-definition}}`. The processor knows objects, snippets and formatters.
230+
231+
**Objects** are application objects that hold attributes that you want to be replaced. An object's attribute will be referenced in a template
232+
with `{{objectKey.attributeName}}`, e.g. `{{user.name}}`.
233+
234+
**Snippets** are more complex replacements that will be inserted in your template. This is useful when you need the same complex
235+
text structure in multiple template generations, e.g. for a footer or a header text. Snippets are referenced in a template by
236+
their keys only: `{{snippetKey}}`. A snippet is implemented by the interface [`Snippet`](https://github.com/technicalguru/php-utils/blob/main/src/TgUtils/Templating/Snippet.php).
237+
238+
**Formatters** can be used to format an object's attribute. Formatters can take parameters to further customize the formatting. A good example
239+
is the [`DateFormatter`](https://github.com/technicalguru/php-utils/blob/main/src/TgUtils/Templating/DateFormatter.php). The formatter
240+
is referenced with the object's attribute by `{{objectKey.attribute:formatterKey:param1:param2...}}`, e.g. `{{user.created_on:date:rfc822}}`.
241+
242+
All three elements - objects, snippets and formatters - are given to the [`Processor`](https://github.com/technicalguru/php-utils/blob/main/src/TgUtils/Templating/Processor.php) in its constructor:
243+
244+
```
245+
$objects = array('user' => $myUser);
246+
$snippets = array('header' => new HeaderSnippet(), 'footer' => $new FooterSnippet());
247+
$formatters = array('date' => new DateFormatter());
248+
$language = 'en';
249+
$processor = new Processor($objects, $snippets, $formatters, $language);
250+
```
251+
252+
The language is for information and can be used in snippets or formatters to select the right text.
253+
254+
Finally you can process a template:
255+
256+
```
257+
$template = '{{header}} Hello {{user.name}}! Your account was created on {{user.created_on:date:d/m/Y}}.{{footer}}';
258+
echo $processor->process($template);
259+
260+
// Output is:
261+
// IMPORTANT MESSAGE! Hello John Doe! Your account was created on 02/03/2017. Best regards!
262+
```
224263

225264
## Other Utils
226265
There are some daily tasks that need to be done in applications. The `Utils` class addresses a few of them:
@@ -264,7 +303,7 @@ $priceString = FormatUtils::formatPrice(3000.643, 'EUR');
264303
$fileSize = FormatUtils::formatUnit(3000643, 'B');
265304
```
266305

267-
Inspect the [source code](https://github.com/technicalguru/php-utils/blob/src/TgUtils/Utils.php) to find more about the methods available.
306+
Inspect the [source code](https://github.com/technicalguru/php-utils/blob/main/src/TgUtils/Utils.php) to find more about the methods available.
268307

269308
# Contribution
270309
Report a bug, request an enhancement or pull request at the [GitHub Issue Tracker](https://github.com/technicalguru/php-utils/issues).

composer.json

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

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)