From 45afbfabdf97d384c06fb190536fa0f9accc032c Mon Sep 17 00:00:00 2001 From: bzick Date: Thu, 8 May 2014 12:56:37 +0400 Subject: [PATCH] Add STRIP option --- README.md | 7 ++- docs/start.md | 71 ++++++++++++++++++++++++++++++ docs/syntax.md | 71 +++++++++++++++++++++++------- docs/usage.md | 38 ---------------- src/Fenom.php | 26 +++++++---- src/Fenom/Compiler.php | 17 +++++-- src/Fenom/Modifier.php | 4 +- src/Fenom/Tag.php | 14 ++++++ src/Fenom/Template.php | 10 +++-- tests/TestCase.php | 20 ++++----- tests/cases/Fenom/TemplateTest.php | 2 +- tests/cases/FenomTest.php | 16 ++++++- 12 files changed, 209 insertions(+), 87 deletions(-) create mode 100644 docs/start.md delete mode 100644 docs/usage.md diff --git a/README.md b/README.md index c060c54..2839411 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,8 @@ Fenom - Template Engine for PHP =============================== -> Composer package: `{"fenom/fenom": "2.*"}`. See on [Packagist.org](https://packagist.org/packages/fenom/fenom) +> Composer [package](https://packagist.org/packages/fenom/fenom): `{"fenom/fenom": "2.*"}`. +> For old version: `{"fenom/fenom": "1.*"}`. List of incompatibilities between 1.* and 2.* versions. [![Latest Stable Version](https://poser.pugx.org/fenom/fenom/v/stable.png)](https://packagist.org/packages/fenom/fenom) [![Build Status](https://travis-ci.org/bzick/fenom.svg?branch=develop)](https://travis-ci.org/bzick/fenom) @@ -9,6 +10,10 @@ Fenom - Template Engine for PHP [![Total Downloads](https://poser.pugx.org/fenom/fenom/downloads.png)](https://packagist.org/packages/fenom/fenom) ## [Usage](./docs/usage.md) :: [Documentation](./docs/readme.md) :: [Benchmark](./docs/benchmark.md) :: [Articles](./docs/articles.md) +## What is it + +*Fenom* (from "fenomenal") — шаблонизатор на PHP с большими возможностями и синтаксисом Smarty. + * Simple [syntax](./docs/syntax.md) * [Fast](./docs/benchmark.md) * [Secure](./docs/settings.md) diff --git a/docs/start.md b/docs/start.md new file mode 100644 index 0000000..a53e07c --- /dev/null +++ b/docs/start.md @@ -0,0 +1,71 @@ +Basic usage +=========== + +## Install Fenom + +### Composer + +Add package Fenom in your require-list in `composer.json`: +```json +{ + "require": { + "fenom/fenom": "2.*" + } +} +``` +and update project's dependencies: `composer update`. + +### Custom loader + +Clone Fenom to any directory: `git clone https://github.com/bzick/fenom.git`. Recommended use latest tag. +Fenom use [psr-0](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md#autoloading-standard) autoloading standard. Therefore you can +* use `psr-0` format in your project loader for loading Fenom's classes +* or register Fenom's autoloader: ```php +Fenom::registerAutoload(); +``` +For loading itself. + +Also you can use this autoloader for loading any library with `psr-0` file naming: +```php +Fenom::registerAutoload(PROJECT_DIR."/src"); +``` + +## Setup Fenom + +Create an object via factory method +```php +$fenom = Fenom::factory('/path/to/templates', '/path/to/compiled/template', $options); +``` + +Create an object via `new` operator +```php +$fenom = new Fenom(new Provider('/path/to/templates')); +$fenom->setCompileDir('/path/to/template/cache'); +$fenom->setOptions($options); +``` + +* `/path/to/templates` — directory, where stores your templates. +* `/path/to/template/cache` — directory, where stores compiled templates in PHP files. +* `$options` - bit-mask or array of [Fenom settings](./docs/settings.md). + +### Use Fenom + +Output template +```php +$fenom->display("template/name.tpl", $vars); +``` + +Get the result of rendering the template +```php +$result = $fenom->fetch("template/name.tpl", $vars); +``` + +Create the pipeline of rendering into callback +```php +$fenom->pipe( + "template/sitemap.tpl", + $vars, + $callback = [new SplFileObject("/tmp/sitemap.xml", "w"), "fwrite"], // pipe to file /tmp/sitemap.xml + $chunk_size = 1e6 // chunk size for callback +); +``` diff --git a/docs/syntax.md b/docs/syntax.md index ef3332e..0063d1a 100644 --- a/docs/syntax.md +++ b/docs/syntax.md @@ -1,11 +1,61 @@ -Syntax [RU] -=========== +Syntax +====== -Fenom implement [Smarty](http://www.smarty.net/) syntax with some improvements +Fenom implements [Smarty](http://www.smarty.net/) syntax with some improvements. +All Fenom tags enclosed in the delimiters `{` and `}`, for example `{var $five = 5}`. +If you wanna leave delimiters as is in the template use [special statements or tags](#ignoring-delimiters). + +*Note* +Fenom implements [Smarty](http://www.smarty.net/) syntax but not implements Smarty tags, however, some tags very similar. +But not so bad, Fenom has the [extras](https://github.com/bzick/fenom-extra) that make Fenom like Smarty. ## Variable -### Use variables +Variables in Fenom can be either displayed directly or used as arguments for functions, attributes and modifiers, +inside conditional expressions, etc. + +### Example variables + +Next example uses simple variables `$user_id` ans `$user_name` +```smarty +
Hello, {$user_name}.
+``` + +Example outputs next HTML code: +```html +
Hello, Bzick.
+``` + +Переменные могут быть массивом. В этом случае обращение по ключу происходит через опертор `.` или, как в PHP, через операторы `[` и `]` +```smarty +
Hello, {$user.name}.
+``` + +`{$user.id}` and `{$user['id']}` are same. + +```smarty +
Hello, {$user->name}.
+``` + +```smarty +
Hello, {$user->getName()}.
+``` + +*Note* +Be careful, Fenom do not checks existence of the method before invoke. +To avoid the problem class of the object have to define method `__call`, which throws an exception etc. +Also you may disable invoke method in [settings](./docs/settings.md). + +Multidimensional value support + +```smarty +{$foo.bar.baz} +{$foo.$bar.$baz} +{$foo[4].baz} +{$foo[4].$baz} +{$foo.bar.baz[4]} +{$foo[ $bar.baz ]} +``` ```smarty {$foo} @@ -25,7 +75,7 @@ Fenom implement [Smarty](http://www.smarty.net/) syntax with some improvements ### System variable -Unnamed system variable starts with `$.` and allow access to global variables and system info (fix doc): +Unnamed system variable starts with `$.` and allows access to global variables and system info (fix doc): * `$.get` is `$_GET`. * `$.post` is `$_POST`. @@ -47,17 +97,6 @@ Unnamed system variable starts with `$.` and allow access to global variables an {/if} ``` -### Multidimensional value support - -```smarty -{$foo.bar.baz} -{$foo.$bar.$baz} -{$foo[4].baz} -{$foo[4].$baz} -{$foo.bar.baz[4]} -{$foo[ $bar.baz ]} -``` - ### Math operations ```smarty diff --git a/docs/usage.md b/docs/usage.md deleted file mode 100644 index e008084..0000000 --- a/docs/usage.md +++ /dev/null @@ -1,38 +0,0 @@ -Basic usage -=========== - -### Initialize Fenom - -Creating an object via factory method -```php -$fenom = Fenom::factory('/path/to/templates', '/path/to/compiled/template', $options); -``` - -Creating an object via `new` operator -```php -$fenom = new Fenom(new Provider('/path/to/templates')); -$fenom->setCompileDir('/path/to/template/cache'); -$fenom->setOptions($options); -``` - -### Rendering template - -Output template -```php -$fenom->display("template/name.tpl", $vars); -``` - -Get the result of rendering the template -```php -$result = $fenom->fetch("template/name.tpl", $vars); -``` - -Create the pipeline of rendering into callback -```php -$fenom->pipe( - "template/sitemap.tpl", - $vars, - $callback = [new SplFileObject("/tmp/sitemap.xml", "w"), "fwrite"], // pipe to file /tmp/sitemap.xml - $chunk_size = 1e6 // chunk size for callback -); -``` diff --git a/src/Fenom.php b/src/Fenom.php index 6c5929d..5f3b78a 100644 --- a/src/Fenom.php +++ b/src/Fenom.php @@ -35,11 +35,8 @@ class Fenom const DISABLE_CACHE = 0x400; const FORCE_VERIFY = 0x800; const AUTO_TRIM = 0x1000; // reserved - const DENY_STATICS = 0x2000; - const AUTO_STRIP = 0x4000; - - /* @deprecated */ - const DENY_INLINE_FUNCS = 0x20; + const DENY_STATICS = 0x2000; + const AUTO_STRIP = 0x4000; /* Default parsers */ const DEFAULT_CLOSE_COMPILER = 'Fenom\Compiler::stdClose'; @@ -66,6 +63,7 @@ class Fenom "force_verify" => self::FORCE_VERIFY, "auto_trim" => self::AUTO_TRIM, "disable_statics" => self::DENY_STATICS, + "strip" => self::AUTO_STRIP, ); /** @@ -265,10 +263,20 @@ class Fenom 'type' => self::INLINE_COMPILER, 'parser' => 'Fenom\Compiler::tagRaw' ), - 'autoescape' => array( + 'autoescape' => array( // deprecated 'type' => self::BLOCK_COMPILER, - 'open' => 'Fenom\Compiler::autoescapeOpen', - 'close' => 'Fenom\Compiler::autoescapeClose' + 'open' => 'Fenom\Compiler::escapeOpen', + 'close' => 'Fenom\Compiler::nope' + ), + 'escape' => array( + 'type' => self::BLOCK_COMPILER, + 'open' => 'Fenom\Compiler::escapeOpen', + 'close' => 'Fenom\Compiler::nope' + ), + 'strip' => array( + 'type' => self::BLOCK_COMPILER, + 'open' => 'Fenom\Compiler::stripOpen', + 'close' => 'Fenom\Compiler::nope' ) ); @@ -988,7 +996,7 @@ class Fenom } /** - * Register PSR-0 autoload for Fenom + * Register PSR-0 autoload * @param string $dir custom directory for autoloading, if NULL — autoload itself * @return bool */ diff --git a/src/Fenom/Compiler.php b/src/Fenom/Compiler.php index 2c5486c..91c987a 100644 --- a/src/Fenom/Compiler.php +++ b/src/Fenom/Compiler.php @@ -962,7 +962,7 @@ class Compiler * @param Tokenizer $tokens * @param Tag $tag */ - public static function autoescapeOpen(Tokenizer $tokens, Tag $tag) + public static function escapeOpen(Tokenizer $tokens, Tag $tag) { $expected = ($tokens->get(T_STRING) == "true" ? true : false); $tokens->next(); @@ -970,11 +970,20 @@ class Compiler } /** - * @param Tokenizer $tokens - * @param Tag $tag + * Do nothing */ - public static function autoescapeClose(Tokenizer $tokens, Tag $tag) + public static function nope() { } + /** + * @param Tokenizer $tokens + * @param Tag $tag + */ + public static function stripOpen(Tokenizer $tokens, Tag $tag) + { + $expected = ($tokens->get(T_STRING) == "true" ? true : false); + $tokens->next(); + $tag->setOption(\Fenom::AUTO_STRIP, $expected); + } } diff --git a/src/Fenom/Modifier.php b/src/Fenom/Modifier.php index 4646ba3..22f326a 100644 --- a/src/Fenom/Modifier.php +++ b/src/Fenom/Modifier.php @@ -140,7 +140,7 @@ class Modifier { $str = trim($str); if ($to_line) { - return preg_replace('#[\s]+#ms', ' ', $str); + return preg_replace('#\s+#ms', ' ', $str); } else { return preg_replace('#[ \t]{2,}#', ' ', $str); } @@ -158,7 +158,7 @@ class Modifier } elseif (is_array($item)) { return count($item); } elseif ($item instanceof \Countable) { - return count($item); + return $item->count(); } else { return 0; } diff --git a/src/Fenom/Tag.php b/src/Fenom/Tag.php index 5bdde33..e71ffdd 100644 --- a/src/Fenom/Tag.php +++ b/src/Fenom/Tag.php @@ -263,13 +263,27 @@ class Tag extends \ArrayObject return $this->tpl->out($code, $this->escape); } + /** + * Enable escape option for the tag + */ public function optEscape() { $this->escape = true; } + /** + * Disable escape option for the tag + */ public function optRaw() { $this->escape = false; } + + /** + * Enable strip spaces option for the tag + */ + public function optStrip() + { + $this->setOption(\Fenom::AUTO_STRIP, true); + } } \ No newline at end of file diff --git a/src/Fenom/Template.php b/src/Fenom/Template.php index b76dd57..ed6d805 100644 --- a/src/Fenom/Template.php +++ b/src/Fenom/Template.php @@ -344,7 +344,6 @@ class Template extends Render foreach ($this->_filters as $filter) { $text = call_user_func($filter, $this, $text); } - $this->_body .= $text; } else { $fragments = explode("_body .= implode('', $fragments); + $text = implode('', $fragments); } } else { - $this->_body .= str_replace("' . PHP_EOL, $text); + $text = str_replace("' . PHP_EOL, $text); } + if($this->_options & Fenom::AUTO_STRIP) { + $text = preg_replace('/\s+/uS', ' ', $text); + $text = preg_replace('/\s*([\pP\pS]+)\s*/uS', '$1', $text); + } + $this->_body .= $text; } /** diff --git a/tests/TestCase.php b/tests/TestCase.php index a7f86f7..da390e7 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -11,18 +11,7 @@ class TestCase extends \PHPUnit_Framework_TestCase */ public $fenom; - public $values = array( - "zero" => 0, - "one" => 1, - "two" => 2, - "three" => 3, - "float" => 4.5, - "bool" => true, - 0 => "empty value", - 1 => "one value", - 2 => "two value", - 3 => "three value", - ); + public $values; public static function getVars() { @@ -40,6 +29,12 @@ class TestCase extends \PHPUnit_Framework_TestCase "b" => 2, "two" => 2 ), + "num" => array( + 1 => "one", + 2 => "two", + 3 => "three", + 4 => "four" + ), 0 => "empty value", 1 => "one value", 2 => "two value", @@ -62,6 +57,7 @@ class TestCase extends \PHPUnit_Framework_TestCase $this->fenom->addModifier('append', __CLASS__ . '::append'); $this->fenom->addFunction('test_function', __CLASS__ . '::inlineFunction'); $this->fenom->addBlockFunction('test_block_function', __CLASS__ . '::blockFunction'); + $this->values = $this->getVars(); } public static function dots($value) diff --git a/tests/cases/Fenom/TemplateTest.php b/tests/cases/Fenom/TemplateTest.php index 8391480..86da05f 100644 --- a/tests/cases/Fenom/TemplateTest.php +++ b/tests/cases/Fenom/TemplateTest.php @@ -185,7 +185,7 @@ class TemplateTest extends TestCase 'Mod: {$lorem|str_rot13}!', 'Fenom\Error\CompileException', "Modifier str_rot13 not found", - Fenom::DENY_INLINE_FUNCS + Fenom::DENY_NATIVE_FUNCS ), array('Mod: {$lorem|my_encode}!', 'Fenom\Error\CompileException', "Modifier my_encode not found"), array('Mod: {$lorem|truncate:}!', 'Fenom\Error\CompileException', "Unexpected end of expression"), diff --git a/tests/cases/FenomTest.php b/tests/cases/FenomTest.php index 351bed9..e3aac2f 100644 --- a/tests/cases/FenomTest.php +++ b/tests/cases/FenomTest.php @@ -13,7 +13,8 @@ class FenomTest extends \Fenom\TestCase array("auto_reload", Fenom::AUTO_RELOAD), array("force_include", Fenom::FORCE_INCLUDE), array("auto_escape", Fenom::AUTO_ESCAPE), - array("force_verify", Fenom::FORCE_VERIFY) + array("force_verify", Fenom::FORCE_VERIFY), + array("strip", Fenom::AUTO_STRIP), ); } @@ -289,6 +290,19 @@ class FenomTest extends \Fenom\TestCase ); $this->assertSame(3, $iteration); } + + /** + * @group strip + */ + public function testStrip() { + $this->fenom->setOptions(Fenom::AUTO_STRIP); + $tpl = << + number {\$num.1} + +TPL; + $this->assertRender($tpl, ''); + } }