Version Description
/ 23.02.2021 = * Security Fixes
Download this release
Release Info
Developer | supsystic.com |
Plugin | Contact Form by Supsystic |
Version | 1.7.12 |
Comparing to | |
See all releases |
Code changes from version 1.7.8 to 1.7.12
- assets/forms/img/bg/2016_ht_1_bg.jpg +0 -0
- assets/forms/img/bg/bg_support_form.jpg +0 -0
- assets/forms/img/bg/scf-red-background.png +0 -0
- assets/forms/img/bg/tea-time.jpg +0 -0
- assets/forms/img/bg/tea-time.png +0 -0
- assets/forms/img/images/2016_ht_1_crist_wrench.png +0 -0
- assets/forms/img/images/2016_ht_1_santa.png +0 -0
- assets/forms/img/images/2016_ht_1_snow1.png +0 -0
- assets/forms/img/images/2016_ht_1_snow2.png +0 -0
- assets/forms/img/images/2016_ht_1_snow3.png +0 -0
- assets/forms/img/images/facebook-icon.png +0 -0
- assets/forms/img/images/google-plus-icon.png +0 -0
- assets/forms/img/images/paper-plane.png +0 -0
- assets/forms/img/images/scf-top-img-snow-1.png +0 -0
- assets/forms/img/images/scf-top-img-snow-2.png +0 -0
- assets/forms/img/images/support_image.png +0 -0
- assets/forms/img/images/twitter-icon.png +0 -0
- assets/forms/img/preview/141-merry-cristmas-prev.png +0 -0
- assets/forms/img/preview/Ho-ho-ho-template-prev.png +0 -0
- assets/forms/img/preview/base-contact.jpg +0 -0
- assets/forms/img/preview/intransigent.jpg +0 -0
- assets/forms/img/preview/kiwifruit.png +0 -0
- assets/forms/img/preview/light-grey.png +0 -0
- assets/forms/img/preview/neon.jpg +0 -0
- assets/forms/img/preview/opacity-grey.png +0 -0
- assets/forms/img/preview/simple-white.png +0 -0
- assets/forms/img/preview/tea-time.png +0 -0
- assets/forms/promo/img/AB-testing-pro.jpg +0 -0
- assets/forms/promo/img/fb-subscribe.jpg +0 -0
- assets/forms/promo/img/logic.png +0 -0
- assets/forms/promo/img/subscribe.png +0 -0
- assets/forms/promo/rating-stats.png +0 -0
- cfs.php +61 -60
- classes/Twig/Autoloader.php +48 -48
- classes/Twig/Compiler.php +270 -270
- classes/Twig/CompilerInterface.php +36 -36
- classes/Twig/Environment.php +1254 -1254
- classes/Twig/Error.php +248 -248
- classes/Twig/Error/Loader.php +31 -31
- classes/Twig/Error/Runtime.php +20 -20
- classes/Twig/Error/Syntax.php +20 -20
- classes/Twig/ExistsLoaderInterface.php +29 -29
- classes/Twig/ExpressionParser.php +598 -598
- classes/Twig/Extension.php +93 -93
- classes/Twig/Extension/Core.php +1462 -1462
- classes/Twig/Extension/Debug.php +71 -71
- classes/Twig/Extension/Escaper.php +107 -107
- classes/Twig/Extension/Optimizer.php +35 -35
- classes/Twig/Extension/Sandbox.php +112 -112
- classes/Twig/Extension/Staging.php +113 -113
- classes/Twig/Extension/StringLoader.php +64 -64
- classes/Twig/ExtensionInterface.php +83 -83
- classes/Twig/Filter.php +81 -81
- classes/Twig/Filter/Function.php +37 -37
- classes/Twig/Filter/Method.php +39 -39
- classes/Twig/Filter/Node.php +39 -39
- classes/Twig/FilterCallableInterface.php +23 -23
- classes/Twig/FilterInterface.php +42 -42
- classes/Twig/Function.php +71 -71
- classes/Twig/Function/Function.php +38 -38
- classes/Twig/Function/Method.php +40 -40
- classes/Twig/Function/Node.php +39 -39
- classes/Twig/FunctionCallableInterface.php +23 -23
- classes/Twig/FunctionInterface.php +39 -39
- classes/Twig/Lexer.php +409 -409
- classes/Twig/LexerInterface.php +32 -32
- classes/Twig/Loader/Array.php +95 -95
- classes/Twig/Loader/Chain.php +138 -138
- classes/Twig/Loader/Filesystem.php +236 -236
- classes/Twig/Loader/String.php +59 -59
- classes/Twig/LoaderInterface.php +52 -52
- classes/Twig/Markup.php +37 -37
- classes/Twig/Node.php +226 -226
- classes/Twig/Node/AutoEscape.php +39 -39
- classes/Twig/Node/Block.php +44 -44
- classes/Twig/Node/BlockReference.php +37 -37
- classes/Twig/Node/Body.php +19 -19
- classes/Twig/Node/Do.php +38 -38
- classes/Twig/Node/Embed.php +38 -38
- classes/Twig/Node/Expression.php +20 -20
- classes/Twig/Node/Expression/Array.php +86 -86
- classes/Twig/Node/Expression/AssignName.php +28 -28
- classes/Twig/Node/Expression/Binary.php +40 -40
- classes/Twig/Node/Expression/Binary/Add.php +18 -18
- classes/Twig/Node/Expression/Binary/And.php +18 -18
- classes/Twig/Node/Expression/Binary/BitwiseAnd.php +18 -18
- classes/Twig/Node/Expression/Binary/BitwiseOr.php +18 -18
- classes/Twig/Node/Expression/Binary/BitwiseXor.php +18 -18
- classes/Twig/Node/Expression/Binary/Concat.php +18 -18
- classes/Twig/Node/Expression/Binary/Div.php +18 -18
- classes/Twig/Node/Expression/Binary/EndsWith.php +30 -30
- classes/Twig/Node/Expression/Binary/Equal.php +17 -17
- classes/Twig/Node/Expression/Binary/FloorDiv.php +29 -29
- classes/Twig/Node/Expression/Binary/Greater.php +17 -17
- classes/Twig/Node/Expression/Binary/GreaterEqual.php +17 -17
- classes/Twig/Node/Expression/Binary/In.php +33 -33
- classes/Twig/Node/Expression/Binary/Less.php +17 -17
- classes/Twig/Node/Expression/Binary/LessEqual.php +17 -17
- classes/Twig/Node/Expression/Binary/Matches.php +28 -28
- classes/Twig/Node/Expression/Binary/Mod.php +18 -18
- classes/Twig/Node/Expression/Binary/Mul.php +18 -18
- classes/Twig/Node/Expression/Binary/NotEqual.php +17 -17
- classes/Twig/Node/Expression/Binary/NotIn.php +33 -33
- classes/Twig/Node/Expression/Binary/Or.php +18 -18
- classes/Twig/Node/Expression/Binary/Power.php +33 -33
- classes/Twig/Node/Expression/Binary/Range.php +33 -33
- classes/Twig/Node/Expression/Binary/StartsWith.php +28 -28
- classes/Twig/Node/Expression/Binary/Sub.php +18 -18
- classes/Twig/Node/Expression/BlockReference.php +51 -51
- classes/Twig/Node/Expression/Call.php +176 -176
- classes/Twig/Node/Expression/Conditional.php +31 -31
- classes/Twig/Node/Expression/Constant.php +23 -23
- classes/Twig/Node/Expression/ExtensionReference.php +33 -33
- classes/Twig/Node/Expression/Filter.php +36 -36
- classes/Twig/Node/Expression/Filter/Default.php +43 -43
- classes/Twig/Node/Expression/Function.php +35 -35
- classes/Twig/Node/Expression/GetAttr.php +53 -53
- classes/Twig/Node/Expression/MethodCall.php +41 -41
- classes/Twig/Node/Expression/Name.php +88 -88
- classes/Twig/Node/Expression/Parent.php +47 -47
- classes/Twig/Node/Expression/TempName.php +26 -26
- classes/Twig/Node/Expression/Test.php +32 -32
- classes/Twig/Node/Expression/Test/Constant.php +46 -46
- classes/Twig/Node/Expression/Test/Defined.php +54 -54
- classes/Twig/Node/Expression/Test/Divisibleby.php +33 -33
- classes/Twig/Node/Expression/Test/Even.php +32 -32
- classes/Twig/Node/Expression/Test/Null.php +31 -31
- classes/Twig/Node/Expression/Test/Odd.php +32 -32
- classes/Twig/Node/Expression/Test/Sameas.php +29 -29
- classes/Twig/Node/Expression/Unary.php +30 -30
- classes/Twig/Node/Expression/Unary/Neg.php +18 -18
- classes/Twig/Node/Expression/Unary/Not.php +18 -18
- classes/Twig/Node/Expression/Unary/Pos.php +18 -18
- classes/Twig/Node/Flush.php +36 -36
- classes/Twig/Node/For.php +112 -112
- classes/Twig/Node/ForLoop.php +55 -55
- classes/Twig/Node/If.php +66 -66
- classes/Twig/Node/Import.php +50 -50
- classes/Twig/Node/Include.php +99 -99
- classes/Twig/Node/Macro.php +96 -96
- classes/Twig/Node/Module.php +383 -383
- classes/Twig/Node/Print.php +39 -39
- classes/Twig/Node/Sandbox.php +47 -47
- classes/Twig/Node/SandboxedModule.php +60 -60
- classes/Twig/Node/SandboxedPrint.php +59 -59
- classes/Twig/Node/Set.php +101 -101
- classes/Twig/Node/SetTemp.php +35 -35
- classes/Twig/Node/Spaceless.php +40 -40
- classes/Twig/Node/Text.php +39 -39
- classes/Twig/NodeInterface.php +31 -31
- classes/Twig/NodeOutputInterface.php +19 -19
- classes/Twig/NodeTraverser.php +88 -88
- classes/Twig/NodeVisitor/Escaper.php +167 -167
- classes/Twig/NodeVisitor/Optimizer.php +246 -246
- classes/Twig/NodeVisitor/SafeAnalysis.php +139 -139
- classes/Twig/NodeVisitor/Sandbox.php +92 -92
- classes/Twig/NodeVisitorInterface.php +47 -47
- classes/Twig/Parser.php +390 -390
- classes/Twig/ParserInterface.php +31 -31
- classes/Twig/Sandbox/SecurityError.php +19 -19
- classes/Twig/Sandbox/SecurityPolicy.php +119 -119
- classes/Twig/Sandbox/SecurityPolicyInterface.php +24 -24
- classes/Twig/SimpleFilter.php +94 -94
- classes/Twig/SimpleFunction.php +84 -84
- classes/Twig/SimpleTest.php +46 -46
- classes/Twig/Template.php +485 -485
- classes/Twig/TemplateInterface.php +48 -48
- classes/Twig/Test.php +34 -34
- classes/Twig/TestCallableInterface.php +21 -21
- classes/Twig/TestInterface.php +26 -26
- classes/Twig/Token.php +216 -216
- classes/Twig/TokenParser.php +33 -33
- classes/Twig/TokenParser/AutoEscape.php +89 -89
- classes/Twig/TokenParser/Block.php +81 -81
- classes/Twig/TokenParser/Do.php +42 -42
- classes/Twig/TokenParser/Embed.php +66 -66
- classes/Twig/TokenParser/Extends.php +52 -52
- classes/Twig/TokenParser/Filter.php +61 -61
- classes/Twig/TokenParser/Flush.php +42 -42
- classes/Twig/TokenParser/For.php +135 -135
- classes/Twig/TokenParser/From.php +70 -70
- classes/Twig/TokenParser/If.php +94 -94
- classes/Twig/TokenParser/Import.php +49 -49
- classes/Twig/TokenParser/Include.php +75 -75
- classes/Twig/TokenParser/Macro.php +68 -68
- classes/Twig/TokenParser/Sandbox.php +68 -68
- classes/Twig/TokenParser/Set.php +83 -83
- classes/Twig/TokenParser/Spaceless.php +59 -59
- classes/Twig/TokenParser/Use.php +76 -76
- classes/Twig/TokenParserBroker.php +136 -136
- classes/Twig/TokenParserBrokerInterface.php +45 -45
- classes/Twig/TokenParserInterface.php +43 -43
- classes/Twig/TokenStream.php +156 -156
- classes/baseObject.php +22 -22
- classes/controller.php +232 -234
- classes/csvgenerator.php +38 -38
- classes/date.php +8 -8
- classes/db.php +154 -141
- classes/dispatcher.php +41 -41
- classes/errors.php +93 -93
- classes/field.php +518 -518
- classes/fieldAdapter.php +315 -310
- classes/filegenerator.php +52 -52
- classes/fileuploader.php +147 -142
- classes/frame.php +374 -500
assets/forms/img/bg/2016_ht_1_bg.jpg
ADDED
Binary file
|
assets/forms/img/bg/bg_support_form.jpg
ADDED
Binary file
|
assets/forms/img/bg/scf-red-background.png
ADDED
Binary file
|
assets/forms/img/bg/tea-time.jpg
ADDED
Binary file
|
assets/forms/img/bg/tea-time.png
ADDED
Binary file
|
assets/forms/img/images/2016_ht_1_crist_wrench.png
ADDED
Binary file
|
assets/forms/img/images/2016_ht_1_santa.png
ADDED
Binary file
|
assets/forms/img/images/2016_ht_1_snow1.png
ADDED
Binary file
|
assets/forms/img/images/2016_ht_1_snow2.png
ADDED
Binary file
|
assets/forms/img/images/2016_ht_1_snow3.png
ADDED
Binary file
|
assets/forms/img/images/facebook-icon.png
ADDED
Binary file
|
assets/forms/img/images/google-plus-icon.png
ADDED
Binary file
|
assets/forms/img/images/paper-plane.png
ADDED
Binary file
|
assets/forms/img/images/scf-top-img-snow-1.png
ADDED
Binary file
|
assets/forms/img/images/scf-top-img-snow-2.png
ADDED
Binary file
|
assets/forms/img/images/support_image.png
ADDED
Binary file
|
assets/forms/img/images/twitter-icon.png
ADDED
Binary file
|
assets/forms/img/preview/141-merry-cristmas-prev.png
ADDED
Binary file
|
assets/forms/img/preview/Ho-ho-ho-template-prev.png
ADDED
Binary file
|
assets/forms/img/preview/base-contact.jpg
ADDED
Binary file
|
assets/forms/img/preview/intransigent.jpg
ADDED
Binary file
|
assets/forms/img/preview/kiwifruit.png
ADDED
Binary file
|
assets/forms/img/preview/light-grey.png
ADDED
Binary file
|
assets/forms/img/preview/neon.jpg
ADDED
Binary file
|
assets/forms/img/preview/opacity-grey.png
ADDED
Binary file
|
assets/forms/img/preview/simple-white.png
ADDED
Binary file
|
assets/forms/img/preview/tea-time.png
ADDED
Binary file
|
assets/forms/promo/img/AB-testing-pro.jpg
ADDED
Binary file
|
assets/forms/promo/img/fb-subscribe.jpg
ADDED
Binary file
|
assets/forms/promo/img/logic.png
ADDED
Binary file
|
assets/forms/promo/img/subscribe.png
ADDED
Binary file
|
assets/forms/promo/rating-stats.png
ADDED
Binary file
|
cfs.php
CHANGED
@@ -1,60 +1,61 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* Plugin Name: Contact Form by Supsystic
|
4 |
-
* Description: Contact Form Builder with drag-and-drop editor to create responsive, mobile ready contact forms in a second. Custom fields and contact form templates
|
5 |
-
* Version: 1.7.
|
6 |
-
* Author: supsystic.com
|
7 |
-
* Author URI: https://supsystic.com
|
8 |
-
* Text Domain: contact-form-by-supsystic
|
9 |
-
* Domain Path: /languages
|
10 |
-
**/
|
11 |
-
/**
|
12 |
-
* Base config constants and functions
|
13 |
-
*/
|
14 |
-
require_once(dirname(__FILE__). DIRECTORY_SEPARATOR. 'config.php');
|
15 |
-
require_once(dirname(__FILE__). DIRECTORY_SEPARATOR. 'functions.php');
|
16 |
-
/**
|
17 |
-
* Connect all required core classes
|
18 |
-
*/
|
19 |
-
|
20 |
-
importClassCfs('
|
21 |
-
importClassCfs('
|
22 |
-
importClassCfs('
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
importClassCfs('
|
28 |
-
importClassCfs('
|
29 |
-
importClassCfs('
|
30 |
-
importClassCfs('
|
31 |
-
importClassCfs('
|
32 |
-
importClassCfs('
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
importClassCfs('
|
38 |
-
importClassCfs('
|
39 |
-
importClassCfs('
|
40 |
-
importClassCfs('
|
41 |
-
importClassCfs('
|
42 |
-
importClassCfs('
|
43 |
-
importClassCfs('
|
44 |
-
importClassCfs('
|
45 |
-
importClassCfs('
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
frameCfs::_()->
|
58 |
-
frameCfs::_()->
|
59 |
-
|
60 |
-
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Plugin Name: Contact Form by Supsystic
|
4 |
+
* Description: Contact Form Builder with drag-and-drop editor to create responsive, mobile ready contact forms in a second. Custom fields and contact form templates
|
5 |
+
* Version: 1.7.12
|
6 |
+
* Author: supsystic.com
|
7 |
+
* Author URI: https://supsystic.com
|
8 |
+
* Text Domain: contact-form-by-supsystic
|
9 |
+
* Domain Path: /languages
|
10 |
+
**/
|
11 |
+
/**
|
12 |
+
* Base config constants and functions
|
13 |
+
*/
|
14 |
+
require_once(dirname(__FILE__). DIRECTORY_SEPARATOR. 'config.php');
|
15 |
+
require_once(dirname(__FILE__). DIRECTORY_SEPARATOR. 'functions.php');
|
16 |
+
/**
|
17 |
+
* Connect all required core classes
|
18 |
+
*/
|
19 |
+
importSqlParser();
|
20 |
+
importClassCfs('dbCfs');
|
21 |
+
importClassCfs('installerCfs');
|
22 |
+
importClassCfs('baseObjectCfs');
|
23 |
+
importClassCfs('moduleCfs');
|
24 |
+
importClassCfs('moduleWidgetCfs');
|
25 |
+
importClassCfs('modelCfs');
|
26 |
+
importClassCfs('modelSubscribeCfs');
|
27 |
+
importClassCfs('viewCfs');
|
28 |
+
importClassCfs('controllerCfs');
|
29 |
+
importClassCfs('helperCfs');
|
30 |
+
importClassCfs('dispatcherCfs');
|
31 |
+
importClassCfs('fieldCfs');
|
32 |
+
importClassCfs('tableCfs');
|
33 |
+
importClassCfs('frameCfs');
|
34 |
+
/**
|
35 |
+
* @deprecated since version 1.0.1
|
36 |
+
*/
|
37 |
+
importClassCfs('langCfs');
|
38 |
+
importClassCfs('reqCfs');
|
39 |
+
importClassCfs('uriCfs');
|
40 |
+
importClassCfs('htmlCfs');
|
41 |
+
importClassCfs('responseCfs');
|
42 |
+
importClassCfs('fieldAdapterCfs');
|
43 |
+
importClassCfs('validatorCfs');
|
44 |
+
importClassCfs('errorsCfs');
|
45 |
+
importClassCfs('utilsCfs');
|
46 |
+
importClassCfs('modInstallerCfs');
|
47 |
+
importClassCfs('installerDbUpdaterCfs');
|
48 |
+
importClassCfs('dateCfs');
|
49 |
+
/**
|
50 |
+
* Check plugin version - maybe we need to update database, and check global errors in request
|
51 |
+
*/
|
52 |
+
installerCfs::update();
|
53 |
+
errorsCfs::init();
|
54 |
+
/**
|
55 |
+
* Start application
|
56 |
+
*/
|
57 |
+
frameCfs::_()->parseRoute();
|
58 |
+
frameCfs::_()->init();
|
59 |
+
frameCfs::_()->exec();
|
60 |
+
|
61 |
+
//var_dump(frameCfs::_()->getActivationErrors()); exit();
|
classes/Twig/Autoloader.php
CHANGED
@@ -1,48 +1,48 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2009 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
/**
|
13 |
-
* Autoloads Twig classes.
|
14 |
-
*
|
15 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
16 |
-
*/
|
17 |
-
class Twig_Autoloader
|
18 |
-
{
|
19 |
-
/**
|
20 |
-
* Registers Twig_Autoloader as an SPL autoloader.
|
21 |
-
*
|
22 |
-
* @param bool $prepend Whether to prepend the autoloader or not.
|
23 |
-
*/
|
24 |
-
public static function register($prepend = false)
|
25 |
-
{
|
26 |
-
if (version_compare(phpversion(), '5.3.0', '>=')) {
|
27 |
-
spl_autoload_register(array(__CLASS__, 'autoload'), true, $prepend);
|
28 |
-
} else {
|
29 |
-
spl_autoload_register(array(__CLASS__, 'autoload'));
|
30 |
-
}
|
31 |
-
}
|
32 |
-
|
33 |
-
/**
|
34 |
-
* Handles autoloading of classes.
|
35 |
-
*
|
36 |
-
* @param string $class A class name.
|
37 |
-
*/
|
38 |
-
public static function autoload($class)
|
39 |
-
{
|
40 |
-
if (0 !== strpos($class, 'Twig')) {
|
41 |
-
return;
|
42 |
-
}
|
43 |
-
|
44 |
-
if (is_file($file = dirname(__FILE__).'/../'.str_replace(array('_', "\0"), array('/', ''), $class).'.php')) {
|
45 |
-
require $file;
|
46 |
-
}
|
47 |
-
}
|
48 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2009 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Autoloads Twig classes.
|
14 |
+
*
|
15 |
+
* @author Fabien Potencier <fabien@symfony.com>
|
16 |
+
*/
|
17 |
+
class Twig_Autoloader
|
18 |
+
{
|
19 |
+
/**
|
20 |
+
* Registers Twig_Autoloader as an SPL autoloader.
|
21 |
+
*
|
22 |
+
* @param bool $prepend Whether to prepend the autoloader or not.
|
23 |
+
*/
|
24 |
+
public static function register($prepend = false)
|
25 |
+
{
|
26 |
+
if (version_compare(phpversion(), '5.3.0', '>=')) {
|
27 |
+
spl_autoload_register(array(__CLASS__, 'autoload'), true, $prepend);
|
28 |
+
} else {
|
29 |
+
spl_autoload_register(array(__CLASS__, 'autoload'));
|
30 |
+
}
|
31 |
+
}
|
32 |
+
|
33 |
+
/**
|
34 |
+
* Handles autoloading of classes.
|
35 |
+
*
|
36 |
+
* @param string $class A class name.
|
37 |
+
*/
|
38 |
+
public static function autoload($class)
|
39 |
+
{
|
40 |
+
if (0 !== strpos($class, 'Twig')) {
|
41 |
+
return;
|
42 |
+
}
|
43 |
+
|
44 |
+
if (is_file($file = dirname(__FILE__).'/../'.str_replace(array('_', "\0"), array('/', ''), $class).'.php')) {
|
45 |
+
require $file;
|
46 |
+
}
|
47 |
+
}
|
48 |
+
}
|
classes/Twig/Compiler.php
CHANGED
@@ -1,270 +1,270 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2009 Fabien Potencier
|
7 |
-
* (c) 2009 Armin Ronacher
|
8 |
-
*
|
9 |
-
* For the full copyright and license information, please view the LICENSE
|
10 |
-
* file that was distributed with this source code.
|
11 |
-
*/
|
12 |
-
|
13 |
-
/**
|
14 |
-
* Compiles a node to PHP code.
|
15 |
-
*
|
16 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
17 |
-
*/
|
18 |
-
class Twig_Compiler implements Twig_CompilerInterface
|
19 |
-
{
|
20 |
-
protected $lastLine;
|
21 |
-
protected $source;
|
22 |
-
protected $indentation;
|
23 |
-
protected $env;
|
24 |
-
protected $debugInfo;
|
25 |
-
protected $sourceOffset;
|
26 |
-
protected $sourceLine;
|
27 |
-
protected $filename;
|
28 |
-
|
29 |
-
/**
|
30 |
-
* Constructor.
|
31 |
-
*
|
32 |
-
* @param Twig_Environment $env The twig environment instance
|
33 |
-
*/
|
34 |
-
public function __construct(Twig_Environment $env)
|
35 |
-
{
|
36 |
-
$this->env = $env;
|
37 |
-
$this->debugInfo = array();
|
38 |
-
}
|
39 |
-
|
40 |
-
public function getFilename()
|
41 |
-
{
|
42 |
-
return $this->filename;
|
43 |
-
}
|
44 |
-
|
45 |
-
/**
|
46 |
-
* Returns the environment instance related to this compiler.
|
47 |
-
*
|
48 |
-
* @return Twig_Environment The environment instance
|
49 |
-
*/
|
50 |
-
public function getEnvironment()
|
51 |
-
{
|
52 |
-
return $this->env;
|
53 |
-
}
|
54 |
-
|
55 |
-
/**
|
56 |
-
* Gets the current PHP code after compilation.
|
57 |
-
*
|
58 |
-
* @return string The PHP code
|
59 |
-
*/
|
60 |
-
public function getSource()
|
61 |
-
{
|
62 |
-
return $this->source;
|
63 |
-
}
|
64 |
-
|
65 |
-
/**
|
66 |
-
* Compiles a node.
|
67 |
-
*
|
68 |
-
* @param Twig_NodeInterface $node The node to compile
|
69 |
-
* @param int $indentation The current indentation
|
70 |
-
*
|
71 |
-
* @return Twig_Compiler The current compiler instance
|
72 |
-
*/
|
73 |
-
public function compile(Twig_NodeInterface $node, $indentation = 0)
|
74 |
-
{
|
75 |
-
$this->lastLine = null;
|
76 |
-
$this->source = '';
|
77 |
-
$this->sourceOffset = 0;
|
78 |
-
// source code starts at 1 (as we then increment it when we encounter new lines)
|
79 |
-
$this->sourceLine = 1;
|
80 |
-
$this->indentation = $indentation;
|
81 |
-
|
82 |
-
if ($node instanceof Twig_Node_Module) {
|
83 |
-
$this->filename = $node->getAttribute('filename');
|
84 |
-
}
|
85 |
-
|
86 |
-
$node->compile($this);
|
87 |
-
|
88 |
-
return $this;
|
89 |
-
}
|
90 |
-
|
91 |
-
public function subcompile(Twig_NodeInterface $node, $raw = true)
|
92 |
-
{
|
93 |
-
if (false === $raw) {
|
94 |
-
$this->addIndentation();
|
95 |
-
}
|
96 |
-
|
97 |
-
$node->compile($this);
|
98 |
-
|
99 |
-
return $this;
|
100 |
-
}
|
101 |
-
|
102 |
-
/**
|
103 |
-
* Adds a raw string to the compiled code.
|
104 |
-
*
|
105 |
-
* @param string $string The string
|
106 |
-
*
|
107 |
-
* @return Twig_Compiler The current compiler instance
|
108 |
-
*/
|
109 |
-
public function raw($string)
|
110 |
-
{
|
111 |
-
$this->source .= $string;
|
112 |
-
|
113 |
-
return $this;
|
114 |
-
}
|
115 |
-
|
116 |
-
/**
|
117 |
-
* Writes a string to the compiled code by adding indentation.
|
118 |
-
*
|
119 |
-
* @return Twig_Compiler The current compiler instance
|
120 |
-
*/
|
121 |
-
public function write()
|
122 |
-
{
|
123 |
-
$strings = func_get_args();
|
124 |
-
foreach ($strings as $string) {
|
125 |
-
$this->addIndentation();
|
126 |
-
$this->source .= $string;
|
127 |
-
}
|
128 |
-
|
129 |
-
return $this;
|
130 |
-
}
|
131 |
-
|
132 |
-
/**
|
133 |
-
* Appends an indentation to the current PHP code after compilation.
|
134 |
-
*
|
135 |
-
* @return Twig_Compiler The current compiler instance
|
136 |
-
*/
|
137 |
-
public function addIndentation()
|
138 |
-
{
|
139 |
-
$this->source .= str_repeat(' ', $this->indentation * 4);
|
140 |
-
|
141 |
-
return $this;
|
142 |
-
}
|
143 |
-
|
144 |
-
/**
|
145 |
-
* Adds a quoted string to the compiled code.
|
146 |
-
*
|
147 |
-
* @param string $value The string
|
148 |
-
*
|
149 |
-
* @return Twig_Compiler The current compiler instance
|
150 |
-
*/
|
151 |
-
public function string($value)
|
152 |
-
{
|
153 |
-
$this->source .= sprintf('"%s"', addcslashes($value, "\0\t\"\$\\"));
|
154 |
-
|
155 |
-
return $this;
|
156 |
-
}
|
157 |
-
|
158 |
-
/**
|
159 |
-
* Returns a PHP representation of a given value.
|
160 |
-
*
|
161 |
-
* @param mixed $value The value to convert
|
162 |
-
*
|
163 |
-
* @return Twig_Compiler The current compiler instance
|
164 |
-
*/
|
165 |
-
public function repr($value)
|
166 |
-
{
|
167 |
-
if (is_int($value) || is_float($value)) {
|
168 |
-
if (false !== $locale = setlocale(LC_NUMERIC, 0)) {
|
169 |
-
setlocale(LC_NUMERIC, 'C');
|
170 |
-
}
|
171 |
-
|
172 |
-
$this->raw($value);
|
173 |
-
|
174 |
-
if (false !== $locale) {
|
175 |
-
setlocale(LC_NUMERIC, $locale);
|
176 |
-
}
|
177 |
-
} elseif (null === $value) {
|
178 |
-
$this->raw('null');
|
179 |
-
} elseif (is_bool($value)) {
|
180 |
-
$this->raw($value ? 'true' : 'false');
|
181 |
-
} elseif (is_array($value)) {
|
182 |
-
$this->raw('array(');
|
183 |
-
$first = true;
|
184 |
-
foreach ($value as $key => $value) {
|
185 |
-
if (!$first) {
|
186 |
-
$this->raw(', ');
|
187 |
-
}
|
188 |
-
$first = false;
|
189 |
-
$this->repr($key);
|
190 |
-
$this->raw(' => ');
|
191 |
-
$this->repr($value);
|
192 |
-
}
|
193 |
-
$this->raw(')');
|
194 |
-
} else {
|
195 |
-
$this->string($value);
|
196 |
-
}
|
197 |
-
|
198 |
-
return $this;
|
199 |
-
}
|
200 |
-
|
201 |
-
/**
|
202 |
-
* Adds debugging information.
|
203 |
-
*
|
204 |
-
* @param Twig_NodeInterface $node The related twig node
|
205 |
-
*
|
206 |
-
* @return Twig_Compiler The current compiler instance
|
207 |
-
*/
|
208 |
-
public function addDebugInfo(Twig_NodeInterface $node)
|
209 |
-
{
|
210 |
-
if ($node->getLine() != $this->lastLine) {
|
211 |
-
$this->write(sprintf("// line %d\n", $node->getLine()));
|
212 |
-
|
213 |
-
// when mbstring.func_overload is set to 2
|
214 |
-
// mb_substr_count() replaces substr_count()
|
215 |
-
// but they have different signatures!
|
216 |
-
if (((int) ini_get('mbstring.func_overload')) & 2) {
|
217 |
-
// this is much slower than the "right" version
|
218 |
-
$this->sourceLine += mb_substr_count(mb_substr($this->source, $this->sourceOffset), "\n");
|
219 |
-
} else {
|
220 |
-
$this->sourceLine += substr_count($this->source, "\n", $this->sourceOffset);
|
221 |
-
}
|
222 |
-
$this->sourceOffset = strlen($this->source);
|
223 |
-
$this->debugInfo[$this->sourceLine] = $node->getLine();
|
224 |
-
|
225 |
-
$this->lastLine = $node->getLine();
|
226 |
-
}
|
227 |
-
|
228 |
-
return $this;
|
229 |
-
}
|
230 |
-
|
231 |
-
public function getDebugInfo()
|
232 |
-
{
|
233 |
-
return $this->debugInfo;
|
234 |
-
}
|
235 |
-
|
236 |
-
/**
|
237 |
-
* Indents the generated code.
|
238 |
-
*
|
239 |
-
* @param int $step The number of indentation to add
|
240 |
-
*
|
241 |
-
* @return Twig_Compiler The current compiler instance
|
242 |
-
*/
|
243 |
-
public function indent($step = 1)
|
244 |
-
{
|
245 |
-
$this->indentation += $step;
|
246 |
-
|
247 |
-
return $this;
|
248 |
-
}
|
249 |
-
|
250 |
-
/**
|
251 |
-
* Outdents the generated code.
|
252 |
-
*
|
253 |
-
* @param int $step The number of indentation to remove
|
254 |
-
*
|
255 |
-
* @return Twig_Compiler The current compiler instance
|
256 |
-
*
|
257 |
-
* @throws LogicException When trying to outdent too much so the indentation would become negative
|
258 |
-
*/
|
259 |
-
public function outdent($step = 1)
|
260 |
-
{
|
261 |
-
// can't outdent by more steps than the current indentation level
|
262 |
-
if ($this->indentation < $step) {
|
263 |
-
throw new LogicException('Unable to call outdent() as the indentation would become negative');
|
264 |
-
}
|
265 |
-
|
266 |
-
$this->indentation -= $step;
|
267 |
-
|
268 |
-
return $this;
|
269 |
-
}
|
270 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2009 Fabien Potencier
|
7 |
+
* (c) 2009 Armin Ronacher
|
8 |
+
*
|
9 |
+
* For the full copyright and license information, please view the LICENSE
|
10 |
+
* file that was distributed with this source code.
|
11 |
+
*/
|
12 |
+
|
13 |
+
/**
|
14 |
+
* Compiles a node to PHP code.
|
15 |
+
*
|
16 |
+
* @author Fabien Potencier <fabien@symfony.com>
|
17 |
+
*/
|
18 |
+
class Twig_Compiler implements Twig_CompilerInterface
|
19 |
+
{
|
20 |
+
protected $lastLine;
|
21 |
+
protected $source;
|
22 |
+
protected $indentation;
|
23 |
+
protected $env;
|
24 |
+
protected $debugInfo;
|
25 |
+
protected $sourceOffset;
|
26 |
+
protected $sourceLine;
|
27 |
+
protected $filename;
|
28 |
+
|
29 |
+
/**
|
30 |
+
* Constructor.
|
31 |
+
*
|
32 |
+
* @param Twig_Environment $env The twig environment instance
|
33 |
+
*/
|
34 |
+
public function __construct(Twig_Environment $env)
|
35 |
+
{
|
36 |
+
$this->env = $env;
|
37 |
+
$this->debugInfo = array();
|
38 |
+
}
|
39 |
+
|
40 |
+
public function getFilename()
|
41 |
+
{
|
42 |
+
return $this->filename;
|
43 |
+
}
|
44 |
+
|
45 |
+
/**
|
46 |
+
* Returns the environment instance related to this compiler.
|
47 |
+
*
|
48 |
+
* @return Twig_Environment The environment instance
|
49 |
+
*/
|
50 |
+
public function getEnvironment()
|
51 |
+
{
|
52 |
+
return $this->env;
|
53 |
+
}
|
54 |
+
|
55 |
+
/**
|
56 |
+
* Gets the current PHP code after compilation.
|
57 |
+
*
|
58 |
+
* @return string The PHP code
|
59 |
+
*/
|
60 |
+
public function getSource()
|
61 |
+
{
|
62 |
+
return $this->source;
|
63 |
+
}
|
64 |
+
|
65 |
+
/**
|
66 |
+
* Compiles a node.
|
67 |
+
*
|
68 |
+
* @param Twig_NodeInterface $node The node to compile
|
69 |
+
* @param int $indentation The current indentation
|
70 |
+
*
|
71 |
+
* @return Twig_Compiler The current compiler instance
|
72 |
+
*/
|
73 |
+
public function compile(Twig_NodeInterface $node, $indentation = 0)
|
74 |
+
{
|
75 |
+
$this->lastLine = null;
|
76 |
+
$this->source = '';
|
77 |
+
$this->sourceOffset = 0;
|
78 |
+
// source code starts at 1 (as we then increment it when we encounter new lines)
|
79 |
+
$this->sourceLine = 1;
|
80 |
+
$this->indentation = $indentation;
|
81 |
+
|
82 |
+
if ($node instanceof Twig_Node_Module) {
|
83 |
+
$this->filename = $node->getAttribute('filename');
|
84 |
+
}
|
85 |
+
|
86 |
+
$node->compile($this);
|
87 |
+
|
88 |
+
return $this;
|
89 |
+
}
|
90 |
+
|
91 |
+
public function subcompile(Twig_NodeInterface $node, $raw = true)
|
92 |
+
{
|
93 |
+
if (false === $raw) {
|
94 |
+
$this->addIndentation();
|
95 |
+
}
|
96 |
+
|
97 |
+
$node->compile($this);
|
98 |
+
|
99 |
+
return $this;
|
100 |
+
}
|
101 |
+
|
102 |
+
/**
|
103 |
+
* Adds a raw string to the compiled code.
|
104 |
+
*
|
105 |
+
* @param string $string The string
|
106 |
+
*
|
107 |
+
* @return Twig_Compiler The current compiler instance
|
108 |
+
*/
|
109 |
+
public function raw($string)
|
110 |
+
{
|
111 |
+
$this->source .= $string;
|
112 |
+
|
113 |
+
return $this;
|
114 |
+
}
|
115 |
+
|
116 |
+
/**
|
117 |
+
* Writes a string to the compiled code by adding indentation.
|
118 |
+
*
|
119 |
+
* @return Twig_Compiler The current compiler instance
|
120 |
+
*/
|
121 |
+
public function write()
|
122 |
+
{
|
123 |
+
$strings = func_get_args();
|
124 |
+
foreach ($strings as $string) {
|
125 |
+
$this->addIndentation();
|
126 |
+
$this->source .= $string;
|
127 |
+
}
|
128 |
+
|
129 |
+
return $this;
|
130 |
+
}
|
131 |
+
|
132 |
+
/**
|
133 |
+
* Appends an indentation to the current PHP code after compilation.
|
134 |
+
*
|
135 |
+
* @return Twig_Compiler The current compiler instance
|
136 |
+
*/
|
137 |
+
public function addIndentation()
|
138 |
+
{
|
139 |
+
$this->source .= str_repeat(' ', $this->indentation * 4);
|
140 |
+
|
141 |
+
return $this;
|
142 |
+
}
|
143 |
+
|
144 |
+
/**
|
145 |
+
* Adds a quoted string to the compiled code.
|
146 |
+
*
|
147 |
+
* @param string $value The string
|
148 |
+
*
|
149 |
+
* @return Twig_Compiler The current compiler instance
|
150 |
+
*/
|
151 |
+
public function string($value)
|
152 |
+
{
|
153 |
+
$this->source .= sprintf('"%s"', addcslashes($value, "\0\t\"\$\\"));
|
154 |
+
|
155 |
+
return $this;
|
156 |
+
}
|
157 |
+
|
158 |
+
/**
|
159 |
+
* Returns a PHP representation of a given value.
|
160 |
+
*
|
161 |
+
* @param mixed $value The value to convert
|
162 |
+
*
|
163 |
+
* @return Twig_Compiler The current compiler instance
|
164 |
+
*/
|
165 |
+
public function repr($value)
|
166 |
+
{
|
167 |
+
if (is_int($value) || is_float($value)) {
|
168 |
+
if (false !== $locale = setlocale(LC_NUMERIC, 0)) {
|
169 |
+
setlocale(LC_NUMERIC, 'C');
|
170 |
+
}
|
171 |
+
|
172 |
+
$this->raw($value);
|
173 |
+
|
174 |
+
if (false !== $locale) {
|
175 |
+
setlocale(LC_NUMERIC, $locale);
|
176 |
+
}
|
177 |
+
} elseif (null === $value) {
|
178 |
+
$this->raw('null');
|
179 |
+
} elseif (is_bool($value)) {
|
180 |
+
$this->raw($value ? 'true' : 'false');
|
181 |
+
} elseif (is_array($value)) {
|
182 |
+
$this->raw('array(');
|
183 |
+
$first = true;
|
184 |
+
foreach ($value as $key => $value) {
|
185 |
+
if (!$first) {
|
186 |
+
$this->raw(', ');
|
187 |
+
}
|
188 |
+
$first = false;
|
189 |
+
$this->repr($key);
|
190 |
+
$this->raw(' => ');
|
191 |
+
$this->repr($value);
|
192 |
+
}
|
193 |
+
$this->raw(')');
|
194 |
+
} else {
|
195 |
+
$this->string($value);
|
196 |
+
}
|
197 |
+
|
198 |
+
return $this;
|
199 |
+
}
|
200 |
+
|
201 |
+
/**
|
202 |
+
* Adds debugging information.
|
203 |
+
*
|
204 |
+
* @param Twig_NodeInterface $node The related twig node
|
205 |
+
*
|
206 |
+
* @return Twig_Compiler The current compiler instance
|
207 |
+
*/
|
208 |
+
public function addDebugInfo(Twig_NodeInterface $node)
|
209 |
+
{
|
210 |
+
if ($node->getLine() != $this->lastLine) {
|
211 |
+
$this->write(sprintf("// line %d\n", $node->getLine()));
|
212 |
+
|
213 |
+
// when mbstring.func_overload is set to 2
|
214 |
+
// mb_substr_count() replaces substr_count()
|
215 |
+
// but they have different signatures!
|
216 |
+
if (((int) ini_get('mbstring.func_overload')) & 2) {
|
217 |
+
// this is much slower than the "right" version
|
218 |
+
$this->sourceLine += mb_substr_count(mb_substr($this->source, $this->sourceOffset), "\n");
|
219 |
+
} else {
|
220 |
+
$this->sourceLine += substr_count($this->source, "\n", $this->sourceOffset);
|
221 |
+
}
|
222 |
+
$this->sourceOffset = strlen($this->source);
|
223 |
+
$this->debugInfo[$this->sourceLine] = $node->getLine();
|
224 |
+
|
225 |
+
$this->lastLine = $node->getLine();
|
226 |
+
}
|
227 |
+
|
228 |
+
return $this;
|
229 |
+
}
|
230 |
+
|
231 |
+
public function getDebugInfo()
|
232 |
+
{
|
233 |
+
return $this->debugInfo;
|
234 |
+
}
|
235 |
+
|
236 |
+
/**
|
237 |
+
* Indents the generated code.
|
238 |
+
*
|
239 |
+
* @param int $step The number of indentation to add
|
240 |
+
*
|
241 |
+
* @return Twig_Compiler The current compiler instance
|
242 |
+
*/
|
243 |
+
public function indent($step = 1)
|
244 |
+
{
|
245 |
+
$this->indentation += $step;
|
246 |
+
|
247 |
+
return $this;
|
248 |
+
}
|
249 |
+
|
250 |
+
/**
|
251 |
+
* Outdents the generated code.
|
252 |
+
*
|
253 |
+
* @param int $step The number of indentation to remove
|
254 |
+
*
|
255 |
+
* @return Twig_Compiler The current compiler instance
|
256 |
+
*
|
257 |
+
* @throws LogicException When trying to outdent too much so the indentation would become negative
|
258 |
+
*/
|
259 |
+
public function outdent($step = 1)
|
260 |
+
{
|
261 |
+
// can't outdent by more steps than the current indentation level
|
262 |
+
if ($this->indentation < $step) {
|
263 |
+
throw new LogicException('Unable to call outdent() as the indentation would become negative');
|
264 |
+
}
|
265 |
+
|
266 |
+
$this->indentation -= $step;
|
267 |
+
|
268 |
+
return $this;
|
269 |
+
}
|
270 |
+
}
|
classes/Twig/CompilerInterface.php
CHANGED
@@ -1,36 +1,36 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2009 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
/**
|
13 |
-
* Interface implemented by compiler classes.
|
14 |
-
*
|
15 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
16 |
-
*
|
17 |
-
* @deprecated since 1.12 (to be removed in 3.0)
|
18 |
-
*/
|
19 |
-
interface Twig_CompilerInterface
|
20 |
-
{
|
21 |
-
/**
|
22 |
-
* Compiles a node.
|
23 |
-
*
|
24 |
-
* @param Twig_NodeInterface $node The node to compile
|
25 |
-
*
|
26 |
-
* @return Twig_CompilerInterface The current compiler instance
|
27 |
-
*/
|
28 |
-
public function compile(Twig_NodeInterface $node);
|
29 |
-
|
30 |
-
/**
|
31 |
-
* Gets the current PHP code after compilation.
|
32 |
-
*
|
33 |
-
* @return string The PHP code
|
34 |
-
*/
|
35 |
-
public function getSource();
|
36 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2009 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Interface implemented by compiler classes.
|
14 |
+
*
|
15 |
+
* @author Fabien Potencier <fabien@symfony.com>
|
16 |
+
*
|
17 |
+
* @deprecated since 1.12 (to be removed in 3.0)
|
18 |
+
*/
|
19 |
+
interface Twig_CompilerInterface
|
20 |
+
{
|
21 |
+
/**
|
22 |
+
* Compiles a node.
|
23 |
+
*
|
24 |
+
* @param Twig_NodeInterface $node The node to compile
|
25 |
+
*
|
26 |
+
* @return Twig_CompilerInterface The current compiler instance
|
27 |
+
*/
|
28 |
+
public function compile(Twig_NodeInterface $node);
|
29 |
+
|
30 |
+
/**
|
31 |
+
* Gets the current PHP code after compilation.
|
32 |
+
*
|
33 |
+
* @return string The PHP code
|
34 |
+
*/
|
35 |
+
public function getSource();
|
36 |
+
}
|
classes/Twig/Environment.php
CHANGED
@@ -1,1254 +1,1254 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2009 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
/**
|
13 |
-
* Stores the Twig configuration.
|
14 |
-
*
|
15 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
16 |
-
*/
|
17 |
-
class Twig_Environment
|
18 |
-
{
|
19 |
-
const VERSION = '1.16.0';
|
20 |
-
|
21 |
-
protected $charset;
|
22 |
-
protected $loader;
|
23 |
-
protected $debug;
|
24 |
-
protected $autoReload;
|
25 |
-
protected $cache;
|
26 |
-
protected $lexer;
|
27 |
-
protected $parser;
|
28 |
-
protected $compiler;
|
29 |
-
protected $baseTemplateClass;
|
30 |
-
protected $extensions;
|
31 |
-
protected $parsers;
|
32 |
-
protected $visitors;
|
33 |
-
protected $filters;
|
34 |
-
protected $tests;
|
35 |
-
protected $functions;
|
36 |
-
protected $globals;
|
37 |
-
protected $runtimeInitialized;
|
38 |
-
protected $extensionInitialized;
|
39 |
-
protected $loadedTemplates;
|
40 |
-
protected $strictVariables;
|
41 |
-
protected $unaryOperators;
|
42 |
-
protected $binaryOperators;
|
43 |
-
protected $templateClassPrefix = '__TwigTemplate_';
|
44 |
-
protected $functionCallbacks;
|
45 |
-
protected $filterCallbacks;
|
46 |
-
protected $staging;
|
47 |
-
|
48 |
-
/**
|
49 |
-
* Constructor.
|
50 |
-
*
|
51 |
-
* Available options:
|
52 |
-
*
|
53 |
-
* * debug: When set to true, it automatically set "auto_reload" to true as
|
54 |
-
* well (default to false).
|
55 |
-
*
|
56 |
-
* * charset: The charset used by the templates (default to UTF-8).
|
57 |
-
*
|
58 |
-
* * base_template_class: The base template class to use for generated
|
59 |
-
* templates (default to Twig_Template).
|
60 |
-
*
|
61 |
-
* * cache: An absolute path where to store the compiled templates, or
|
62 |
-
* false to disable compilation cache (default).
|
63 |
-
*
|
64 |
-
* * auto_reload: Whether to reload the template if the original source changed.
|
65 |
-
* If you don't provide the auto_reload option, it will be
|
66 |
-
* determined automatically based on the debug value.
|
67 |
-
*
|
68 |
-
* * strict_variables: Whether to ignore invalid variables in templates
|
69 |
-
* (default to false).
|
70 |
-
*
|
71 |
-
* * autoescape: Whether to enable auto-escaping (default to html):
|
72 |
-
* * false: disable auto-escaping
|
73 |
-
* * true: equivalent to html
|
74 |
-
* * html, js: set the autoescaping to one of the supported strategies
|
75 |
-
* * PHP callback: a PHP callback that returns an escaping strategy based on the template "filename"
|
76 |
-
*
|
77 |
-
* * optimizations: A flag that indicates which optimizations to apply
|
78 |
-
* (default to -1 which means that all optimizations are enabled;
|
79 |
-
* set it to 0 to disable).
|
80 |
-
*
|
81 |
-
* @param Twig_LoaderInterface $loader A Twig_LoaderInterface instance
|
82 |
-
* @param array $options An array of options
|
83 |
-
*/
|
84 |
-
public function __construct(Twig_LoaderInterface $loader = null, $options = array())
|
85 |
-
{
|
86 |
-
if (null !== $loader) {
|
87 |
-
$this->setLoader($loader);
|
88 |
-
}
|
89 |
-
|
90 |
-
$options = array_merge(array(
|
91 |
-
'debug' => false,
|
92 |
-
'charset' => 'UTF-8',
|
93 |
-
'base_template_class' => 'Twig_Template',
|
94 |
-
'strict_variables' => false,
|
95 |
-
'autoescape' => 'html',
|
96 |
-
'cache' => false,
|
97 |
-
'auto_reload' => null,
|
98 |
-
'optimizations' => -1,
|
99 |
-
), $options);
|
100 |
-
|
101 |
-
$this->debug = (bool) $options['debug'];
|
102 |
-
$this->charset = strtoupper($options['charset']);
|
103 |
-
$this->baseTemplateClass = $options['base_template_class'];
|
104 |
-
$this->autoReload = null === $options['auto_reload'] ? $this->debug : (bool) $options['auto_reload'];
|
105 |
-
$this->strictVariables = (bool) $options['strict_variables'];
|
106 |
-
$this->runtimeInitialized = false;
|
107 |
-
$this->setCache($options['cache']);
|
108 |
-
$this->functionCallbacks = array();
|
109 |
-
$this->filterCallbacks = array();
|
110 |
-
|
111 |
-
$this->addExtension(new Twig_Extension_Core());
|
112 |
-
$this->addExtension(new Twig_Extension_Escaper($options['autoescape']));
|
113 |
-
$this->addExtension(new Twig_Extension_Optimizer($options['optimizations']));
|
114 |
-
$this->extensionInitialized = false;
|
115 |
-
$this->staging = new Twig_Extension_Staging();
|
116 |
-
}
|
117 |
-
|
118 |
-
/**
|
119 |
-
* Gets the base template class for compiled templates.
|
120 |
-
*
|
121 |
-
* @return string The base template class name
|
122 |
-
*/
|
123 |
-
public function getBaseTemplateClass()
|
124 |
-
{
|
125 |
-
return $this->baseTemplateClass;
|
126 |
-
}
|
127 |
-
|
128 |
-
/**
|
129 |
-
* Sets the base template class for compiled templates.
|
130 |
-
*
|
131 |
-
* @param string $class The base template class name
|
132 |
-
*/
|
133 |
-
public function setBaseTemplateClass($class)
|
134 |
-
{
|
135 |
-
$this->baseTemplateClass = $class;
|
136 |
-
}
|
137 |
-
|
138 |
-
/**
|
139 |
-
* Enables debugging mode.
|
140 |
-
*/
|
141 |
-
public function enableDebug()
|
142 |
-
{
|
143 |
-
$this->debug = true;
|
144 |
-
}
|
145 |
-
|
146 |
-
/**
|
147 |
-
* Disables debugging mode.
|
148 |
-
*/
|
149 |
-
public function disableDebug()
|
150 |
-
{
|
151 |
-
$this->debug = false;
|
152 |
-
}
|
153 |
-
|
154 |
-
/**
|
155 |
-
* Checks if debug mode is enabled.
|
156 |
-
*
|
157 |
-
* @return bool true if debug mode is enabled, false otherwise
|
158 |
-
*/
|
159 |
-
public function isDebug()
|
160 |
-
{
|
161 |
-
return $this->debug;
|
162 |
-
}
|
163 |
-
|
164 |
-
/**
|
165 |
-
* Enables the auto_reload option.
|
166 |
-
*/
|
167 |
-
public function enableAutoReload()
|
168 |
-
{
|
169 |
-
$this->autoReload = true;
|
170 |
-
}
|
171 |
-
|
172 |
-
/**
|
173 |
-
* Disables the auto_reload option.
|
174 |
-
*/
|
175 |
-
public function disableAutoReload()
|
176 |
-
{
|
177 |
-
$this->autoReload = false;
|
178 |
-
}
|
179 |
-
|
180 |
-
/**
|
181 |
-
* Checks if the auto_reload option is enabled.
|
182 |
-
*
|
183 |
-
* @return bool true if auto_reload is enabled, false otherwise
|
184 |
-
*/
|
185 |
-
public function isAutoReload()
|
186 |
-
{
|
187 |
-
return $this->autoReload;
|
188 |
-
}
|
189 |
-
|
190 |
-
/**
|
191 |
-
* Enables the strict_variables option.
|
192 |
-
*/
|
193 |
-
public function enableStrictVariables()
|
194 |
-
{
|
195 |
-
$this->strictVariables = true;
|
196 |
-
}
|
197 |
-
|
198 |
-
/**
|
199 |
-
* Disables the strict_variables option.
|
200 |
-
*/
|
201 |
-
public function disableStrictVariables()
|
202 |
-
{
|
203 |
-
$this->strictVariables = false;
|
204 |
-
}
|
205 |
-
|
206 |
-
/**
|
207 |
-
* Checks if the strict_variables option is enabled.
|
208 |
-
*
|
209 |
-
* @return bool true if strict_variables is enabled, false otherwise
|
210 |
-
*/
|
211 |
-
public function isStrictVariables()
|
212 |
-
{
|
213 |
-
return $this->strictVariables;
|
214 |
-
}
|
215 |
-
|
216 |
-
/**
|
217 |
-
* Gets the cache directory or false if cache is disabled.
|
218 |
-
*
|
219 |
-
* @return string|false
|
220 |
-
*/
|
221 |
-
public function getCache()
|
222 |
-
{
|
223 |
-
return $this->cache;
|
224 |
-
}
|
225 |
-
|
226 |
-
/**
|
227 |
-
* Sets the cache directory or false if cache is disabled.
|
228 |
-
*
|
229 |
-
* @param string|false $cache The absolute path to the compiled templates,
|
230 |
-
* or false to disable cache
|
231 |
-
*/
|
232 |
-
public function setCache($cache)
|
233 |
-
{
|
234 |
-
$this->cache = $cache ? $cache : false;
|
235 |
-
}
|
236 |
-
|
237 |
-
/**
|
238 |
-
* Gets the cache filename for a given template.
|
239 |
-
*
|
240 |
-
* @param string $name The template name
|
241 |
-
*
|
242 |
-
* @return string|false The cache file name or false when caching is disabled
|
243 |
-
*/
|
244 |
-
public function getCacheFilename($name)
|
245 |
-
{
|
246 |
-
if (false === $this->cache) {
|
247 |
-
return false;
|
248 |
-
}
|
249 |
-
|
250 |
-
$class = substr($this->getTemplateClass($name), strlen($this->templateClassPrefix));
|
251 |
-
|
252 |
-
return $this->getCache().'/'.substr($class, 0, 2).'/'.substr($class, 2, 2).'/'.substr($class, 4).'.php';
|
253 |
-
}
|
254 |
-
|
255 |
-
/**
|
256 |
-
* Gets the template class associated with the given string.
|
257 |
-
*
|
258 |
-
* @param string $name The name for which to calculate the template class name
|
259 |
-
* @param int $index The index if it is an embedded template
|
260 |
-
*
|
261 |
-
* @return string The template class name
|
262 |
-
*/
|
263 |
-
public function getTemplateClass($name, $index = null)
|
264 |
-
{
|
265 |
-
return $this->templateClassPrefix.hash('sha256', $this->getLoader()->getCacheKey($name)).(null === $index ? '' : '_'.$index);
|
266 |
-
}
|
267 |
-
|
268 |
-
/**
|
269 |
-
* Gets the template class prefix.
|
270 |
-
*
|
271 |
-
* @return string The template class prefix
|
272 |
-
*/
|
273 |
-
public function getTemplateClassPrefix()
|
274 |
-
{
|
275 |
-
return $this->templateClassPrefix;
|
276 |
-
}
|
277 |
-
|
278 |
-
/**
|
279 |
-
* Renders a template.
|
280 |
-
*
|
281 |
-
* @param string $name The template name
|
282 |
-
* @param array $context An array of parameters to pass to the template
|
283 |
-
*
|
284 |
-
* @return string The rendered template
|
285 |
-
*
|
286 |
-
* @throws Twig_Error_Loader When the template cannot be found
|
287 |
-
* @throws Twig_Error_Syntax When an error occurred during compilation
|
288 |
-
* @throws Twig_Error_Runtime When an error occurred during rendering
|
289 |
-
*/
|
290 |
-
public function render($name, array $context = array())
|
291 |
-
{
|
292 |
-
return $this->loadTemplate($name)->render($context);
|
293 |
-
}
|
294 |
-
|
295 |
-
/**
|
296 |
-
* Displays a template.
|
297 |
-
*
|
298 |
-
* @param string $name The template name
|
299 |
-
* @param array $context An array of parameters to pass to the template
|
300 |
-
*
|
301 |
-
* @throws Twig_Error_Loader When the template cannot be found
|
302 |
-
* @throws Twig_Error_Syntax When an error occurred during compilation
|
303 |
-
* @throws Twig_Error_Runtime When an error occurred during rendering
|
304 |
-
*/
|
305 |
-
public function display($name, array $context = array())
|
306 |
-
{
|
307 |
-
$this->loadTemplate($name)->display($context);
|
308 |
-
}
|
309 |
-
|
310 |
-
/**
|
311 |
-
* Loads a template by name.
|
312 |
-
*
|
313 |
-
* @param string $name The template name
|
314 |
-
* @param int $index The index if it is an embedded template
|
315 |
-
*
|
316 |
-
* @return Twig_TemplateInterface A template instance representing the given template name
|
317 |
-
*
|
318 |
-
* @throws Twig_Error_Loader When the template cannot be found
|
319 |
-
* @throws Twig_Error_Syntax When an error occurred during compilation
|
320 |
-
*/
|
321 |
-
public function loadTemplate($name, $index = null)
|
322 |
-
{
|
323 |
-
$cls = $this->getTemplateClass($name, $index);
|
324 |
-
|
325 |
-
if (isset($this->loadedTemplates[$cls])) {
|
326 |
-
return $this->loadedTemplates[$cls];
|
327 |
-
}
|
328 |
-
|
329 |
-
if (!class_exists($cls, false)) {
|
330 |
-
if (false === $cache = $this->getCacheFilename($name)) {
|
331 |
-
eval('?>'.$this->compileSource($this->getLoader()->getSource($name), $name));
|
332 |
-
} else {
|
333 |
-
if (!is_file($cache) || ($this->isAutoReload() && !$this->isTemplateFresh($name, filemtime($cache)))) {
|
334 |
-
$this->writeCacheFile($cache, $this->compileSource($this->getLoader()->getSource($name), $name));
|
335 |
-
}
|
336 |
-
|
337 |
-
require_once $cache;
|
338 |
-
}
|
339 |
-
}
|
340 |
-
|
341 |
-
if (!$this->runtimeInitialized) {
|
342 |
-
$this->initRuntime();
|
343 |
-
}
|
344 |
-
|
345 |
-
return $this->loadedTemplates[$cls] = new $cls($this);
|
346 |
-
}
|
347 |
-
|
348 |
-
/**
|
349 |
-
* Returns true if the template is still fresh.
|
350 |
-
*
|
351 |
-
* Besides checking the loader for freshness information,
|
352 |
-
* this method also checks if the enabled extensions have
|
353 |
-
* not changed.
|
354 |
-
*
|
355 |
-
* @param string $name The template name
|
356 |
-
* @param timestamp $time The last modification time of the cached template
|
357 |
-
*
|
358 |
-
* @return bool true if the template is fresh, false otherwise
|
359 |
-
*/
|
360 |
-
public function isTemplateFresh($name, $time)
|
361 |
-
{
|
362 |
-
foreach ($this->extensions as $extension) {
|
363 |
-
$r = new ReflectionObject($extension);
|
364 |
-
if (filemtime($r->getFileName()) > $time) {
|
365 |
-
return false;
|
366 |
-
}
|
367 |
-
}
|
368 |
-
|
369 |
-
return $this->getLoader()->isFresh($name, $time);
|
370 |
-
}
|
371 |
-
|
372 |
-
/**
|
373 |
-
* Tries to load a template consecutively from an array.
|
374 |
-
*
|
375 |
-
* Similar to loadTemplate() but it also accepts Twig_TemplateInterface instances and an array
|
376 |
-
* of templates where each is tried to be loaded.
|
377 |
-
*
|
378 |
-
* @param string|Twig_Template|array $names A template or an array of templates to try consecutively
|
379 |
-
*
|
380 |
-
* @return Twig_Template
|
381 |
-
*
|
382 |
-
* @throws Twig_Error_Loader When none of the templates can be found
|
383 |
-
* @throws Twig_Error_Syntax When an error occurred during compilation
|
384 |
-
*/
|
385 |
-
public function resolveTemplate($names)
|
386 |
-
{
|
387 |
-
if (!is_array($names)) {
|
388 |
-
$names = array($names);
|
389 |
-
}
|
390 |
-
|
391 |
-
foreach ($names as $name) {
|
392 |
-
if ($name instanceof Twig_Template) {
|
393 |
-
return $name;
|
394 |
-
}
|
395 |
-
|
396 |
-
try {
|
397 |
-
return $this->loadTemplate($name);
|
398 |
-
} catch (Twig_Error_Loader $e) {
|
399 |
-
}
|
400 |
-
}
|
401 |
-
|
402 |
-
if (1 === count($names)) {
|
403 |
-
throw $e;
|
404 |
-
}
|
405 |
-
|
406 |
-
throw new Twig_Error_Loader(sprintf('Unable to find one of the following templates: "%s".', implode('", "', $names)));
|
407 |
-
}
|
408 |
-
|
409 |
-
/**
|
410 |
-
* Clears the internal template cache.
|
411 |
-
*/
|
412 |
-
public function clearTemplateCache()
|
413 |
-
{
|
414 |
-
$this->loadedTemplates = array();
|
415 |
-
}
|
416 |
-
|
417 |
-
/**
|
418 |
-
* Clears the template cache files on the filesystem.
|
419 |
-
*/
|
420 |
-
public function clearCacheFiles()
|
421 |
-
{
|
422 |
-
if (false === $this->cache) {
|
423 |
-
return;
|
424 |
-
}
|
425 |
-
|
426 |
-
foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($this->cache), RecursiveIteratorIterator::LEAVES_ONLY) as $file) {
|
427 |
-
if ($file->isFile()) {
|
428 |
-
@unlink($file->getPathname());
|
429 |
-
}
|
430 |
-
}
|
431 |
-
}
|
432 |
-
|
433 |
-
/**
|
434 |
-
* Gets the Lexer instance.
|
435 |
-
*
|
436 |
-
* @return Twig_LexerInterface A Twig_LexerInterface instance
|
437 |
-
*/
|
438 |
-
public function getLexer()
|
439 |
-
{
|
440 |
-
if (null === $this->lexer) {
|
441 |
-
$this->lexer = new Twig_Lexer($this);
|
442 |
-
}
|
443 |
-
|
444 |
-
return $this->lexer;
|
445 |
-
}
|
446 |
-
|
447 |
-
/**
|
448 |
-
* Sets the Lexer instance.
|
449 |
-
*
|
450 |
-
* @param Twig_LexerInterface A Twig_LexerInterface instance
|
451 |
-
*/
|
452 |
-
public function setLexer(Twig_LexerInterface $lexer)
|
453 |
-
{
|
454 |
-
$this->lexer = $lexer;
|
455 |
-
}
|
456 |
-
|
457 |
-
/**
|
458 |
-
* Tokenizes a source code.
|
459 |
-
*
|
460 |
-
* @param string $source The template source code
|
461 |
-
* @param string $name The template name
|
462 |
-
*
|
463 |
-
* @return Twig_TokenStream A Twig_TokenStream instance
|
464 |
-
*
|
465 |
-
* @throws Twig_Error_Syntax When the code is syntactically wrong
|
466 |
-
*/
|
467 |
-
public function tokenize($source, $name = null)
|
468 |
-
{
|
469 |
-
return $this->getLexer()->tokenize($source, $name);
|
470 |
-
}
|
471 |
-
|
472 |
-
/**
|
473 |
-
* Gets the Parser instance.
|
474 |
-
*
|
475 |
-
* @return Twig_ParserInterface A Twig_ParserInterface instance
|
476 |
-
*/
|
477 |
-
public function getParser()
|
478 |
-
{
|
479 |
-
if (null === $this->parser) {
|
480 |
-
$this->parser = new Twig_Parser($this);
|
481 |
-
}
|
482 |
-
|
483 |
-
return $this->parser;
|
484 |
-
}
|
485 |
-
|
486 |
-
/**
|
487 |
-
* Sets the Parser instance.
|
488 |
-
*
|
489 |
-
* @param Twig_ParserInterface A Twig_ParserInterface instance
|
490 |
-
*/
|
491 |
-
public function setParser(Twig_ParserInterface $parser)
|
492 |
-
{
|
493 |
-
$this->parser = $parser;
|
494 |
-
}
|
495 |
-
|
496 |
-
/**
|
497 |
-
* Converts a token stream to a node tree.
|
498 |
-
*
|
499 |
-
* @param Twig_TokenStream $stream A token stream instance
|
500 |
-
*
|
501 |
-
* @return Twig_Node_Module A node tree
|
502 |
-
*
|
503 |
-
* @throws Twig_Error_Syntax When the token stream is syntactically or semantically wrong
|
504 |
-
*/
|
505 |
-
public function parse(Twig_TokenStream $stream)
|
506 |
-
{
|
507 |
-
return $this->getParser()->parse($stream);
|
508 |
-
}
|
509 |
-
|
510 |
-
/**
|
511 |
-
* Gets the Compiler instance.
|
512 |
-
*
|
513 |
-
* @return Twig_CompilerInterface A Twig_CompilerInterface instance
|
514 |
-
*/
|
515 |
-
public function getCompiler()
|
516 |
-
{
|
517 |
-
if (null === $this->compiler) {
|
518 |
-
$this->compiler = new Twig_Compiler($this);
|
519 |
-
}
|
520 |
-
|
521 |
-
return $this->compiler;
|
522 |
-
}
|
523 |
-
|
524 |
-
/**
|
525 |
-
* Sets the Compiler instance.
|
526 |
-
*
|
527 |
-
* @param Twig_CompilerInterface $compiler A Twig_CompilerInterface instance
|
528 |
-
*/
|
529 |
-
public function setCompiler(Twig_CompilerInterface $compiler)
|
530 |
-
{
|
531 |
-
$this->compiler = $compiler;
|
532 |
-
}
|
533 |
-
|
534 |
-
/**
|
535 |
-
* Compiles a node and returns the PHP code.
|
536 |
-
*
|
537 |
-
* @param Twig_NodeInterface $node A Twig_NodeInterface instance
|
538 |
-
*
|
539 |
-
* @return string The compiled PHP source code
|
540 |
-
*/
|
541 |
-
public function compile(Twig_NodeInterface $node)
|
542 |
-
{
|
543 |
-
return $this->getCompiler()->compile($node)->getSource();
|
544 |
-
}
|
545 |
-
|
546 |
-
/**
|
547 |
-
* Compiles a template source code.
|
548 |
-
*
|
549 |
-
* @param string $source The template source code
|
550 |
-
* @param string $name The template name
|
551 |
-
*
|
552 |
-
* @return string The compiled PHP source code
|
553 |
-
*
|
554 |
-
* @throws Twig_Error_Syntax When there was an error during tokenizing, parsing or compiling
|
555 |
-
*/
|
556 |
-
public function compileSource($source, $name = null)
|
557 |
-
{
|
558 |
-
try {
|
559 |
-
return $this->compile($this->parse($this->tokenize($source, $name)));
|
560 |
-
} catch (Twig_Error $e) {
|
561 |
-
$e->setTemplateFile($name);
|
562 |
-
throw $e;
|
563 |
-
} catch (Exception $e) {
|
564 |
-
throw new Twig_Error_Syntax(sprintf('An exception has been thrown during the compilation of a template ("%s").', $e->getMessage()), -1, $name, $e);
|
565 |
-
}
|
566 |
-
}
|
567 |
-
|
568 |
-
/**
|
569 |
-
* Sets the Loader instance.
|
570 |
-
*
|
571 |
-
* @param Twig_LoaderInterface $loader A Twig_LoaderInterface instance
|
572 |
-
*/
|
573 |
-
public function setLoader(Twig_LoaderInterface $loader)
|
574 |
-
{
|
575 |
-
$this->loader = $loader;
|
576 |
-
}
|
577 |
-
|
578 |
-
/**
|
579 |
-
* Gets the Loader instance.
|
580 |
-
*
|
581 |
-
* @return Twig_LoaderInterface A Twig_LoaderInterface instance
|
582 |
-
*/
|
583 |
-
public function getLoader()
|
584 |
-
{
|
585 |
-
if (null === $this->loader) {
|
586 |
-
throw new LogicException('You must set a loader first.');
|
587 |
-
}
|
588 |
-
|
589 |
-
return $this->loader;
|
590 |
-
}
|
591 |
-
|
592 |
-
/**
|
593 |
-
* Sets the default template charset.
|
594 |
-
*
|
595 |
-
* @param string $charset The default charset
|
596 |
-
*/
|
597 |
-
public function setCharset($charset)
|
598 |
-
{
|
599 |
-
$this->charset = strtoupper($charset);
|
600 |
-
}
|
601 |
-
|
602 |
-
/**
|
603 |
-
* Gets the default template charset.
|
604 |
-
*
|
605 |
-
* @return string The default charset
|
606 |
-
*/
|
607 |
-
public function getCharset()
|
608 |
-
{
|
609 |
-
return $this->charset;
|
610 |
-
}
|
611 |
-
|
612 |
-
/**
|
613 |
-
* Initializes the runtime environment.
|
614 |
-
*/
|
615 |
-
public function initRuntime()
|
616 |
-
{
|
617 |
-
$this->runtimeInitialized = true;
|
618 |
-
|
619 |
-
foreach ($this->getExtensions() as $extension) {
|
620 |
-
$extension->initRuntime($this);
|
621 |
-
}
|
622 |
-
}
|
623 |
-
|
624 |
-
/**
|
625 |
-
* Returns true if the given extension is registered.
|
626 |
-
*
|
627 |
-
* @param string $name The extension name
|
628 |
-
*
|
629 |
-
* @return bool Whether the extension is registered or not
|
630 |
-
*/
|
631 |
-
public function hasExtension($name)
|
632 |
-
{
|
633 |
-
return isset($this->extensions[$name]);
|
634 |
-
}
|
635 |
-
|
636 |
-
/**
|
637 |
-
* Gets an extension by name.
|
638 |
-
*
|
639 |
-
* @param string $name The extension name
|
640 |
-
*
|
641 |
-
* @return Twig_ExtensionInterface A Twig_ExtensionInterface instance
|
642 |
-
*/
|
643 |
-
public function getExtension($name)
|
644 |
-
{
|
645 |
-
if (!isset($this->extensions[$name])) {
|
646 |
-
throw new Twig_Error_Runtime(sprintf('The "%s" extension is not enabled.', $name));
|
647 |
-
}
|
648 |
-
|
649 |
-
return $this->extensions[$name];
|
650 |
-
}
|
651 |
-
|
652 |
-
/**
|
653 |
-
* Registers an extension.
|
654 |
-
*
|
655 |
-
* @param Twig_ExtensionInterface $extension A Twig_ExtensionInterface instance
|
656 |
-
*/
|
657 |
-
public function addExtension(Twig_ExtensionInterface $extension)
|
658 |
-
{
|
659 |
-
if ($this->extensionInitialized) {
|
660 |
-
throw new LogicException(sprintf('Unable to register extension "%s" as extensions have already been initialized.', $extension->getName()));
|
661 |
-
}
|
662 |
-
|
663 |
-
$this->extensions[$extension->getName()] = $extension;
|
664 |
-
}
|
665 |
-
|
666 |
-
/**
|
667 |
-
* Removes an extension by name.
|
668 |
-
*
|
669 |
-
* This method is deprecated and you should not use it.
|
670 |
-
*
|
671 |
-
* @param string $name The extension name
|
672 |
-
*
|
673 |
-
* @deprecated since 1.12 (to be removed in 2.0)
|
674 |
-
*/
|
675 |
-
public function removeExtension($name)
|
676 |
-
{
|
677 |
-
if ($this->extensionInitialized) {
|
678 |
-
throw new LogicException(sprintf('Unable to remove extension "%s" as extensions have already been initialized.', $name));
|
679 |
-
}
|
680 |
-
|
681 |
-
unset($this->extensions[$name]);
|
682 |
-
}
|
683 |
-
|
684 |
-
/**
|
685 |
-
* Registers an array of extensions.
|
686 |
-
*
|
687 |
-
* @param array $extensions An array of extensions
|
688 |
-
*/
|
689 |
-
public function setExtensions(array $extensions)
|
690 |
-
{
|
691 |
-
foreach ($extensions as $extension) {
|
692 |
-
$this->addExtension($extension);
|
693 |
-
}
|
694 |
-
}
|
695 |
-
|
696 |
-
/**
|
697 |
-
* Returns all registered extensions.
|
698 |
-
*
|
699 |
-
* @return array An array of extensions
|
700 |
-
*/
|
701 |
-
public function getExtensions()
|
702 |
-
{
|
703 |
-
return $this->extensions;
|
704 |
-
}
|
705 |
-
|
706 |
-
/**
|
707 |
-
* Registers a Token Parser.
|
708 |
-
*
|
709 |
-
* @param Twig_TokenParserInterface $parser A Twig_TokenParserInterface instance
|
710 |
-
*/
|
711 |
-
public function addTokenParser(Twig_TokenParserInterface $parser)
|
712 |
-
{
|
713 |
-
if ($this->extensionInitialized) {
|
714 |
-
throw new LogicException('Unable to add a token parser as extensions have already been initialized.');
|
715 |
-
}
|
716 |
-
|
717 |
-
$this->staging->addTokenParser($parser);
|
718 |
-
}
|
719 |
-
|
720 |
-
/**
|
721 |
-
* Gets the registered Token Parsers.
|
722 |
-
*
|
723 |
-
* @return Twig_TokenParserBrokerInterface A broker containing token parsers
|
724 |
-
*/
|
725 |
-
public function getTokenParsers()
|
726 |
-
{
|
727 |
-
if (!$this->extensionInitialized) {
|
728 |
-
$this->initExtensions();
|
729 |
-
}
|
730 |
-
|
731 |
-
return $this->parsers;
|
732 |
-
}
|
733 |
-
|
734 |
-
/**
|
735 |
-
* Gets registered tags.
|
736 |
-
*
|
737 |
-
* Be warned that this method cannot return tags defined by Twig_TokenParserBrokerInterface classes.
|
738 |
-
*
|
739 |
-
* @return Twig_TokenParserInterface[] An array of Twig_TokenParserInterface instances
|
740 |
-
*/
|
741 |
-
public function getTags()
|
742 |
-
{
|
743 |
-
$tags = array();
|
744 |
-
foreach ($this->getTokenParsers()->getParsers() as $parser) {
|
745 |
-
if ($parser instanceof Twig_TokenParserInterface) {
|
746 |
-
$tags[$parser->getTag()] = $parser;
|
747 |
-
}
|
748 |
-
}
|
749 |
-
|
750 |
-
return $tags;
|
751 |
-
}
|
752 |
-
|
753 |
-
/**
|
754 |
-
* Registers a Node Visitor.
|
755 |
-
*
|
756 |
-
* @param Twig_NodeVisitorInterface $visitor A Twig_NodeVisitorInterface instance
|
757 |
-
*/
|
758 |
-
public function addNodeVisitor(Twig_NodeVisitorInterface $visitor)
|
759 |
-
{
|
760 |
-
if ($this->extensionInitialized) {
|
761 |
-
throw new LogicException('Unable to add a node visitor as extensions have already been initialized.');
|
762 |
-
}
|
763 |
-
|
764 |
-
$this->staging->addNodeVisitor($visitor);
|
765 |
-
}
|
766 |
-
|
767 |
-
/**
|
768 |
-
* Gets the registered Node Visitors.
|
769 |
-
*
|
770 |
-
* @return Twig_NodeVisitorInterface[] An array of Twig_NodeVisitorInterface instances
|
771 |
-
*/
|
772 |
-
public function getNodeVisitors()
|
773 |
-
{
|
774 |
-
if (!$this->extensionInitialized) {
|
775 |
-
$this->initExtensions();
|
776 |
-
}
|
777 |
-
|
778 |
-
return $this->visitors;
|
779 |
-
}
|
780 |
-
|
781 |
-
/**
|
782 |
-
* Registers a Filter.
|
783 |
-
*
|
784 |
-
* @param string|Twig_SimpleFilter $name The filter name or a Twig_SimpleFilter instance
|
785 |
-
* @param Twig_FilterInterface|Twig_SimpleFilter $filter A Twig_FilterInterface instance or a Twig_SimpleFilter instance
|
786 |
-
*/
|
787 |
-
public function addFilter($name, $filter = null)
|
788 |
-
{
|
789 |
-
if (!$name instanceof Twig_SimpleFilter && !($filter instanceof Twig_SimpleFilter || $filter instanceof Twig_FilterInterface)) {
|
790 |
-
throw new LogicException('A filter must be an instance of Twig_FilterInterface or Twig_SimpleFilter');
|
791 |
-
}
|
792 |
-
|
793 |
-
if ($name instanceof Twig_SimpleFilter) {
|
794 |
-
$filter = $name;
|
795 |
-
$name = $filter->getName();
|
796 |
-
}
|
797 |
-
|
798 |
-
if ($this->extensionInitialized) {
|
799 |
-
throw new LogicException(sprintf('Unable to add filter "%s" as extensions have already been initialized.', $name));
|
800 |
-
}
|
801 |
-
|
802 |
-
$this->staging->addFilter($name, $filter);
|
803 |
-
}
|
804 |
-
|
805 |
-
/**
|
806 |
-
* Get a filter by name.
|
807 |
-
*
|
808 |
-
* Subclasses may override this method and load filters differently;
|
809 |
-
* so no list of filters is available.
|
810 |
-
*
|
811 |
-
* @param string $name The filter name
|
812 |
-
*
|
813 |
-
* @return Twig_Filter|false A Twig_Filter instance or false if the filter does not exist
|
814 |
-
*/
|
815 |
-
public function getFilter($name)
|
816 |
-
{
|
817 |
-
if (!$this->extensionInitialized) {
|
818 |
-
$this->initExtensions();
|
819 |
-
}
|
820 |
-
|
821 |
-
if (isset($this->filters[$name])) {
|
822 |
-
return $this->filters[$name];
|
823 |
-
}
|
824 |
-
|
825 |
-
foreach ($this->filters as $pattern => $filter) {
|
826 |
-
$pattern = str_replace('\\*', '(.*?)', preg_quote($pattern, '#'), $count);
|
827 |
-
|
828 |
-
if ($count) {
|
829 |
-
if (preg_match('#^'.$pattern.'$#', $name, $matches)) {
|
830 |
-
array_shift($matches);
|
831 |
-
$filter->setArguments($matches);
|
832 |
-
|
833 |
-
return $filter;
|
834 |
-
}
|
835 |
-
}
|
836 |
-
}
|
837 |
-
|
838 |
-
foreach ($this->filterCallbacks as $callback) {
|
839 |
-
if (false !== $filter = call_user_func($callback, $name)) {
|
840 |
-
return $filter;
|
841 |
-
}
|
842 |
-
}
|
843 |
-
|
844 |
-
return false;
|
845 |
-
}
|
846 |
-
|
847 |
-
public function registerUndefinedFilterCallback($callable)
|
848 |
-
{
|
849 |
-
$this->filterCallbacks[] = $callable;
|
850 |
-
}
|
851 |
-
|
852 |
-
/**
|
853 |
-
* Gets the registered Filters.
|
854 |
-
*
|
855 |
-
* Be warned that this method cannot return filters defined with registerUndefinedFunctionCallback.
|
856 |
-
*
|
857 |
-
* @return Twig_FilterInterface[] An array of Twig_FilterInterface instances
|
858 |
-
*
|
859 |
-
* @see registerUndefinedFilterCallback
|
860 |
-
*/
|
861 |
-
public function getFilters()
|
862 |
-
{
|
863 |
-
if (!$this->extensionInitialized) {
|
864 |
-
$this->initExtensions();
|
865 |
-
}
|
866 |
-
|
867 |
-
return $this->filters;
|
868 |
-
}
|
869 |
-
|
870 |
-
/**
|
871 |
-
* Registers a Test.
|
872 |
-
*
|
873 |
-
* @param string|Twig_SimpleTest $name The test name or a Twig_SimpleTest instance
|
874 |
-
* @param Twig_TestInterface|Twig_SimpleTest $test A Twig_TestInterface instance or a Twig_SimpleTest instance
|
875 |
-
*/
|
876 |
-
public function addTest($name, $test = null)
|
877 |
-
{
|
878 |
-
if (!$name instanceof Twig_SimpleTest && !($test instanceof Twig_SimpleTest || $test instanceof Twig_TestInterface)) {
|
879 |
-
throw new LogicException('A test must be an instance of Twig_TestInterface or Twig_SimpleTest');
|
880 |
-
}
|
881 |
-
|
882 |
-
if ($name instanceof Twig_SimpleTest) {
|
883 |
-
$test = $name;
|
884 |
-
$name = $test->getName();
|
885 |
-
}
|
886 |
-
|
887 |
-
if ($this->extensionInitialized) {
|
888 |
-
throw new LogicException(sprintf('Unable to add test "%s" as extensions have already been initialized.', $name));
|
889 |
-
}
|
890 |
-
|
891 |
-
$this->staging->addTest($name, $test);
|
892 |
-
}
|
893 |
-
|
894 |
-
/**
|
895 |
-
* Gets the registered Tests.
|
896 |
-
*
|
897 |
-
* @return Twig_TestInterface[] An array of Twig_TestInterface instances
|
898 |
-
*/
|
899 |
-
public function getTests()
|
900 |
-
{
|
901 |
-
if (!$this->extensionInitialized) {
|
902 |
-
$this->initExtensions();
|
903 |
-
}
|
904 |
-
|
905 |
-
return $this->tests;
|
906 |
-
}
|
907 |
-
|
908 |
-
/**
|
909 |
-
* Gets a test by name.
|
910 |
-
*
|
911 |
-
* @param string $name The test name
|
912 |
-
*
|
913 |
-
* @return Twig_Test|false A Twig_Test instance or false if the test does not exist
|
914 |
-
*/
|
915 |
-
public function getTest($name)
|
916 |
-
{
|
917 |
-
if (!$this->extensionInitialized) {
|
918 |
-
$this->initExtensions();
|
919 |
-
}
|
920 |
-
|
921 |
-
if (isset($this->tests[$name])) {
|
922 |
-
return $this->tests[$name];
|
923 |
-
}
|
924 |
-
|
925 |
-
return false;
|
926 |
-
}
|
927 |
-
|
928 |
-
/**
|
929 |
-
* Registers a Function.
|
930 |
-
*
|
931 |
-
* @param string|Twig_SimpleFunction $name The function name or a Twig_SimpleFunction instance
|
932 |
-
* @param Twig_FunctionInterface|Twig_SimpleFunction $function A Twig_FunctionInterface instance or a Twig_SimpleFunction instance
|
933 |
-
*/
|
934 |
-
public function addFunction($name, $function = null)
|
935 |
-
{
|
936 |
-
if (!$name instanceof Twig_SimpleFunction && !($function instanceof Twig_SimpleFunction || $function instanceof Twig_FunctionInterface)) {
|
937 |
-
throw new LogicException('A function must be an instance of Twig_FunctionInterface or Twig_SimpleFunction');
|
938 |
-
}
|
939 |
-
|
940 |
-
if ($name instanceof Twig_SimpleFunction) {
|
941 |
-
$function = $name;
|
942 |
-
$name = $function->getName();
|
943 |
-
}
|
944 |
-
|
945 |
-
if ($this->extensionInitialized) {
|
946 |
-
throw new LogicException(sprintf('Unable to add function "%s" as extensions have already been initialized.', $name));
|
947 |
-
}
|
948 |
-
|
949 |
-
$this->staging->addFunction($name, $function);
|
950 |
-
}
|
951 |
-
|
952 |
-
/**
|
953 |
-
* Get a function by name.
|
954 |
-
*
|
955 |
-
* Subclasses may override this method and load functions differently;
|
956 |
-
* so no list of functions is available.
|
957 |
-
*
|
958 |
-
* @param string $name function name
|
959 |
-
*
|
960 |
-
* @return Twig_Function|false A Twig_Function instance or false if the function does not exist
|
961 |
-
*/
|
962 |
-
public function getFunction($name)
|
963 |
-
{
|
964 |
-
if (!$this->extensionInitialized) {
|
965 |
-
$this->initExtensions();
|
966 |
-
}
|
967 |
-
|
968 |
-
if (isset($this->functions[$name])) {
|
969 |
-
return $this->functions[$name];
|
970 |
-
}
|
971 |
-
|
972 |
-
foreach ($this->functions as $pattern => $function) {
|
973 |
-
$pattern = str_replace('\\*', '(.*?)', preg_quote($pattern, '#'), $count);
|
974 |
-
|
975 |
-
if ($count) {
|
976 |
-
if (preg_match('#^'.$pattern.'$#', $name, $matches)) {
|
977 |
-
array_shift($matches);
|
978 |
-
$function->setArguments($matches);
|
979 |
-
|
980 |
-
return $function;
|
981 |
-
}
|
982 |
-
}
|
983 |
-
}
|
984 |
-
|
985 |
-
foreach ($this->functionCallbacks as $callback) {
|
986 |
-
if (false !== $function = call_user_func($callback, $name)) {
|
987 |
-
return $function;
|
988 |
-
}
|
989 |
-
}
|
990 |
-
|
991 |
-
return false;
|
992 |
-
}
|
993 |
-
|
994 |
-
public function registerUndefinedFunctionCallback($callable)
|
995 |
-
{
|
996 |
-
$this->functionCallbacks[] = $callable;
|
997 |
-
}
|
998 |
-
|
999 |
-
/**
|
1000 |
-
* Gets registered functions.
|
1001 |
-
*
|
1002 |
-
* Be warned that this method cannot return functions defined with registerUndefinedFunctionCallback.
|
1003 |
-
*
|
1004 |
-
* @return Twig_FunctionInterface[] An array of Twig_FunctionInterface instances
|
1005 |
-
*
|
1006 |
-
* @see registerUndefinedFunctionCallback
|
1007 |
-
*/
|
1008 |
-
public function getFunctions()
|
1009 |
-
{
|
1010 |
-
if (!$this->extensionInitialized) {
|
1011 |
-
$this->initExtensions();
|
1012 |
-
}
|
1013 |
-
|
1014 |
-
return $this->functions;
|
1015 |
-
}
|
1016 |
-
|
1017 |
-
/**
|
1018 |
-
* Registers a Global.
|
1019 |
-
*
|
1020 |
-
* New globals can be added before compiling or rendering a template;
|
1021 |
-
* but after, you can only update existing globals.
|
1022 |
-
*
|
1023 |
-
* @param string $name The global name
|
1024 |
-
* @param mixed $value The global value
|
1025 |
-
*/
|
1026 |
-
public function addGlobal($name, $value)
|
1027 |
-
{
|
1028 |
-
if ($this->extensionInitialized || $this->runtimeInitialized) {
|
1029 |
-
if (null === $this->globals) {
|
1030 |
-
$this->globals = $this->initGlobals();
|
1031 |
-
}
|
1032 |
-
|
1033 |
-
/* This condition must be uncommented in Twig 2.0
|
1034 |
-
if (!array_key_exists($name, $this->globals)) {
|
1035 |
-
throw new LogicException(sprintf('Unable to add global "%s" as the runtime or the extensions have already been initialized.', $name));
|
1036 |
-
}
|
1037 |
-
*/
|
1038 |
-
}
|
1039 |
-
|
1040 |
-
if ($this->extensionInitialized || $this->runtimeInitialized) {
|
1041 |
-
// update the value
|
1042 |
-
$this->globals[$name] = $value;
|
1043 |
-
} else {
|
1044 |
-
$this->staging->addGlobal($name, $value);
|
1045 |
-
}
|
1046 |
-
}
|
1047 |
-
|
1048 |
-
/**
|
1049 |
-
* Gets the registered Globals.
|
1050 |
-
*
|
1051 |
-
* @return array An array of globals
|
1052 |
-
*/
|
1053 |
-
public function getGlobals()
|
1054 |
-
{
|
1055 |
-
if (!$this->runtimeInitialized && !$this->extensionInitialized) {
|
1056 |
-
return $this->initGlobals();
|
1057 |
-
}
|
1058 |
-
|
1059 |
-
if (null === $this->globals) {
|
1060 |
-
$this->globals = $this->initGlobals();
|
1061 |
-
}
|
1062 |
-
|
1063 |
-
return $this->globals;
|
1064 |
-
}
|
1065 |
-
|
1066 |
-
/**
|
1067 |
-
* Merges a context with the defined globals.
|
1068 |
-
*
|
1069 |
-
* @param array $context An array representing the context
|
1070 |
-
*
|
1071 |
-
* @return array The context merged with the globals
|
1072 |
-
*/
|
1073 |
-
public function mergeGlobals(array $context)
|
1074 |
-
{
|
1075 |
-
// we don't use array_merge as the context being generally
|
1076 |
-
// bigger than globals, this code is faster.
|
1077 |
-
foreach ($this->getGlobals() as $key => $value) {
|
1078 |
-
if (!array_key_exists($key, $context)) {
|
1079 |
-
$context[$key] = $value;
|
1080 |
-
}
|
1081 |
-
}
|
1082 |
-
|
1083 |
-
return $context;
|
1084 |
-
}
|
1085 |
-
|
1086 |
-
/**
|
1087 |
-
* Gets the registered unary Operators.
|
1088 |
-
*
|
1089 |
-
* @return array An array of unary operators
|
1090 |
-
*/
|
1091 |
-
public function getUnaryOperators()
|
1092 |
-
{
|
1093 |
-
if (!$this->extensionInitialized) {
|
1094 |
-
$this->initExtensions();
|
1095 |
-
}
|
1096 |
-
|
1097 |
-
return $this->unaryOperators;
|
1098 |
-
}
|
1099 |
-
|
1100 |
-
/**
|
1101 |
-
* Gets the registered binary Operators.
|
1102 |
-
*
|
1103 |
-
* @return array An array of binary operators
|
1104 |
-
*/
|
1105 |
-
public function getBinaryOperators()
|
1106 |
-
{
|
1107 |
-
if (!$this->extensionInitialized) {
|
1108 |
-
$this->initExtensions();
|
1109 |
-
}
|
1110 |
-
|
1111 |
-
return $this->binaryOperators;
|
1112 |
-
}
|
1113 |
-
|
1114 |
-
public function computeAlternatives($name, $items)
|
1115 |
-
{
|
1116 |
-
$alternatives = array();
|
1117 |
-
foreach ($items as $item) {
|
1118 |
-
$lev = levenshtein($name, $item);
|
1119 |
-
if ($lev <= strlen($name) / 3 || false !== strpos($item, $name)) {
|
1120 |
-
$alternatives[$item] = $lev;
|
1121 |
-
}
|
1122 |
-
}
|
1123 |
-
asort($alternatives);
|
1124 |
-
|
1125 |
-
return array_keys($alternatives);
|
1126 |
-
}
|
1127 |
-
|
1128 |
-
protected function initGlobals()
|
1129 |
-
{
|
1130 |
-
$globals = array();
|
1131 |
-
foreach ($this->extensions as $extension) {
|
1132 |
-
$extGlob = $extension->getGlobals();
|
1133 |
-
if (!is_array($extGlob)) {
|
1134 |
-
throw new UnexpectedValueException(sprintf('"%s::getGlobals()" must return an array of globals.', get_class($extension)));
|
1135 |
-
}
|
1136 |
-
|
1137 |
-
$globals[] = $extGlob;
|
1138 |
-
}
|
1139 |
-
|
1140 |
-
$globals[] = $this->staging->getGlobals();
|
1141 |
-
|
1142 |
-
return call_user_func_array('array_merge', $globals);
|
1143 |
-
}
|
1144 |
-
|
1145 |
-
protected function initExtensions()
|
1146 |
-
{
|
1147 |
-
if ($this->extensionInitialized) {
|
1148 |
-
return;
|
1149 |
-
}
|
1150 |
-
|
1151 |
-
$this->extensionInitialized = true;
|
1152 |
-
$this->parsers = new Twig_TokenParserBroker();
|
1153 |
-
$this->filters = array();
|
1154 |
-
$this->functions = array();
|
1155 |
-
$this->tests = array();
|
1156 |
-
$this->visitors = array();
|
1157 |
-
$this->unaryOperators = array();
|
1158 |
-
$this->binaryOperators = array();
|
1159 |
-
|
1160 |
-
foreach ($this->extensions as $extension) {
|
1161 |
-
$this->initExtension($extension);
|
1162 |
-
}
|
1163 |
-
$this->initExtension($this->staging);
|
1164 |
-
}
|
1165 |
-
|
1166 |
-
protected function initExtension(Twig_ExtensionInterface $extension)
|
1167 |
-
{
|
1168 |
-
// filters
|
1169 |
-
foreach ($extension->getFilters() as $name => $filter) {
|
1170 |
-
if ($name instanceof Twig_SimpleFilter) {
|
1171 |
-
$filter = $name;
|
1172 |
-
$name = $filter->getName();
|
1173 |
-
} elseif ($filter instanceof Twig_SimpleFilter) {
|
1174 |
-
$name = $filter->getName();
|
1175 |
-
}
|
1176 |
-
|
1177 |
-
$this->filters[$name] = $filter;
|
1178 |
-
}
|
1179 |
-
|
1180 |
-
// functions
|
1181 |
-
foreach ($extension->getFunctions() as $name => $function) {
|
1182 |
-
if ($name instanceof Twig_SimpleFunction) {
|
1183 |
-
$function = $name;
|
1184 |
-
$name = $function->getName();
|
1185 |
-
} elseif ($function instanceof Twig_SimpleFunction) {
|
1186 |
-
$name = $function->getName();
|
1187 |
-
}
|
1188 |
-
|
1189 |
-
$this->functions[$name] = $function;
|
1190 |
-
}
|
1191 |
-
|
1192 |
-
// tests
|
1193 |
-
foreach ($extension->getTests() as $name => $test) {
|
1194 |
-
if ($name instanceof Twig_SimpleTest) {
|
1195 |
-
$test = $name;
|
1196 |
-
$name = $test->getName();
|
1197 |
-
} elseif ($test instanceof Twig_SimpleTest) {
|
1198 |
-
$name = $test->getName();
|
1199 |
-
}
|
1200 |
-
|
1201 |
-
$this->tests[$name] = $test;
|
1202 |
-
}
|
1203 |
-
|
1204 |
-
// token parsers
|
1205 |
-
foreach ($extension->getTokenParsers() as $parser) {
|
1206 |
-
if ($parser instanceof Twig_TokenParserInterface) {
|
1207 |
-
$this->parsers->addTokenParser($parser);
|
1208 |
-
} elseif ($parser instanceof Twig_TokenParserBrokerInterface) {
|
1209 |
-
$this->parsers->addTokenParserBroker($parser);
|
1210 |
-
} else {
|
1211 |
-
throw new LogicException('getTokenParsers() must return an array of Twig_TokenParserInterface or Twig_TokenParserBrokerInterface instances');
|
1212 |
-
}
|
1213 |
-
}
|
1214 |
-
|
1215 |
-
// node visitors
|
1216 |
-
foreach ($extension->getNodeVisitors() as $visitor) {
|
1217 |
-
$this->visitors[] = $visitor;
|
1218 |
-
}
|
1219 |
-
|
1220 |
-
// operators
|
1221 |
-
if ($operators = $extension->getOperators()) {
|
1222 |
-
if (2 !== count($operators)) {
|
1223 |
-
throw new InvalidArgumentException(sprintf('"%s::getOperators()" does not return a valid operators array.', get_class($extension)));
|
1224 |
-
}
|
1225 |
-
|
1226 |
-
$this->unaryOperators = array_merge($this->unaryOperators, $operators[0]);
|
1227 |
-
$this->binaryOperators = array_merge($this->binaryOperators, $operators[1]);
|
1228 |
-
}
|
1229 |
-
}
|
1230 |
-
|
1231 |
-
protected function writeCacheFile($file, $content)
|
1232 |
-
{
|
1233 |
-
$dir = dirname($file);
|
1234 |
-
if (!is_dir($dir)) {
|
1235 |
-
if (false === @mkdir($dir, 0777, true) && !is_dir($dir)) {
|
1236 |
-
throw new RuntimeException(sprintf("Unable to create the cache directory (%s).", $dir));
|
1237 |
-
}
|
1238 |
-
} elseif (!is_writable($dir)) {
|
1239 |
-
throw new RuntimeException(sprintf("Unable to write in the cache directory (%s).", $dir));
|
1240 |
-
}
|
1241 |
-
|
1242 |
-
$tmpFile = tempnam($dir, basename($file));
|
1243 |
-
if (false !== @file_put_contents($tmpFile, $content)) {
|
1244 |
-
// rename does not work on Win32 before 5.2.6
|
1245 |
-
if (@rename($tmpFile, $file) || (@copy($tmpFile, $file) && unlink($tmpFile))) {
|
1246 |
-
@chmod($file, 0666 & ~umask());
|
1247 |
-
|
1248 |
-
return;
|
1249 |
-
}
|
1250 |
-
}
|
1251 |
-
|
1252 |
-
throw new RuntimeException(sprintf('Failed to write cache file "%s".', $file));
|
1253 |
-
}
|
1254 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2009 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Stores the Twig configuration.
|
14 |
+
*
|
15 |
+
* @author Fabien Potencier <fabien@symfony.com>
|
16 |
+
*/
|
17 |
+
class Twig_Environment
|
18 |
+
{
|
19 |
+
const VERSION = '1.16.0';
|
20 |
+
|
21 |
+
protected $charset;
|
22 |
+
protected $loader;
|
23 |
+
protected $debug;
|
24 |
+
protected $autoReload;
|
25 |
+
protected $cache;
|
26 |
+
protected $lexer;
|
27 |
+
protected $parser;
|
28 |
+
protected $compiler;
|
29 |
+
protected $baseTemplateClass;
|
30 |
+
protected $extensions;
|
31 |
+
protected $parsers;
|
32 |
+
protected $visitors;
|
33 |
+
protected $filters;
|
34 |
+
protected $tests;
|
35 |
+
protected $functions;
|
36 |
+
protected $globals;
|
37 |
+
protected $runtimeInitialized;
|
38 |
+
protected $extensionInitialized;
|
39 |
+
protected $loadedTemplates;
|
40 |
+
protected $strictVariables;
|
41 |
+
protected $unaryOperators;
|
42 |
+
protected $binaryOperators;
|
43 |
+
protected $templateClassPrefix = '__TwigTemplate_';
|
44 |
+
protected $functionCallbacks;
|
45 |
+
protected $filterCallbacks;
|
46 |
+
protected $staging;
|
47 |
+
|
48 |
+
/**
|
49 |
+
* Constructor.
|
50 |
+
*
|
51 |
+
* Available options:
|
52 |
+
*
|
53 |
+
* * debug: When set to true, it automatically set "auto_reload" to true as
|
54 |
+
* well (default to false).
|
55 |
+
*
|
56 |
+
* * charset: The charset used by the templates (default to UTF-8).
|
57 |
+
*
|
58 |
+
* * base_template_class: The base template class to use for generated
|
59 |
+
* templates (default to Twig_Template).
|
60 |
+
*
|
61 |
+
* * cache: An absolute path where to store the compiled templates, or
|
62 |
+
* false to disable compilation cache (default).
|
63 |
+
*
|
64 |
+
* * auto_reload: Whether to reload the template if the original source changed.
|
65 |
+
* If you don't provide the auto_reload option, it will be
|
66 |
+
* determined automatically based on the debug value.
|
67 |
+
*
|
68 |
+
* * strict_variables: Whether to ignore invalid variables in templates
|
69 |
+
* (default to false).
|
70 |
+
*
|
71 |
+
* * autoescape: Whether to enable auto-escaping (default to html):
|
72 |
+
* * false: disable auto-escaping
|
73 |
+
* * true: equivalent to html
|
74 |
+
* * html, js: set the autoescaping to one of the supported strategies
|
75 |
+
* * PHP callback: a PHP callback that returns an escaping strategy based on the template "filename"
|
76 |
+
*
|
77 |
+
* * optimizations: A flag that indicates which optimizations to apply
|
78 |
+
* (default to -1 which means that all optimizations are enabled;
|
79 |
+
* set it to 0 to disable).
|
80 |
+
*
|
81 |
+
* @param Twig_LoaderInterface $loader A Twig_LoaderInterface instance
|
82 |
+
* @param array $options An array of options
|
83 |
+
*/
|
84 |
+
public function __construct(Twig_LoaderInterface $loader = null, $options = array())
|
85 |
+
{
|
86 |
+
if (null !== $loader) {
|
87 |
+
$this->setLoader($loader);
|
88 |
+
}
|
89 |
+
|
90 |
+
$options = array_merge(array(
|
91 |
+
'debug' => false,
|
92 |
+
'charset' => 'UTF-8',
|
93 |
+
'base_template_class' => 'Twig_Template',
|
94 |
+
'strict_variables' => false,
|
95 |
+
'autoescape' => 'html',
|
96 |
+
'cache' => false,
|
97 |
+
'auto_reload' => null,
|
98 |
+
'optimizations' => -1,
|
99 |
+
), $options);
|
100 |
+
|
101 |
+
$this->debug = (bool) $options['debug'];
|
102 |
+
$this->charset = strtoupper($options['charset']);
|
103 |
+
$this->baseTemplateClass = $options['base_template_class'];
|
104 |
+
$this->autoReload = null === $options['auto_reload'] ? $this->debug : (bool) $options['auto_reload'];
|
105 |
+
$this->strictVariables = (bool) $options['strict_variables'];
|
106 |
+
$this->runtimeInitialized = false;
|
107 |
+
$this->setCache($options['cache']);
|
108 |
+
$this->functionCallbacks = array();
|
109 |
+
$this->filterCallbacks = array();
|
110 |
+
|
111 |
+
$this->addExtension(new Twig_Extension_Core());
|
112 |
+
$this->addExtension(new Twig_Extension_Escaper($options['autoescape']));
|
113 |
+
$this->addExtension(new Twig_Extension_Optimizer($options['optimizations']));
|
114 |
+
$this->extensionInitialized = false;
|
115 |
+
$this->staging = new Twig_Extension_Staging();
|
116 |
+
}
|
117 |
+
|
118 |
+
/**
|
119 |
+
* Gets the base template class for compiled templates.
|
120 |
+
*
|
121 |
+
* @return string The base template class name
|
122 |
+
*/
|
123 |
+
public function getBaseTemplateClass()
|
124 |
+
{
|
125 |
+
return $this->baseTemplateClass;
|
126 |
+
}
|
127 |
+
|
128 |
+
/**
|
129 |
+
* Sets the base template class for compiled templates.
|
130 |
+
*
|
131 |
+
* @param string $class The base template class name
|
132 |
+
*/
|
133 |
+
public function setBaseTemplateClass($class)
|
134 |
+
{
|
135 |
+
$this->baseTemplateClass = $class;
|
136 |
+
}
|
137 |
+
|
138 |
+
/**
|
139 |
+
* Enables debugging mode.
|
140 |
+
*/
|
141 |
+
public function enableDebug()
|
142 |
+
{
|
143 |
+
$this->debug = true;
|
144 |
+
}
|
145 |
+
|
146 |
+
/**
|
147 |
+
* Disables debugging mode.
|
148 |
+
*/
|
149 |
+
public function disableDebug()
|
150 |
+
{
|
151 |
+
$this->debug = false;
|
152 |
+
}
|
153 |
+
|
154 |
+
/**
|
155 |
+
* Checks if debug mode is enabled.
|
156 |
+
*
|
157 |
+
* @return bool true if debug mode is enabled, false otherwise
|
158 |
+
*/
|
159 |
+
public function isDebug()
|
160 |
+
{
|
161 |
+
return $this->debug;
|
162 |
+
}
|
163 |
+
|
164 |
+
/**
|
165 |
+
* Enables the auto_reload option.
|
166 |
+
*/
|
167 |
+
public function enableAutoReload()
|
168 |
+
{
|
169 |
+
$this->autoReload = true;
|
170 |
+
}
|
171 |
+
|
172 |
+
/**
|
173 |
+
* Disables the auto_reload option.
|
174 |
+
*/
|
175 |
+
public function disableAutoReload()
|
176 |
+
{
|
177 |
+
$this->autoReload = false;
|
178 |
+
}
|
179 |
+
|
180 |
+
/**
|
181 |
+
* Checks if the auto_reload option is enabled.
|
182 |
+
*
|
183 |
+
* @return bool true if auto_reload is enabled, false otherwise
|
184 |
+
*/
|
185 |
+
public function isAutoReload()
|
186 |
+
{
|
187 |
+
return $this->autoReload;
|
188 |
+
}
|
189 |
+
|
190 |
+
/**
|
191 |
+
* Enables the strict_variables option.
|
192 |
+
*/
|
193 |
+
public function enableStrictVariables()
|
194 |
+
{
|
195 |
+
$this->strictVariables = true;
|
196 |
+
}
|
197 |
+
|
198 |
+
/**
|
199 |
+
* Disables the strict_variables option.
|
200 |
+
*/
|
201 |
+
public function disableStrictVariables()
|
202 |
+
{
|
203 |
+
$this->strictVariables = false;
|
204 |
+
}
|
205 |
+
|
206 |
+
/**
|
207 |
+
* Checks if the strict_variables option is enabled.
|
208 |
+
*
|
209 |
+
* @return bool true if strict_variables is enabled, false otherwise
|
210 |
+
*/
|
211 |
+
public function isStrictVariables()
|
212 |
+
{
|
213 |
+
return $this->strictVariables;
|
214 |
+
}
|
215 |
+
|
216 |
+
/**
|
217 |
+
* Gets the cache directory or false if cache is disabled.
|
218 |
+
*
|
219 |
+
* @return string|false
|
220 |
+
*/
|
221 |
+
public function getCache()
|
222 |
+
{
|
223 |
+
return $this->cache;
|
224 |
+
}
|
225 |
+
|
226 |
+
/**
|
227 |
+
* Sets the cache directory or false if cache is disabled.
|
228 |
+
*
|
229 |
+
* @param string|false $cache The absolute path to the compiled templates,
|
230 |
+
* or false to disable cache
|
231 |
+
*/
|
232 |
+
public function setCache($cache)
|
233 |
+
{
|
234 |
+
$this->cache = $cache ? $cache : false;
|
235 |
+
}
|
236 |
+
|
237 |
+
/**
|
238 |
+
* Gets the cache filename for a given template.
|
239 |
+
*
|
240 |
+
* @param string $name The template name
|
241 |
+
*
|
242 |
+
* @return string|false The cache file name or false when caching is disabled
|
243 |
+
*/
|
244 |
+
public function getCacheFilename($name)
|
245 |
+
{
|
246 |
+
if (false === $this->cache) {
|
247 |
+
return false;
|
248 |
+
}
|
249 |
+
|
250 |
+
$class = substr($this->getTemplateClass($name), strlen($this->templateClassPrefix));
|
251 |
+
|
252 |
+
return $this->getCache().'/'.substr($class, 0, 2).'/'.substr($class, 2, 2).'/'.substr($class, 4).'.php';
|
253 |
+
}
|
254 |
+
|
255 |
+
/**
|
256 |
+
* Gets the template class associated with the given string.
|
257 |
+
*
|
258 |
+
* @param string $name The name for which to calculate the template class name
|
259 |
+
* @param int $index The index if it is an embedded template
|
260 |
+
*
|
261 |
+
* @return string The template class name
|
262 |
+
*/
|
263 |
+
public function getTemplateClass($name, $index = null)
|
264 |
+
{
|
265 |
+
return $this->templateClassPrefix.hash('sha256', $this->getLoader()->getCacheKey($name)).(null === $index ? '' : '_'.$index);
|
266 |
+
}
|
267 |
+
|
268 |
+
/**
|
269 |
+
* Gets the template class prefix.
|
270 |
+
*
|
271 |
+
* @return string The template class prefix
|
272 |
+
*/
|
273 |
+
public function getTemplateClassPrefix()
|
274 |
+
{
|
275 |
+
return $this->templateClassPrefix;
|
276 |
+
}
|
277 |
+
|
278 |
+
/**
|
279 |
+
* Renders a template.
|
280 |
+
*
|
281 |
+
* @param string $name The template name
|
282 |
+
* @param array $context An array of parameters to pass to the template
|
283 |
+
*
|
284 |
+
* @return string The rendered template
|
285 |
+
*
|
286 |
+
* @throws Twig_Error_Loader When the template cannot be found
|
287 |
+
* @throws Twig_Error_Syntax When an error occurred during compilation
|
288 |
+
* @throws Twig_Error_Runtime When an error occurred during rendering
|
289 |
+
*/
|
290 |
+
public function render($name, array $context = array())
|
291 |
+
{
|
292 |
+
return $this->loadTemplate($name)->render($context);
|
293 |
+
}
|
294 |
+
|
295 |
+
/**
|
296 |
+
* Displays a template.
|
297 |
+
*
|
298 |
+
* @param string $name The template name
|
299 |
+
* @param array $context An array of parameters to pass to the template
|
300 |
+
*
|
301 |
+
* @throws Twig_Error_Loader When the template cannot be found
|
302 |
+
* @throws Twig_Error_Syntax When an error occurred during compilation
|
303 |
+
* @throws Twig_Error_Runtime When an error occurred during rendering
|
304 |
+
*/
|
305 |
+
public function display($name, array $context = array())
|
306 |
+
{
|
307 |
+
$this->loadTemplate($name)->display($context);
|
308 |
+
}
|
309 |
+
|
310 |
+
/**
|
311 |
+
* Loads a template by name.
|
312 |
+
*
|
313 |
+
* @param string $name The template name
|
314 |
+
* @param int $index The index if it is an embedded template
|
315 |
+
*
|
316 |
+
* @return Twig_TemplateInterface A template instance representing the given template name
|
317 |
+
*
|
318 |
+
* @throws Twig_Error_Loader When the template cannot be found
|
319 |
+
* @throws Twig_Error_Syntax When an error occurred during compilation
|
320 |
+
*/
|
321 |
+
public function loadTemplate($name, $index = null)
|
322 |
+
{
|
323 |
+
$cls = $this->getTemplateClass($name, $index);
|
324 |
+
|
325 |
+
if (isset($this->loadedTemplates[$cls])) {
|
326 |
+
return $this->loadedTemplates[$cls];
|
327 |
+
}
|
328 |
+
|
329 |
+
if (!class_exists($cls, false)) {
|
330 |
+
if (false === $cache = $this->getCacheFilename($name)) {
|
331 |
+
eval('?>'.$this->compileSource($this->getLoader()->getSource($name), $name));
|
332 |
+
} else {
|
333 |
+
if (!is_file($cache) || ($this->isAutoReload() && !$this->isTemplateFresh($name, filemtime($cache)))) {
|
334 |
+
$this->writeCacheFile($cache, $this->compileSource($this->getLoader()->getSource($name), $name));
|
335 |
+
}
|
336 |
+
|
337 |
+
require_once $cache;
|
338 |
+
}
|
339 |
+
}
|
340 |
+
|
341 |
+
if (!$this->runtimeInitialized) {
|
342 |
+
$this->initRuntime();
|
343 |
+
}
|
344 |
+
|
345 |
+
return $this->loadedTemplates[$cls] = new $cls($this);
|
346 |
+
}
|
347 |
+
|
348 |
+
/**
|
349 |
+
* Returns true if the template is still fresh.
|
350 |
+
*
|
351 |
+
* Besides checking the loader for freshness information,
|
352 |
+
* this method also checks if the enabled extensions have
|
353 |
+
* not changed.
|
354 |
+
*
|
355 |
+
* @param string $name The template name
|
356 |
+
* @param timestamp $time The last modification time of the cached template
|
357 |
+
*
|
358 |
+
* @return bool true if the template is fresh, false otherwise
|
359 |
+
*/
|
360 |
+
public function isTemplateFresh($name, $time)
|
361 |
+
{
|
362 |
+
foreach ($this->extensions as $extension) {
|
363 |
+
$r = new ReflectionObject($extension);
|
364 |
+
if (filemtime($r->getFileName()) > $time) {
|
365 |
+
return false;
|
366 |
+
}
|
367 |
+
}
|
368 |
+
|
369 |
+
return $this->getLoader()->isFresh($name, $time);
|
370 |
+
}
|
371 |
+
|
372 |
+
/**
|
373 |
+
* Tries to load a template consecutively from an array.
|
374 |
+
*
|
375 |
+
* Similar to loadTemplate() but it also accepts Twig_TemplateInterface instances and an array
|
376 |
+
* of templates where each is tried to be loaded.
|
377 |
+
*
|
378 |
+
* @param string|Twig_Template|array $names A template or an array of templates to try consecutively
|
379 |
+
*
|
380 |
+
* @return Twig_Template
|
381 |
+
*
|
382 |
+
* @throws Twig_Error_Loader When none of the templates can be found
|
383 |
+
* @throws Twig_Error_Syntax When an error occurred during compilation
|
384 |
+
*/
|
385 |
+
public function resolveTemplate($names)
|
386 |
+
{
|
387 |
+
if (!is_array($names)) {
|
388 |
+
$names = array($names);
|
389 |
+
}
|
390 |
+
|
391 |
+
foreach ($names as $name) {
|
392 |
+
if ($name instanceof Twig_Template) {
|
393 |
+
return $name;
|
394 |
+
}
|
395 |
+
|
396 |
+
try {
|
397 |
+
return $this->loadTemplate($name);
|
398 |
+
} catch (Twig_Error_Loader $e) {
|
399 |
+
}
|
400 |
+
}
|
401 |
+
|
402 |
+
if (1 === count($names)) {
|
403 |
+
throw $e;
|
404 |
+
}
|
405 |
+
|
406 |
+
throw new Twig_Error_Loader(sprintf('Unable to find one of the following templates: "%s".', implode('", "', $names)));
|
407 |
+
}
|
408 |
+
|
409 |
+
/**
|
410 |
+
* Clears the internal template cache.
|
411 |
+
*/
|
412 |
+
public function clearTemplateCache()
|
413 |
+
{
|
414 |
+
$this->loadedTemplates = array();
|
415 |
+
}
|
416 |
+
|
417 |
+
/**
|
418 |
+
* Clears the template cache files on the filesystem.
|
419 |
+
*/
|
420 |
+
public function clearCacheFiles()
|
421 |
+
{
|
422 |
+
if (false === $this->cache) {
|
423 |
+
return;
|
424 |
+
}
|
425 |
+
|
426 |
+
foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($this->cache), RecursiveIteratorIterator::LEAVES_ONLY) as $file) {
|
427 |
+
if ($file->isFile()) {
|
428 |
+
@unlink($file->getPathname());
|
429 |
+
}
|
430 |
+
}
|
431 |
+
}
|
432 |
+
|
433 |
+
/**
|
434 |
+
* Gets the Lexer instance.
|
435 |
+
*
|
436 |
+
* @return Twig_LexerInterface A Twig_LexerInterface instance
|
437 |
+
*/
|
438 |
+
public function getLexer()
|
439 |
+
{
|
440 |
+
if (null === $this->lexer) {
|
441 |
+
$this->lexer = new Twig_Lexer($this);
|
442 |
+
}
|
443 |
+
|
444 |
+
return $this->lexer;
|
445 |
+
}
|
446 |
+
|
447 |
+
/**
|
448 |
+
* Sets the Lexer instance.
|
449 |
+
*
|
450 |
+
* @param Twig_LexerInterface A Twig_LexerInterface instance
|
451 |
+
*/
|
452 |
+
public function setLexer(Twig_LexerInterface $lexer)
|
453 |
+
{
|
454 |
+
$this->lexer = $lexer;
|
455 |
+
}
|
456 |
+
|
457 |
+
/**
|
458 |
+
* Tokenizes a source code.
|
459 |
+
*
|
460 |
+
* @param string $source The template source code
|
461 |
+
* @param string $name The template name
|
462 |
+
*
|
463 |
+
* @return Twig_TokenStream A Twig_TokenStream instance
|
464 |
+
*
|
465 |
+
* @throws Twig_Error_Syntax When the code is syntactically wrong
|
466 |
+
*/
|
467 |
+
public function tokenize($source, $name = null)
|
468 |
+
{
|
469 |
+
return $this->getLexer()->tokenize($source, $name);
|
470 |
+
}
|
471 |
+
|
472 |
+
/**
|
473 |
+
* Gets the Parser instance.
|
474 |
+
*
|
475 |
+
* @return Twig_ParserInterface A Twig_ParserInterface instance
|
476 |
+
*/
|
477 |
+
public function getParser()
|
478 |
+
{
|
479 |
+
if (null === $this->parser) {
|
480 |
+
$this->parser = new Twig_Parser($this);
|
481 |
+
}
|
482 |
+
|
483 |
+
return $this->parser;
|
484 |
+
}
|
485 |
+
|
486 |
+
/**
|
487 |
+
* Sets the Parser instance.
|
488 |
+
*
|
489 |
+
* @param Twig_ParserInterface A Twig_ParserInterface instance
|
490 |
+
*/
|
491 |
+
public function setParser(Twig_ParserInterface $parser)
|
492 |
+
{
|
493 |
+
$this->parser = $parser;
|
494 |
+
}
|
495 |
+
|
496 |
+
/**
|
497 |
+
* Converts a token stream to a node tree.
|
498 |
+
*
|
499 |
+
* @param Twig_TokenStream $stream A token stream instance
|
500 |
+
*
|
501 |
+
* @return Twig_Node_Module A node tree
|
502 |
+
*
|
503 |
+
* @throws Twig_Error_Syntax When the token stream is syntactically or semantically wrong
|
504 |
+
*/
|
505 |
+
public function parse(Twig_TokenStream $stream)
|
506 |
+
{
|
507 |
+
return $this->getParser()->parse($stream);
|
508 |
+
}
|
509 |
+
|
510 |
+
/**
|
511 |
+
* Gets the Compiler instance.
|
512 |
+
*
|
513 |
+
* @return Twig_CompilerInterface A Twig_CompilerInterface instance
|
514 |
+
*/
|
515 |
+
public function getCompiler()
|
516 |
+
{
|
517 |
+
if (null === $this->compiler) {
|
518 |
+
$this->compiler = new Twig_Compiler($this);
|
519 |
+
}
|
520 |
+
|
521 |
+
return $this->compiler;
|
522 |
+
}
|
523 |
+
|
524 |
+
/**
|
525 |
+
* Sets the Compiler instance.
|
526 |
+
*
|
527 |
+
* @param Twig_CompilerInterface $compiler A Twig_CompilerInterface instance
|
528 |
+
*/
|
529 |
+
public function setCompiler(Twig_CompilerInterface $compiler)
|
530 |
+
{
|
531 |
+
$this->compiler = $compiler;
|
532 |
+
}
|
533 |
+
|
534 |
+
/**
|
535 |
+
* Compiles a node and returns the PHP code.
|
536 |
+
*
|
537 |
+
* @param Twig_NodeInterface $node A Twig_NodeInterface instance
|
538 |
+
*
|
539 |
+
* @return string The compiled PHP source code
|
540 |
+
*/
|
541 |
+
public function compile(Twig_NodeInterface $node)
|
542 |
+
{
|
543 |
+
return $this->getCompiler()->compile($node)->getSource();
|
544 |
+
}
|
545 |
+
|
546 |
+
/**
|
547 |
+
* Compiles a template source code.
|
548 |
+
*
|
549 |
+
* @param string $source The template source code
|
550 |
+
* @param string $name The template name
|
551 |
+
*
|
552 |
+
* @return string The compiled PHP source code
|
553 |
+
*
|
554 |
+
* @throws Twig_Error_Syntax When there was an error during tokenizing, parsing or compiling
|
555 |
+
*/
|
556 |
+
public function compileSource($source, $name = null)
|
557 |
+
{
|
558 |
+
try {
|
559 |
+
return $this->compile($this->parse($this->tokenize($source, $name)));
|
560 |
+
} catch (Twig_Error $e) {
|
561 |
+
$e->setTemplateFile($name);
|
562 |
+
throw $e;
|
563 |
+
} catch (Exception $e) {
|
564 |
+
throw new Twig_Error_Syntax(sprintf('An exception has been thrown during the compilation of a template ("%s").', $e->getMessage()), -1, $name, $e);
|
565 |
+
}
|
566 |
+
}
|
567 |
+
|
568 |
+
/**
|
569 |
+
* Sets the Loader instance.
|
570 |
+
*
|
571 |
+
* @param Twig_LoaderInterface $loader A Twig_LoaderInterface instance
|
572 |
+
*/
|
573 |
+
public function setLoader(Twig_LoaderInterface $loader)
|
574 |
+
{
|
575 |
+
$this->loader = $loader;
|
576 |
+
}
|
577 |
+
|
578 |
+
/**
|
579 |
+
* Gets the Loader instance.
|
580 |
+
*
|
581 |
+
* @return Twig_LoaderInterface A Twig_LoaderInterface instance
|
582 |
+
*/
|
583 |
+
public function getLoader()
|
584 |
+
{
|
585 |
+
if (null === $this->loader) {
|
586 |
+
throw new LogicException('You must set a loader first.');
|
587 |
+
}
|
588 |
+
|
589 |
+
return $this->loader;
|
590 |
+
}
|
591 |
+
|
592 |
+
/**
|
593 |
+
* Sets the default template charset.
|
594 |
+
*
|
595 |
+
* @param string $charset The default charset
|
596 |
+
*/
|
597 |
+
public function setCharset($charset)
|
598 |
+
{
|
599 |
+
$this->charset = strtoupper($charset);
|
600 |
+
}
|
601 |
+
|
602 |
+
/**
|
603 |
+
* Gets the default template charset.
|
604 |
+
*
|
605 |
+
* @return string The default charset
|
606 |
+
*/
|
607 |
+
public function getCharset()
|
608 |
+
{
|
609 |
+
return $this->charset;
|
610 |
+
}
|
611 |
+
|
612 |
+
/**
|
613 |
+
* Initializes the runtime environment.
|
614 |
+
*/
|
615 |
+
public function initRuntime()
|
616 |
+
{
|
617 |
+
$this->runtimeInitialized = true;
|
618 |
+
|
619 |
+
foreach ($this->getExtensions() as $extension) {
|
620 |
+
$extension->initRuntime($this);
|
621 |
+
}
|
622 |
+
}
|
623 |
+
|
624 |
+
/**
|
625 |
+
* Returns true if the given extension is registered.
|
626 |
+
*
|
627 |
+
* @param string $name The extension name
|
628 |
+
*
|
629 |
+
* @return bool Whether the extension is registered or not
|
630 |
+
*/
|
631 |
+
public function hasExtension($name)
|
632 |
+
{
|
633 |
+
return isset($this->extensions[$name]);
|
634 |
+
}
|
635 |
+
|
636 |
+
/**
|
637 |
+
* Gets an extension by name.
|
638 |
+
*
|
639 |
+
* @param string $name The extension name
|
640 |
+
*
|
641 |
+
* @return Twig_ExtensionInterface A Twig_ExtensionInterface instance
|
642 |
+
*/
|
643 |
+
public function getExtension($name)
|
644 |
+
{
|
645 |
+
if (!isset($this->extensions[$name])) {
|
646 |
+
throw new Twig_Error_Runtime(sprintf('The "%s" extension is not enabled.', $name));
|
647 |
+
}
|
648 |
+
|
649 |
+
return $this->extensions[$name];
|
650 |
+
}
|
651 |
+
|
652 |
+
/**
|
653 |
+
* Registers an extension.
|
654 |
+
*
|
655 |
+
* @param Twig_ExtensionInterface $extension A Twig_ExtensionInterface instance
|
656 |
+
*/
|
657 |
+
public function addExtension(Twig_ExtensionInterface $extension)
|
658 |
+
{
|
659 |
+
if ($this->extensionInitialized) {
|
660 |
+
throw new LogicException(sprintf('Unable to register extension "%s" as extensions have already been initialized.', $extension->getName()));
|
661 |
+
}
|
662 |
+
|
663 |
+
$this->extensions[$extension->getName()] = $extension;
|
664 |
+
}
|
665 |
+
|
666 |
+
/**
|
667 |
+
* Removes an extension by name.
|
668 |
+
*
|
669 |
+
* This method is deprecated and you should not use it.
|
670 |
+
*
|
671 |
+
* @param string $name The extension name
|
672 |
+
*
|
673 |
+
* @deprecated since 1.12 (to be removed in 2.0)
|
674 |
+
*/
|
675 |
+
public function removeExtension($name)
|
676 |
+
{
|
677 |
+
if ($this->extensionInitialized) {
|
678 |
+
throw new LogicException(sprintf('Unable to remove extension "%s" as extensions have already been initialized.', $name));
|
679 |
+
}
|
680 |
+
|
681 |
+
unset($this->extensions[$name]);
|
682 |
+
}
|
683 |
+
|
684 |
+
/**
|
685 |
+
* Registers an array of extensions.
|
686 |
+
*
|
687 |
+
* @param array $extensions An array of extensions
|
688 |
+
*/
|
689 |
+
public function setExtensions(array $extensions)
|
690 |
+
{
|
691 |
+
foreach ($extensions as $extension) {
|
692 |
+
$this->addExtension($extension);
|
693 |
+
}
|
694 |
+
}
|
695 |
+
|
696 |
+
/**
|
697 |
+
* Returns all registered extensions.
|
698 |
+
*
|
699 |
+
* @return array An array of extensions
|
700 |
+
*/
|
701 |
+
public function getExtensions()
|
702 |
+
{
|
703 |
+
return $this->extensions;
|
704 |
+
}
|
705 |
+
|
706 |
+
/**
|
707 |
+
* Registers a Token Parser.
|
708 |
+
*
|
709 |
+
* @param Twig_TokenParserInterface $parser A Twig_TokenParserInterface instance
|
710 |
+
*/
|
711 |
+
public function addTokenParser(Twig_TokenParserInterface $parser)
|
712 |
+
{
|
713 |
+
if ($this->extensionInitialized) {
|
714 |
+
throw new LogicException('Unable to add a token parser as extensions have already been initialized.');
|
715 |
+
}
|
716 |
+
|
717 |
+
$this->staging->addTokenParser($parser);
|
718 |
+
}
|
719 |
+
|
720 |
+
/**
|
721 |
+
* Gets the registered Token Parsers.
|
722 |
+
*
|
723 |
+
* @return Twig_TokenParserBrokerInterface A broker containing token parsers
|
724 |
+
*/
|
725 |
+
public function getTokenParsers()
|
726 |
+
{
|
727 |
+
if (!$this->extensionInitialized) {
|
728 |
+
$this->initExtensions();
|
729 |
+
}
|
730 |
+
|
731 |
+
return $this->parsers;
|
732 |
+
}
|
733 |
+
|
734 |
+
/**
|
735 |
+
* Gets registered tags.
|
736 |
+
*
|
737 |
+
* Be warned that this method cannot return tags defined by Twig_TokenParserBrokerInterface classes.
|
738 |
+
*
|
739 |
+
* @return Twig_TokenParserInterface[] An array of Twig_TokenParserInterface instances
|
740 |
+
*/
|
741 |
+
public function getTags()
|
742 |
+
{
|
743 |
+
$tags = array();
|
744 |
+
foreach ($this->getTokenParsers()->getParsers() as $parser) {
|
745 |
+
if ($parser instanceof Twig_TokenParserInterface) {
|
746 |
+
$tags[$parser->getTag()] = $parser;
|
747 |
+
}
|
748 |
+
}
|
749 |
+
|
750 |
+
return $tags;
|
751 |
+
}
|
752 |
+
|
753 |
+
/**
|
754 |
+
* Registers a Node Visitor.
|
755 |
+
*
|
756 |
+
* @param Twig_NodeVisitorInterface $visitor A Twig_NodeVisitorInterface instance
|
757 |
+
*/
|
758 |
+
public function addNodeVisitor(Twig_NodeVisitorInterface $visitor)
|
759 |
+
{
|
760 |
+
if ($this->extensionInitialized) {
|
761 |
+
throw new LogicException('Unable to add a node visitor as extensions have already been initialized.');
|
762 |
+
}
|
763 |
+
|
764 |
+
$this->staging->addNodeVisitor($visitor);
|
765 |
+
}
|
766 |
+
|
767 |
+
/**
|
768 |
+
* Gets the registered Node Visitors.
|
769 |
+
*
|
770 |
+
* @return Twig_NodeVisitorInterface[] An array of Twig_NodeVisitorInterface instances
|
771 |
+
*/
|
772 |
+
public function getNodeVisitors()
|
773 |
+
{
|
774 |
+
if (!$this->extensionInitialized) {
|
775 |
+
$this->initExtensions();
|
776 |
+
}
|
777 |
+
|
778 |
+
return $this->visitors;
|
779 |
+
}
|
780 |
+
|
781 |
+
/**
|
782 |
+
* Registers a Filter.
|
783 |
+
*
|
784 |
+
* @param string|Twig_SimpleFilter $name The filter name or a Twig_SimpleFilter instance
|
785 |
+
* @param Twig_FilterInterface|Twig_SimpleFilter $filter A Twig_FilterInterface instance or a Twig_SimpleFilter instance
|
786 |
+
*/
|
787 |
+
public function addFilter($name, $filter = null)
|
788 |
+
{
|
789 |
+
if (!$name instanceof Twig_SimpleFilter && !($filter instanceof Twig_SimpleFilter || $filter instanceof Twig_FilterInterface)) {
|
790 |
+
throw new LogicException('A filter must be an instance of Twig_FilterInterface or Twig_SimpleFilter');
|
791 |
+
}
|
792 |
+
|
793 |
+
if ($name instanceof Twig_SimpleFilter) {
|
794 |
+
$filter = $name;
|
795 |
+
$name = $filter->getName();
|
796 |
+
}
|
797 |
+
|
798 |
+
if ($this->extensionInitialized) {
|
799 |
+
throw new LogicException(sprintf('Unable to add filter "%s" as extensions have already been initialized.', $name));
|
800 |
+
}
|
801 |
+
|
802 |
+
$this->staging->addFilter($name, $filter);
|
803 |
+
}
|
804 |
+
|
805 |
+
/**
|
806 |
+
* Get a filter by name.
|
807 |
+
*
|
808 |
+
* Subclasses may override this method and load filters differently;
|
809 |
+
* so no list of filters is available.
|
810 |
+
*
|
811 |
+
* @param string $name The filter name
|
812 |
+
*
|
813 |
+
* @return Twig_Filter|false A Twig_Filter instance or false if the filter does not exist
|
814 |
+
*/
|
815 |
+
public function getFilter($name)
|
816 |
+
{
|
817 |
+
if (!$this->extensionInitialized) {
|
818 |
+
$this->initExtensions();
|
819 |
+
}
|
820 |
+
|
821 |
+
if (isset($this->filters[$name])) {
|
822 |
+
return $this->filters[$name];
|
823 |
+
}
|
824 |
+
|
825 |
+
foreach ($this->filters as $pattern => $filter) {
|
826 |
+
$pattern = str_replace('\\*', '(.*?)', preg_quote($pattern, '#'), $count);
|
827 |
+
|
828 |
+
if ($count) {
|
829 |
+
if (preg_match('#^'.$pattern.'$#', $name, $matches)) {
|
830 |
+
array_shift($matches);
|
831 |
+
$filter->setArguments($matches);
|
832 |
+
|
833 |
+
return $filter;
|
834 |
+
}
|
835 |
+
}
|
836 |
+
}
|
837 |
+
|
838 |
+
foreach ($this->filterCallbacks as $callback) {
|
839 |
+
if (false !== $filter = call_user_func($callback, $name)) {
|
840 |
+
return $filter;
|
841 |
+
}
|
842 |
+
}
|
843 |
+
|
844 |
+
return false;
|
845 |
+
}
|
846 |
+
|
847 |
+
public function registerUndefinedFilterCallback($callable)
|
848 |
+
{
|
849 |
+
$this->filterCallbacks[] = $callable;
|
850 |
+
}
|
851 |
+
|
852 |
+
/**
|
853 |
+
* Gets the registered Filters.
|
854 |
+
*
|
855 |
+
* Be warned that this method cannot return filters defined with registerUndefinedFunctionCallback.
|
856 |
+
*
|
857 |
+
* @return Twig_FilterInterface[] An array of Twig_FilterInterface instances
|
858 |
+
*
|
859 |
+
* @see registerUndefinedFilterCallback
|
860 |
+
*/
|
861 |
+
public function getFilters()
|
862 |
+
{
|
863 |
+
if (!$this->extensionInitialized) {
|
864 |
+
$this->initExtensions();
|
865 |
+
}
|
866 |
+
|
867 |
+
return $this->filters;
|
868 |
+
}
|
869 |
+
|
870 |
+
/**
|
871 |
+
* Registers a Test.
|
872 |
+
*
|
873 |
+
* @param string|Twig_SimpleTest $name The test name or a Twig_SimpleTest instance
|
874 |
+
* @param Twig_TestInterface|Twig_SimpleTest $test A Twig_TestInterface instance or a Twig_SimpleTest instance
|
875 |
+
*/
|
876 |
+
public function addTest($name, $test = null)
|
877 |
+
{
|
878 |
+
if (!$name instanceof Twig_SimpleTest && !($test instanceof Twig_SimpleTest || $test instanceof Twig_TestInterface)) {
|
879 |
+
throw new LogicException('A test must be an instance of Twig_TestInterface or Twig_SimpleTest');
|
880 |
+
}
|
881 |
+
|
882 |
+
if ($name instanceof Twig_SimpleTest) {
|
883 |
+
$test = $name;
|
884 |
+
$name = $test->getName();
|
885 |
+
}
|
886 |
+
|
887 |
+
if ($this->extensionInitialized) {
|
888 |
+
throw new LogicException(sprintf('Unable to add test "%s" as extensions have already been initialized.', $name));
|
889 |
+
}
|
890 |
+
|
891 |
+
$this->staging->addTest($name, $test);
|
892 |
+
}
|
893 |
+
|
894 |
+
/**
|
895 |
+
* Gets the registered Tests.
|
896 |
+
*
|
897 |
+
* @return Twig_TestInterface[] An array of Twig_TestInterface instances
|
898 |
+
*/
|
899 |
+
public function getTests()
|
900 |
+
{
|
901 |
+
if (!$this->extensionInitialized) {
|
902 |
+
$this->initExtensions();
|
903 |
+
}
|
904 |
+
|
905 |
+
return $this->tests;
|
906 |
+
}
|
907 |
+
|
908 |
+
/**
|
909 |
+
* Gets a test by name.
|
910 |
+
*
|
911 |
+
* @param string $name The test name
|
912 |
+
*
|
913 |
+
* @return Twig_Test|false A Twig_Test instance or false if the test does not exist
|
914 |
+
*/
|
915 |
+
public function getTest($name)
|
916 |
+
{
|
917 |
+
if (!$this->extensionInitialized) {
|
918 |
+
$this->initExtensions();
|
919 |
+
}
|
920 |
+
|
921 |
+
if (isset($this->tests[$name])) {
|
922 |
+
return $this->tests[$name];
|
923 |
+
}
|
924 |
+
|
925 |
+
return false;
|
926 |
+
}
|
927 |
+
|
928 |
+
/**
|
929 |
+
* Registers a Function.
|
930 |
+
*
|
931 |
+
* @param string|Twig_SimpleFunction $name The function name or a Twig_SimpleFunction instance
|
932 |
+
* @param Twig_FunctionInterface|Twig_SimpleFunction $function A Twig_FunctionInterface instance or a Twig_SimpleFunction instance
|
933 |
+
*/
|
934 |
+
public function addFunction($name, $function = null)
|
935 |
+
{
|
936 |
+
if (!$name instanceof Twig_SimpleFunction && !($function instanceof Twig_SimpleFunction || $function instanceof Twig_FunctionInterface)) {
|
937 |
+
throw new LogicException('A function must be an instance of Twig_FunctionInterface or Twig_SimpleFunction');
|
938 |
+
}
|
939 |
+
|
940 |
+
if ($name instanceof Twig_SimpleFunction) {
|
941 |
+
$function = $name;
|
942 |
+
$name = $function->getName();
|
943 |
+
}
|
944 |
+
|
945 |
+
if ($this->extensionInitialized) {
|
946 |
+
throw new LogicException(sprintf('Unable to add function "%s" as extensions have already been initialized.', $name));
|
947 |
+
}
|
948 |
+
|
949 |
+
$this->staging->addFunction($name, $function);
|
950 |
+
}
|
951 |
+
|
952 |
+
/**
|
953 |
+
* Get a function by name.
|
954 |
+
*
|
955 |
+
* Subclasses may override this method and load functions differently;
|
956 |
+
* so no list of functions is available.
|
957 |
+
*
|
958 |
+
* @param string $name function name
|
959 |
+
*
|
960 |
+
* @return Twig_Function|false A Twig_Function instance or false if the function does not exist
|
961 |
+
*/
|
962 |
+
public function getFunction($name)
|
963 |
+
{
|
964 |
+
if (!$this->extensionInitialized) {
|
965 |
+
$this->initExtensions();
|
966 |
+
}
|
967 |
+
|
968 |
+
if (isset($this->functions[$name])) {
|
969 |
+
return $this->functions[$name];
|
970 |
+
}
|
971 |
+
|
972 |
+
foreach ($this->functions as $pattern => $function) {
|
973 |
+
$pattern = str_replace('\\*', '(.*?)', preg_quote($pattern, '#'), $count);
|
974 |
+
|
975 |
+
if ($count) {
|
976 |
+
if (preg_match('#^'.$pattern.'$#', $name, $matches)) {
|
977 |
+
array_shift($matches);
|
978 |
+
$function->setArguments($matches);
|
979 |
+
|
980 |
+
return $function;
|
981 |
+
}
|
982 |
+
}
|
983 |
+
}
|
984 |
+
|
985 |
+
foreach ($this->functionCallbacks as $callback) {
|
986 |
+
if (false !== $function = call_user_func($callback, $name)) {
|
987 |
+
return $function;
|
988 |
+
}
|
989 |
+
}
|
990 |
+
|
991 |
+
return false;
|
992 |
+
}
|
993 |
+
|
994 |
+
public function registerUndefinedFunctionCallback($callable)
|
995 |
+
{
|
996 |
+
$this->functionCallbacks[] = $callable;
|
997 |
+
}
|
998 |
+
|
999 |
+
/**
|
1000 |
+
* Gets registered functions.
|
1001 |
+
*
|
1002 |
+
* Be warned that this method cannot return functions defined with registerUndefinedFunctionCallback.
|
1003 |
+
*
|
1004 |
+
* @return Twig_FunctionInterface[] An array of Twig_FunctionInterface instances
|
1005 |
+
*
|
1006 |
+
* @see registerUndefinedFunctionCallback
|
1007 |
+
*/
|
1008 |
+
public function getFunctions()
|
1009 |
+
{
|
1010 |
+
if (!$this->extensionInitialized) {
|
1011 |
+
$this->initExtensions();
|
1012 |
+
}
|
1013 |
+
|
1014 |
+
return $this->functions;
|
1015 |
+
}
|
1016 |
+
|
1017 |
+
/**
|
1018 |
+
* Registers a Global.
|
1019 |
+
*
|
1020 |
+
* New globals can be added before compiling or rendering a template;
|
1021 |
+
* but after, you can only update existing globals.
|
1022 |
+
*
|
1023 |
+
* @param string $name The global name
|
1024 |
+
* @param mixed $value The global value
|
1025 |
+
*/
|
1026 |
+
public function addGlobal($name, $value)
|
1027 |
+
{
|
1028 |
+
if ($this->extensionInitialized || $this->runtimeInitialized) {
|
1029 |
+
if (null === $this->globals) {
|
1030 |
+
$this->globals = $this->initGlobals();
|
1031 |
+
}
|
1032 |
+
|
1033 |
+
/* This condition must be uncommented in Twig 2.0
|
1034 |
+
if (!array_key_exists($name, $this->globals)) {
|
1035 |
+
throw new LogicException(sprintf('Unable to add global "%s" as the runtime or the extensions have already been initialized.', $name));
|
1036 |
+
}
|
1037 |
+
*/
|
1038 |
+
}
|
1039 |
+
|
1040 |
+
if ($this->extensionInitialized || $this->runtimeInitialized) {
|
1041 |
+
// update the value
|
1042 |
+
$this->globals[$name] = $value;
|
1043 |
+
} else {
|
1044 |
+
$this->staging->addGlobal($name, $value);
|
1045 |
+
}
|
1046 |
+
}
|
1047 |
+
|
1048 |
+
/**
|
1049 |
+
* Gets the registered Globals.
|
1050 |
+
*
|
1051 |
+
* @return array An array of globals
|
1052 |
+
*/
|
1053 |
+
public function getGlobals()
|
1054 |
+
{
|
1055 |
+
if (!$this->runtimeInitialized && !$this->extensionInitialized) {
|
1056 |
+
return $this->initGlobals();
|
1057 |
+
}
|
1058 |
+
|
1059 |
+
if (null === $this->globals) {
|
1060 |
+
$this->globals = $this->initGlobals();
|
1061 |
+
}
|
1062 |
+
|
1063 |
+
return $this->globals;
|
1064 |
+
}
|
1065 |
+
|
1066 |
+
/**
|
1067 |
+
* Merges a context with the defined globals.
|
1068 |
+
*
|
1069 |
+
* @param array $context An array representing the context
|
1070 |
+
*
|
1071 |
+
* @return array The context merged with the globals
|
1072 |
+
*/
|
1073 |
+
public function mergeGlobals(array $context)
|
1074 |
+
{
|
1075 |
+
// we don't use array_merge as the context being generally
|
1076 |
+
// bigger than globals, this code is faster.
|
1077 |
+
foreach ($this->getGlobals() as $key => $value) {
|
1078 |
+
if (!array_key_exists($key, $context)) {
|
1079 |
+
$context[$key] = $value;
|
1080 |
+
}
|
1081 |
+
}
|
1082 |
+
|
1083 |
+
return $context;
|
1084 |
+
}
|
1085 |
+
|
1086 |
+
/**
|
1087 |
+
* Gets the registered unary Operators.
|
1088 |
+
*
|
1089 |
+
* @return array An array of unary operators
|
1090 |
+
*/
|
1091 |
+
public function getUnaryOperators()
|
1092 |
+
{
|
1093 |
+
if (!$this->extensionInitialized) {
|
1094 |
+
$this->initExtensions();
|
1095 |
+
}
|
1096 |
+
|
1097 |
+
return $this->unaryOperators;
|
1098 |
+
}
|
1099 |
+
|
1100 |
+
/**
|
1101 |
+
* Gets the registered binary Operators.
|
1102 |
+
*
|
1103 |
+
* @return array An array of binary operators
|
1104 |
+
*/
|
1105 |
+
public function getBinaryOperators()
|
1106 |
+
{
|
1107 |
+
if (!$this->extensionInitialized) {
|
1108 |
+
$this->initExtensions();
|
1109 |
+
}
|
1110 |
+
|
1111 |
+
return $this->binaryOperators;
|
1112 |
+
}
|
1113 |
+
|
1114 |
+
public function computeAlternatives($name, $items)
|
1115 |
+
{
|
1116 |
+
$alternatives = array();
|
1117 |
+
foreach ($items as $item) {
|
1118 |
+
$lev = levenshtein($name, $item);
|
1119 |
+
if ($lev <= strlen($name) / 3 || false !== strpos($item, $name)) {
|
1120 |
+
$alternatives[$item] = $lev;
|
1121 |
+
}
|
1122 |
+
}
|
1123 |
+
asort($alternatives);
|
1124 |
+
|
1125 |
+
return array_keys($alternatives);
|
1126 |
+
}
|
1127 |
+
|
1128 |
+
protected function initGlobals()
|
1129 |
+
{
|
1130 |
+
$globals = array();
|
1131 |
+
foreach ($this->extensions as $extension) {
|
1132 |
+
$extGlob = $extension->getGlobals();
|
1133 |
+
if (!is_array($extGlob)) {
|
1134 |
+
throw new UnexpectedValueException(sprintf('"%s::getGlobals()" must return an array of globals.', get_class($extension)));
|
1135 |
+
}
|
1136 |
+
|
1137 |
+
$globals[] = $extGlob;
|
1138 |
+
}
|
1139 |
+
|
1140 |
+
$globals[] = $this->staging->getGlobals();
|
1141 |
+
|
1142 |
+
return call_user_func_array('array_merge', $globals);
|
1143 |
+
}
|
1144 |
+
|
1145 |
+
protected function initExtensions()
|
1146 |
+
{
|
1147 |
+
if ($this->extensionInitialized) {
|
1148 |
+
return;
|
1149 |
+
}
|
1150 |
+
|
1151 |
+
$this->extensionInitialized = true;
|
1152 |
+
$this->parsers = new Twig_TokenParserBroker();
|
1153 |
+
$this->filters = array();
|
1154 |
+
$this->functions = array();
|
1155 |
+
$this->tests = array();
|
1156 |
+
$this->visitors = array();
|
1157 |
+
$this->unaryOperators = array();
|
1158 |
+
$this->binaryOperators = array();
|
1159 |
+
|
1160 |
+
foreach ($this->extensions as $extension) {
|
1161 |
+
$this->initExtension($extension);
|
1162 |
+
}
|
1163 |
+
$this->initExtension($this->staging);
|
1164 |
+
}
|
1165 |
+
|
1166 |
+
protected function initExtension(Twig_ExtensionInterface $extension)
|
1167 |
+
{
|
1168 |
+
// filters
|
1169 |
+
foreach ($extension->getFilters() as $name => $filter) {
|
1170 |
+
if ($name instanceof Twig_SimpleFilter) {
|
1171 |
+
$filter = $name;
|
1172 |
+
$name = $filter->getName();
|
1173 |
+
} elseif ($filter instanceof Twig_SimpleFilter) {
|
1174 |
+
$name = $filter->getName();
|
1175 |
+
}
|
1176 |
+
|
1177 |
+
$this->filters[$name] = $filter;
|
1178 |
+
}
|
1179 |
+
|
1180 |
+
// functions
|
1181 |
+
foreach ($extension->getFunctions() as $name => $function) {
|
1182 |
+
if ($name instanceof Twig_SimpleFunction) {
|
1183 |
+
$function = $name;
|
1184 |
+
$name = $function->getName();
|
1185 |
+
} elseif ($function instanceof Twig_SimpleFunction) {
|
1186 |
+
$name = $function->getName();
|
1187 |
+
}
|
1188 |
+
|
1189 |
+
$this->functions[$name] = $function;
|
1190 |
+
}
|
1191 |
+
|
1192 |
+
// tests
|
1193 |
+
foreach ($extension->getTests() as $name => $test) {
|
1194 |
+
if ($name instanceof Twig_SimpleTest) {
|
1195 |
+
$test = $name;
|
1196 |
+
$name = $test->getName();
|
1197 |
+
} elseif ($test instanceof Twig_SimpleTest) {
|
1198 |
+
$name = $test->getName();
|
1199 |
+
}
|
1200 |
+
|
1201 |
+
$this->tests[$name] = $test;
|
1202 |
+
}
|
1203 |
+
|
1204 |
+
// token parsers
|
1205 |
+
foreach ($extension->getTokenParsers() as $parser) {
|
1206 |
+
if ($parser instanceof Twig_TokenParserInterface) {
|
1207 |
+
$this->parsers->addTokenParser($parser);
|
1208 |
+
} elseif ($parser instanceof Twig_TokenParserBrokerInterface) {
|
1209 |
+
$this->parsers->addTokenParserBroker($parser);
|
1210 |
+
} else {
|
1211 |
+
throw new LogicException('getTokenParsers() must return an array of Twig_TokenParserInterface or Twig_TokenParserBrokerInterface instances');
|
1212 |
+
}
|
1213 |
+
}
|
1214 |
+
|
1215 |
+
// node visitors
|
1216 |
+
foreach ($extension->getNodeVisitors() as $visitor) {
|
1217 |
+
$this->visitors[] = $visitor;
|
1218 |
+
}
|
1219 |
+
|
1220 |
+
// operators
|
1221 |
+
if ($operators = $extension->getOperators()) {
|
1222 |
+
if (2 !== count($operators)) {
|
1223 |
+
throw new InvalidArgumentException(sprintf('"%s::getOperators()" does not return a valid operators array.', get_class($extension)));
|
1224 |
+
}
|
1225 |
+
|
1226 |
+
$this->unaryOperators = array_merge($this->unaryOperators, $operators[0]);
|
1227 |
+
$this->binaryOperators = array_merge($this->binaryOperators, $operators[1]);
|
1228 |
+
}
|
1229 |
+
}
|
1230 |
+
|
1231 |
+
protected function writeCacheFile($file, $content)
|
1232 |
+
{
|
1233 |
+
$dir = dirname($file);
|
1234 |
+
if (!is_dir($dir)) {
|
1235 |
+
if (false === @mkdir($dir, 0777, true) && !is_dir($dir)) {
|
1236 |
+
throw new RuntimeException(sprintf("Unable to create the cache directory (%s).", $dir));
|
1237 |
+
}
|
1238 |
+
} elseif (!is_writable($dir)) {
|
1239 |
+
throw new RuntimeException(sprintf("Unable to write in the cache directory (%s).", $dir));
|
1240 |
+
}
|
1241 |
+
|
1242 |
+
$tmpFile = tempnam($dir, basename($file));
|
1243 |
+
if (false !== @file_put_contents($tmpFile, $content)) {
|
1244 |
+
// rename does not work on Win32 before 5.2.6
|
1245 |
+
if (@rename($tmpFile, $file) || (@copy($tmpFile, $file) && unlink($tmpFile))) {
|
1246 |
+
@chmod($file, 0666 & ~umask());
|
1247 |
+
|
1248 |
+
return;
|
1249 |
+
}
|
1250 |
+
}
|
1251 |
+
|
1252 |
+
throw new RuntimeException(sprintf('Failed to write cache file "%s".', $file));
|
1253 |
+
}
|
1254 |
+
}
|
classes/Twig/Error.php
CHANGED
@@ -1,248 +1,248 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2009 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
/**
|
13 |
-
* Twig base exception.
|
14 |
-
*
|
15 |
-
* This exception class and its children must only be used when
|
16 |
-
* an error occurs during the loading of a template, when a syntax error
|
17 |
-
* is detected in a template, or when rendering a template. Other
|
18 |
-
* errors must use regular PHP exception classes (like when the template
|
19 |
-
* cache directory is not writable for instance).
|
20 |
-
*
|
21 |
-
* To help debugging template issues, this class tracks the original template
|
22 |
-
* name and line where the error occurred.
|
23 |
-
*
|
24 |
-
* Whenever possible, you must set these information (original template name
|
25 |
-
* and line number) yourself by passing them to the constructor. If some or all
|
26 |
-
* these information are not available from where you throw the exception, then
|
27 |
-
* this class will guess them automatically (when the line number is set to -1
|
28 |
-
* and/or the filename is set to null). As this is a costly operation, this
|
29 |
-
* can be disabled by passing false for both the filename and the line number
|
30 |
-
* when creating a new instance of this class.
|
31 |
-
*
|
32 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
33 |
-
*/
|
34 |
-
class Twig_Error extends Exception
|
35 |
-
{
|
36 |
-
protected $lineno;
|
37 |
-
protected $filename;
|
38 |
-
protected $rawMessage;
|
39 |
-
protected $previous;
|
40 |
-
|
41 |
-
/**
|
42 |
-
* Constructor.
|
43 |
-
*
|
44 |
-
* Set both the line number and the filename to false to
|
45 |
-
* disable automatic guessing of the original template name
|
46 |
-
* and line number.
|
47 |
-
*
|
48 |
-
* Set the line number to -1 to enable its automatic guessing.
|
49 |
-
* Set the filename to null to enable its automatic guessing.
|
50 |
-
*
|
51 |
-
* By default, automatic guessing is enabled.
|
52 |
-
*
|
53 |
-
* @param string $message The error message
|
54 |
-
* @param int $lineno The template line where the error occurred
|
55 |
-
* @param string $filename The template file name where the error occurred
|
56 |
-
* @param Exception $previous The previous exception
|
57 |
-
*/
|
58 |
-
public function __construct($message, $lineno = -1, $filename = null, Exception $previous = null)
|
59 |
-
{
|
60 |
-
if (version_compare(PHP_VERSION, '5.3.0', '<')) {
|
61 |
-
$this->previous = $previous;
|
62 |
-
parent::__construct('');
|
63 |
-
} else {
|
64 |
-
parent::__construct('', 0, $previous);
|
65 |
-
}
|
66 |
-
|
67 |
-
$this->lineno = $lineno;
|
68 |
-
$this->filename = $filename;
|
69 |
-
|
70 |
-
if (-1 === $this->lineno || null === $this->filename) {
|
71 |
-
$this->guessTemplateInfo();
|
72 |
-
}
|
73 |
-
|
74 |
-
$this->rawMessage = $message;
|
75 |
-
|
76 |
-
$this->updateRepr();
|
77 |
-
}
|
78 |
-
|
79 |
-
/**
|
80 |
-
* Gets the raw message.
|
81 |
-
*
|
82 |
-
* @return string The raw message
|
83 |
-
*/
|
84 |
-
public function getRawMessage()
|
85 |
-
{
|
86 |
-
return $this->rawMessage;
|
87 |
-
}
|
88 |
-
|
89 |
-
/**
|
90 |
-
* Gets the filename where the error occurred.
|
91 |
-
*
|
92 |
-
* @return string The filename
|
93 |
-
*/
|
94 |
-
public function getTemplateFile()
|
95 |
-
{
|
96 |
-
return $this->filename;
|
97 |
-
}
|
98 |
-
|
99 |
-
/**
|
100 |
-
* Sets the filename where the error occurred.
|
101 |
-
*
|
102 |
-
* @param string $filename The filename
|
103 |
-
*/
|
104 |
-
public function setTemplateFile($filename)
|
105 |
-
{
|
106 |
-
$this->filename = $filename;
|
107 |
-
|
108 |
-
$this->updateRepr();
|
109 |
-
}
|
110 |
-
|
111 |
-
/**
|
112 |
-
* Gets the template line where the error occurred.
|
113 |
-
*
|
114 |
-
* @return int The template line
|
115 |
-
*/
|
116 |
-
public function getTemplateLine()
|
117 |
-
{
|
118 |
-
return $this->lineno;
|
119 |
-
}
|
120 |
-
|
121 |
-
/**
|
122 |
-
* Sets the template line where the error occurred.
|
123 |
-
*
|
124 |
-
* @param int $lineno The template line
|
125 |
-
*/
|
126 |
-
public function setTemplateLine($lineno)
|
127 |
-
{
|
128 |
-
$this->lineno = $lineno;
|
129 |
-
|
130 |
-
$this->updateRepr();
|
131 |
-
}
|
132 |
-
|
133 |
-
public function guess()
|
134 |
-
{
|
135 |
-
$this->guessTemplateInfo();
|
136 |
-
$this->updateRepr();
|
137 |
-
}
|
138 |
-
|
139 |
-
/**
|
140 |
-
* For PHP < 5.3.0, provides access to the getPrevious() method.
|
141 |
-
*
|
142 |
-
* @param string $method The method name
|
143 |
-
* @param array $arguments The parameters to be passed to the method
|
144 |
-
*
|
145 |
-
* @return Exception The previous exception or null
|
146 |
-
*
|
147 |
-
* @throws BadMethodCallException
|
148 |
-
*/
|
149 |
-
public function __call($method, $arguments)
|
150 |
-
{
|
151 |
-
if ('getprevious' == strtolower($method)) {
|
152 |
-
return $this->previous;
|
153 |
-
}
|
154 |
-
|
155 |
-
throw new BadMethodCallException(sprintf('Method "Twig_Error::%s()" does not exist.', $method));
|
156 |
-
}
|
157 |
-
|
158 |
-
protected function updateRepr()
|
159 |
-
{
|
160 |
-
$this->message = $this->rawMessage;
|
161 |
-
|
162 |
-
$dot = false;
|
163 |
-
if ('.' === substr($this->message, -1)) {
|
164 |
-
$this->message = substr($this->message, 0, -1);
|
165 |
-
$dot = true;
|
166 |
-
}
|
167 |
-
|
168 |
-
if ($this->filename) {
|
169 |
-
if (is_string($this->filename) || (is_object($this->filename) && method_exists($this->filename, '__toString'))) {
|
170 |
-
$filename = sprintf('"%s"', $this->filename);
|
171 |
-
} else {
|
172 |
-
$filename = json_encode($this->filename);
|
173 |
-
}
|
174 |
-
$this->message .= sprintf(' in %s', $filename);
|
175 |
-
}
|
176 |
-
|
177 |
-
if ($this->lineno && $this->lineno >= 0) {
|
178 |
-
$this->message .= sprintf(' at line %d', $this->lineno);
|
179 |
-
}
|
180 |
-
|
181 |
-
if ($dot) {
|
182 |
-
$this->message .= '.';
|
183 |
-
}
|
184 |
-
}
|
185 |
-
|
186 |
-
protected function guessTemplateInfo()
|
187 |
-
{
|
188 |
-
$template = null;
|
189 |
-
$templateClass = null;
|
190 |
-
|
191 |
-
if (version_compare(phpversion(), '5.3.6', '>=')) {
|
192 |
-
$backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS | DEBUG_BACKTRACE_PROVIDE_OBJECT);
|
193 |
-
} else {
|
194 |
-
$backtrace = debug_backtrace();
|
195 |
-
}
|
196 |
-
|
197 |
-
foreach ($backtrace as $trace) {
|
198 |
-
if (isset($trace['object']) && $trace['object'] instanceof Twig_Template && 'Twig_Template' !== get_class($trace['object'])) {
|
199 |
-
$currentClass = get_class($trace['object']);
|
200 |
-
$isEmbedContainer = 0 === strpos($templateClass, $currentClass);
|
201 |
-
if (null === $this->filename || ($this->filename == $trace['object']->getTemplateName() && !$isEmbedContainer)) {
|
202 |
-
$template = $trace['object'];
|
203 |
-
$templateClass = get_class($trace['object']);
|
204 |
-
}
|
205 |
-
}
|
206 |
-
}
|
207 |
-
|
208 |
-
// update template filename
|
209 |
-
if (null !== $template && null === $this->filename) {
|
210 |
-
$this->filename = $template->getTemplateName();
|
211 |
-
}
|
212 |
-
|
213 |
-
if (null === $template || $this->lineno > -1) {
|
214 |
-
return;
|
215 |
-
}
|
216 |
-
|
217 |
-
$r = new ReflectionObject($template);
|
218 |
-
$file = $r->getFileName();
|
219 |
-
|
220 |
-
// hhvm has a bug where eval'ed files comes out as the current directory
|
221 |
-
if (is_dir($file)) {
|
222 |
-
$file = '';
|
223 |
-
}
|
224 |
-
|
225 |
-
$exceptions = array($e = $this);
|
226 |
-
while (($e instanceof self || method_exists($e, 'getPrevious')) && $e = $e->getPrevious()) {
|
227 |
-
$exceptions[] = $e;
|
228 |
-
}
|
229 |
-
|
230 |
-
while ($e = array_pop($exceptions)) {
|
231 |
-
$traces = $e->getTrace();
|
232 |
-
while ($trace = array_shift($traces)) {
|
233 |
-
if (!isset($trace['file']) || !isset($trace['line']) || $file != $trace['file']) {
|
234 |
-
continue;
|
235 |
-
}
|
236 |
-
|
237 |
-
foreach ($template->getDebugInfo() as $codeLine => $templateLine) {
|
238 |
-
if ($codeLine <= $trace['line']) {
|
239 |
-
// update template line
|
240 |
-
$this->lineno = $templateLine;
|
241 |
-
|
242 |
-
return;
|
243 |
-
}
|
244 |
-
}
|
245 |
-
}
|
246 |
-
}
|
247 |
-
}
|
248 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2009 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Twig base exception.
|
14 |
+
*
|
15 |
+
* This exception class and its children must only be used when
|
16 |
+
* an error occurs during the loading of a template, when a syntax error
|
17 |
+
* is detected in a template, or when rendering a template. Other
|
18 |
+
* errors must use regular PHP exception classes (like when the template
|
19 |
+
* cache directory is not writable for instance).
|
20 |
+
*
|
21 |
+
* To help debugging template issues, this class tracks the original template
|
22 |
+
* name and line where the error occurred.
|
23 |
+
*
|
24 |
+
* Whenever possible, you must set these information (original template name
|
25 |
+
* and line number) yourself by passing them to the constructor. If some or all
|
26 |
+
* these information are not available from where you throw the exception, then
|
27 |
+
* this class will guess them automatically (when the line number is set to -1
|
28 |
+
* and/or the filename is set to null). As this is a costly operation, this
|
29 |
+
* can be disabled by passing false for both the filename and the line number
|
30 |
+
* when creating a new instance of this class.
|
31 |
+
*
|
32 |
+
* @author Fabien Potencier <fabien@symfony.com>
|
33 |
+
*/
|
34 |
+
class Twig_Error extends Exception
|
35 |
+
{
|
36 |
+
protected $lineno;
|
37 |
+
protected $filename;
|
38 |
+
protected $rawMessage;
|
39 |
+
protected $previous;
|
40 |
+
|
41 |
+
/**
|
42 |
+
* Constructor.
|
43 |
+
*
|
44 |
+
* Set both the line number and the filename to false to
|
45 |
+
* disable automatic guessing of the original template name
|
46 |
+
* and line number.
|
47 |
+
*
|
48 |
+
* Set the line number to -1 to enable its automatic guessing.
|
49 |
+
* Set the filename to null to enable its automatic guessing.
|
50 |
+
*
|
51 |
+
* By default, automatic guessing is enabled.
|
52 |
+
*
|
53 |
+
* @param string $message The error message
|
54 |
+
* @param int $lineno The template line where the error occurred
|
55 |
+
* @param string $filename The template file name where the error occurred
|
56 |
+
* @param Exception $previous The previous exception
|
57 |
+
*/
|
58 |
+
public function __construct($message, $lineno = -1, $filename = null, Exception $previous = null)
|
59 |
+
{
|
60 |
+
if (version_compare(PHP_VERSION, '5.3.0', '<')) {
|
61 |
+
$this->previous = $previous;
|
62 |
+
parent::__construct('');
|
63 |
+
} else {
|
64 |
+
parent::__construct('', 0, $previous);
|
65 |
+
}
|
66 |
+
|
67 |
+
$this->lineno = $lineno;
|
68 |
+
$this->filename = $filename;
|
69 |
+
|
70 |
+
if (-1 === $this->lineno || null === $this->filename) {
|
71 |
+
$this->guessTemplateInfo();
|
72 |
+
}
|
73 |
+
|
74 |
+
$this->rawMessage = $message;
|
75 |
+
|
76 |
+
$this->updateRepr();
|
77 |
+
}
|
78 |
+
|
79 |
+
/**
|
80 |
+
* Gets the raw message.
|
81 |
+
*
|
82 |
+
* @return string The raw message
|
83 |
+
*/
|
84 |
+
public function getRawMessage()
|
85 |
+
{
|
86 |
+
return $this->rawMessage;
|
87 |
+
}
|
88 |
+
|
89 |
+
/**
|
90 |
+
* Gets the filename where the error occurred.
|
91 |
+
*
|
92 |
+
* @return string The filename
|
93 |
+
*/
|
94 |
+
public function getTemplateFile()
|
95 |
+
{
|
96 |
+
return $this->filename;
|
97 |
+
}
|
98 |
+
|
99 |
+
/**
|
100 |
+
* Sets the filename where the error occurred.
|
101 |
+
*
|
102 |
+
* @param string $filename The filename
|
103 |
+
*/
|
104 |
+
public function setTemplateFile($filename)
|
105 |
+
{
|
106 |
+
$this->filename = $filename;
|
107 |
+
|
108 |
+
$this->updateRepr();
|
109 |
+
}
|
110 |
+
|
111 |
+
/**
|
112 |
+
* Gets the template line where the error occurred.
|
113 |
+
*
|
114 |
+
* @return int The template line
|
115 |
+
*/
|
116 |
+
public function getTemplateLine()
|
117 |
+
{
|
118 |
+
return $this->lineno;
|
119 |
+
}
|
120 |
+
|
121 |
+
/**
|
122 |
+
* Sets the template line where the error occurred.
|
123 |
+
*
|
124 |
+
* @param int $lineno The template line
|
125 |
+
*/
|
126 |
+
public function setTemplateLine($lineno)
|
127 |
+
{
|
128 |
+
$this->lineno = $lineno;
|
129 |
+
|
130 |
+
$this->updateRepr();
|
131 |
+
}
|
132 |
+
|
133 |
+
public function guess()
|
134 |
+
{
|
135 |
+
$this->guessTemplateInfo();
|
136 |
+
$this->updateRepr();
|
137 |
+
}
|
138 |
+
|
139 |
+
/**
|
140 |
+
* For PHP < 5.3.0, provides access to the getPrevious() method.
|
141 |
+
*
|
142 |
+
* @param string $method The method name
|
143 |
+
* @param array $arguments The parameters to be passed to the method
|
144 |
+
*
|
145 |
+
* @return Exception The previous exception or null
|
146 |
+
*
|
147 |
+
* @throws BadMethodCallException
|
148 |
+
*/
|
149 |
+
public function __call($method, $arguments)
|
150 |
+
{
|
151 |
+
if ('getprevious' == strtolower($method)) {
|
152 |
+
return $this->previous;
|
153 |
+
}
|
154 |
+
|
155 |
+
throw new BadMethodCallException(sprintf('Method "Twig_Error::%s()" does not exist.', $method));
|
156 |
+
}
|
157 |
+
|
158 |
+
protected function updateRepr()
|
159 |
+
{
|
160 |
+
$this->message = $this->rawMessage;
|
161 |
+
|
162 |
+
$dot = false;
|
163 |
+
if ('.' === substr($this->message, -1)) {
|
164 |
+
$this->message = substr($this->message, 0, -1);
|
165 |
+
$dot = true;
|
166 |
+
}
|
167 |
+
|
168 |
+
if ($this->filename) {
|
169 |
+
if (is_string($this->filename) || (is_object($this->filename) && method_exists($this->filename, '__toString'))) {
|
170 |
+
$filename = sprintf('"%s"', $this->filename);
|
171 |
+
} else {
|
172 |
+
$filename = json_encode($this->filename);
|
173 |
+
}
|
174 |
+
$this->message .= sprintf(' in %s', $filename);
|
175 |
+
}
|
176 |
+
|
177 |
+
if ($this->lineno && $this->lineno >= 0) {
|
178 |
+
$this->message .= sprintf(' at line %d', $this->lineno);
|
179 |
+
}
|
180 |
+
|
181 |
+
if ($dot) {
|
182 |
+
$this->message .= '.';
|
183 |
+
}
|
184 |
+
}
|
185 |
+
|
186 |
+
protected function guessTemplateInfo()
|
187 |
+
{
|
188 |
+
$template = null;
|
189 |
+
$templateClass = null;
|
190 |
+
|
191 |
+
if (version_compare(phpversion(), '5.3.6', '>=')) {
|
192 |
+
$backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS | DEBUG_BACKTRACE_PROVIDE_OBJECT);
|
193 |
+
} else {
|
194 |
+
$backtrace = debug_backtrace();
|
195 |
+
}
|
196 |
+
|
197 |
+
foreach ($backtrace as $trace) {
|
198 |
+
if (isset($trace['object']) && $trace['object'] instanceof Twig_Template && 'Twig_Template' !== get_class($trace['object'])) {
|
199 |
+
$currentClass = get_class($trace['object']);
|
200 |
+
$isEmbedContainer = 0 === strpos($templateClass, $currentClass);
|
201 |
+
if (null === $this->filename || ($this->filename == $trace['object']->getTemplateName() && !$isEmbedContainer)) {
|
202 |
+
$template = $trace['object'];
|
203 |
+
$templateClass = get_class($trace['object']);
|
204 |
+
}
|
205 |
+
}
|
206 |
+
}
|
207 |
+
|
208 |
+
// update template filename
|
209 |
+
if (null !== $template && null === $this->filename) {
|
210 |
+
$this->filename = $template->getTemplateName();
|
211 |
+
}
|
212 |
+
|
213 |
+
if (null === $template || $this->lineno > -1) {
|
214 |
+
return;
|
215 |
+
}
|
216 |
+
|
217 |
+
$r = new ReflectionObject($template);
|
218 |
+
$file = $r->getFileName();
|
219 |
+
|
220 |
+
// hhvm has a bug where eval'ed files comes out as the current directory
|
221 |
+
if (is_dir($file)) {
|
222 |
+
$file = '';
|
223 |
+
}
|
224 |
+
|
225 |
+
$exceptions = array($e = $this);
|
226 |
+
while (($e instanceof self || method_exists($e, 'getPrevious')) && $e = $e->getPrevious()) {
|
227 |
+
$exceptions[] = $e;
|
228 |
+
}
|
229 |
+
|
230 |
+
while ($e = array_pop($exceptions)) {
|
231 |
+
$traces = $e->getTrace();
|
232 |
+
while ($trace = array_shift($traces)) {
|
233 |
+
if (!isset($trace['file']) || !isset($trace['line']) || $file != $trace['file']) {
|
234 |
+
continue;
|
235 |
+
}
|
236 |
+
|
237 |
+
foreach ($template->getDebugInfo() as $codeLine => $templateLine) {
|
238 |
+
if ($codeLine <= $trace['line']) {
|
239 |
+
// update template line
|
240 |
+
$this->lineno = $templateLine;
|
241 |
+
|
242 |
+
return;
|
243 |
+
}
|
244 |
+
}
|
245 |
+
}
|
246 |
+
}
|
247 |
+
}
|
248 |
+
}
|
classes/Twig/Error/Loader.php
CHANGED
@@ -1,31 +1,31 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2010 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
/**
|
13 |
-
* Exception thrown when an error occurs during template loading.
|
14 |
-
*
|
15 |
-
* Automatic template information guessing is always turned off as
|
16 |
-
* if a template cannot be loaded, there is nothing to guess.
|
17 |
-
* However, when a template is loaded from another one, then, we need
|
18 |
-
* to find the current context and this is automatically done by
|
19 |
-
* Twig_Template::displayWithErrorHandling().
|
20 |
-
*
|
21 |
-
* This strategy makes Twig_Environment::resolveTemplate() much faster.
|
22 |
-
*
|
23 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
24 |
-
*/
|
25 |
-
class Twig_Error_Loader extends Twig_Error
|
26 |
-
{
|
27 |
-
public function __construct($message, $lineno = -1, $filename = null, Exception $previous = null)
|
28 |
-
{
|
29 |
-
parent::__construct($message, false, false, $previous);
|
30 |
-
}
|
31 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2010 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Exception thrown when an error occurs during template loading.
|
14 |
+
*
|
15 |
+
* Automatic template information guessing is always turned off as
|
16 |
+
* if a template cannot be loaded, there is nothing to guess.
|
17 |
+
* However, when a template is loaded from another one, then, we need
|
18 |
+
* to find the current context and this is automatically done by
|
19 |
+
* Twig_Template::displayWithErrorHandling().
|
20 |
+
*
|
21 |
+
* This strategy makes Twig_Environment::resolveTemplate() much faster.
|
22 |
+
*
|
23 |
+
* @author Fabien Potencier <fabien@symfony.com>
|
24 |
+
*/
|
25 |
+
class Twig_Error_Loader extends Twig_Error
|
26 |
+
{
|
27 |
+
public function __construct($message, $lineno = -1, $filename = null, Exception $previous = null)
|
28 |
+
{
|
29 |
+
parent::__construct($message, false, false, $previous);
|
30 |
+
}
|
31 |
+
}
|
classes/Twig/Error/Runtime.php
CHANGED
@@ -1,20 +1,20 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2009 Fabien Potencier
|
7 |
-
* (c) 2009 Armin Ronacher
|
8 |
-
*
|
9 |
-
* For the full copyright and license information, please view the LICENSE
|
10 |
-
* file that was distributed with this source code.
|
11 |
-
*/
|
12 |
-
|
13 |
-
/**
|
14 |
-
* Exception thrown when an error occurs at runtime.
|
15 |
-
*
|
16 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
17 |
-
*/
|
18 |
-
class Twig_Error_Runtime extends Twig_Error
|
19 |
-
{
|
20 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2009 Fabien Potencier
|
7 |
+
* (c) 2009 Armin Ronacher
|
8 |
+
*
|
9 |
+
* For the full copyright and license information, please view the LICENSE
|
10 |
+
* file that was distributed with this source code.
|
11 |
+
*/
|
12 |
+
|
13 |
+
/**
|
14 |
+
* Exception thrown when an error occurs at runtime.
|
15 |
+
*
|
16 |
+
* @author Fabien Potencier <fabien@symfony.com>
|
17 |
+
*/
|
18 |
+
class Twig_Error_Runtime extends Twig_Error
|
19 |
+
{
|
20 |
+
}
|
classes/Twig/Error/Syntax.php
CHANGED
@@ -1,20 +1,20 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2009 Fabien Potencier
|
7 |
-
* (c) 2009 Armin Ronacher
|
8 |
-
*
|
9 |
-
* For the full copyright and license information, please view the LICENSE
|
10 |
-
* file that was distributed with this source code.
|
11 |
-
*/
|
12 |
-
|
13 |
-
/**
|
14 |
-
* Exception thrown when a syntax error occurs during lexing or parsing of a template.
|
15 |
-
*
|
16 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
17 |
-
*/
|
18 |
-
class Twig_Error_Syntax extends Twig_Error
|
19 |
-
{
|
20 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2009 Fabien Potencier
|
7 |
+
* (c) 2009 Armin Ronacher
|
8 |
+
*
|
9 |
+
* For the full copyright and license information, please view the LICENSE
|
10 |
+
* file that was distributed with this source code.
|
11 |
+
*/
|
12 |
+
|
13 |
+
/**
|
14 |
+
* Exception thrown when a syntax error occurs during lexing or parsing of a template.
|
15 |
+
*
|
16 |
+
* @author Fabien Potencier <fabien@symfony.com>
|
17 |
+
*/
|
18 |
+
class Twig_Error_Syntax extends Twig_Error
|
19 |
+
{
|
20 |
+
}
|
classes/Twig/ExistsLoaderInterface.php
CHANGED
@@ -1,29 +1,29 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2009 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
/**
|
13 |
-
* Adds an exists() method for loaders.
|
14 |
-
*
|
15 |
-
* @author Florin Patan <florinpatan@gmail.com>
|
16 |
-
*
|
17 |
-
* @deprecated since 1.12 (to be removed in 3.0)
|
18 |
-
*/
|
19 |
-
interface Twig_ExistsLoaderInterface
|
20 |
-
{
|
21 |
-
/**
|
22 |
-
* Check if we have the source code of a template, given its name.
|
23 |
-
*
|
24 |
-
* @param string $name The name of the template to check if we can load
|
25 |
-
*
|
26 |
-
* @return bool If the template source code is handled by this loader or not
|
27 |
-
*/
|
28 |
-
public function exists($name);
|
29 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2009 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Adds an exists() method for loaders.
|
14 |
+
*
|
15 |
+
* @author Florin Patan <florinpatan@gmail.com>
|
16 |
+
*
|
17 |
+
* @deprecated since 1.12 (to be removed in 3.0)
|
18 |
+
*/
|
19 |
+
interface Twig_ExistsLoaderInterface
|
20 |
+
{
|
21 |
+
/**
|
22 |
+
* Check if we have the source code of a template, given its name.
|
23 |
+
*
|
24 |
+
* @param string $name The name of the template to check if we can load
|
25 |
+
*
|
26 |
+
* @return bool If the template source code is handled by this loader or not
|
27 |
+
*/
|
28 |
+
public function exists($name);
|
29 |
+
}
|
classes/Twig/ExpressionParser.php
CHANGED
@@ -1,598 +1,598 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2009 Fabien Potencier
|
7 |
-
* (c) 2009 Armin Ronacher
|
8 |
-
*
|
9 |
-
* For the full copyright and license information, please view the LICENSE
|
10 |
-
* file that was distributed with this source code.
|
11 |
-
*/
|
12 |
-
|
13 |
-
/**
|
14 |
-
* Parses expressions.
|
15 |
-
*
|
16 |
-
* This parser implements a "Precedence climbing" algorithm.
|
17 |
-
*
|
18 |
-
* @see http://www.engr.mun.ca/~theo/Misc/exp_parsing.htm
|
19 |
-
* @see http://en.wikipedia.org/wiki/Operator-precedence_parser
|
20 |
-
*
|
21 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
22 |
-
*/
|
23 |
-
class Twig_ExpressionParser
|
24 |
-
{
|
25 |
-
const OPERATOR_LEFT = 1;
|
26 |
-
const OPERATOR_RIGHT = 2;
|
27 |
-
|
28 |
-
protected $parser;
|
29 |
-
protected $unaryOperators;
|
30 |
-
protected $binaryOperators;
|
31 |
-
|
32 |
-
public function __construct(Twig_Parser $parser, array $unaryOperators, array $binaryOperators)
|
33 |
-
{
|
34 |
-
$this->parser = $parser;
|
35 |
-
$this->unaryOperators = $unaryOperators;
|
36 |
-
$this->binaryOperators = $binaryOperators;
|
37 |
-
}
|
38 |
-
|
39 |
-
public function parseExpression($precedence = 0)
|
40 |
-
{
|
41 |
-
$expr = $this->getPrimary();
|
42 |
-
$token = $this->parser->getCurrentToken();
|
43 |
-
while ($this->isBinary($token) && $this->binaryOperators[$token->getValue()]['precedence'] >= $precedence) {
|
44 |
-
$op = $this->binaryOperators[$token->getValue()];
|
45 |
-
$this->parser->getStream()->next();
|
46 |
-
|
47 |
-
if (isset($op['callable'])) {
|
48 |
-
$expr = call_user_func($op['callable'], $this->parser, $expr);
|
49 |
-
} else {
|
50 |
-
$expr1 = $this->parseExpression(self::OPERATOR_LEFT === $op['associativity'] ? $op['precedence'] + 1 : $op['precedence']);
|
51 |
-
$class = $op['class'];
|
52 |
-
$expr = new $class($expr, $expr1, $token->getLine());
|
53 |
-
}
|
54 |
-
|
55 |
-
$token = $this->parser->getCurrentToken();
|
56 |
-
}
|
57 |
-
|
58 |
-
if (0 === $precedence) {
|
59 |
-
return $this->parseConditionalExpression($expr);
|
60 |
-
}
|
61 |
-
|
62 |
-
return $expr;
|
63 |
-
}
|
64 |
-
|
65 |
-
protected function getPrimary()
|
66 |
-
{
|
67 |
-
$token = $this->parser->getCurrentToken();
|
68 |
-
|
69 |
-
if ($this->isUnary($token)) {
|
70 |
-
$operator = $this->unaryOperators[$token->getValue()];
|
71 |
-
$this->parser->getStream()->next();
|
72 |
-
$expr = $this->parseExpression($operator['precedence']);
|
73 |
-
$class = $operator['class'];
|
74 |
-
|
75 |
-
return $this->parsePostfixExpression(new $class($expr, $token->getLine()));
|
76 |
-
} elseif ($token->test(Twig_Token::PUNCTUATION_TYPE, '(')) {
|
77 |
-
$this->parser->getStream()->next();
|
78 |
-
$expr = $this->parseExpression();
|
79 |
-
$this->parser->getStream()->expect(Twig_Token::PUNCTUATION_TYPE, ')', 'An opened parenthesis is not properly closed');
|
80 |
-
|
81 |
-
return $this->parsePostfixExpression($expr);
|
82 |
-
}
|
83 |
-
|
84 |
-
return $this->parsePrimaryExpression();
|
85 |
-
}
|
86 |
-
|
87 |
-
protected function parseConditionalExpression($expr)
|
88 |
-
{
|
89 |
-
while ($this->parser->getStream()->nextIf(Twig_Token::PUNCTUATION_TYPE, '?')) {
|
90 |
-
if (!$this->parser->getStream()->nextIf(Twig_Token::PUNCTUATION_TYPE, ':')) {
|
91 |
-
$expr2 = $this->parseExpression();
|
92 |
-
if ($this->parser->getStream()->nextIf(Twig_Token::PUNCTUATION_TYPE, ':')) {
|
93 |
-
$expr3 = $this->parseExpression();
|
94 |
-
} else {
|
95 |
-
$expr3 = new Twig_Node_Expression_Constant('', $this->parser->getCurrentToken()->getLine());
|
96 |
-
}
|
97 |
-
} else {
|
98 |
-
$expr2 = $expr;
|
99 |
-
$expr3 = $this->parseExpression();
|
100 |
-
}
|
101 |
-
|
102 |
-
$expr = new Twig_Node_Expression_Conditional($expr, $expr2, $expr3, $this->parser->getCurrentToken()->getLine());
|
103 |
-
}
|
104 |
-
|
105 |
-
return $expr;
|
106 |
-
}
|
107 |
-
|
108 |
-
protected function isUnary(Twig_Token $token)
|
109 |
-
{
|
110 |
-
return $token->test(Twig_Token::OPERATOR_TYPE) && isset($this->unaryOperators[$token->getValue()]);
|
111 |
-
}
|
112 |
-
|
113 |
-
protected function isBinary(Twig_Token $token)
|
114 |
-
{
|
115 |
-
return $token->test(Twig_Token::OPERATOR_TYPE) && isset($this->binaryOperators[$token->getValue()]);
|
116 |
-
}
|
117 |
-
|
118 |
-
public function parsePrimaryExpression()
|
119 |
-
{
|
120 |
-
$token = $this->parser->getCurrentToken();
|
121 |
-
switch ($token->getType()) {
|
122 |
-
case Twig_Token::NAME_TYPE:
|
123 |
-
$this->parser->getStream()->next();
|
124 |
-
switch ($token->getValue()) {
|
125 |
-
case 'true':
|
126 |
-
case 'TRUE':
|
127 |
-
$node = new Twig_Node_Expression_Constant(true, $token->getLine());
|
128 |
-
break;
|
129 |
-
|
130 |
-
case 'false':
|
131 |
-
case 'FALSE':
|
132 |
-
$node = new Twig_Node_Expression_Constant(false, $token->getLine());
|
133 |
-
break;
|
134 |
-
|
135 |
-
case 'none':
|
136 |
-
case 'NONE':
|
137 |
-
case 'null':
|
138 |
-
case 'NULL':
|
139 |
-
$node = new Twig_Node_Expression_Constant(null, $token->getLine());
|
140 |
-
break;
|
141 |
-
|
142 |
-
default:
|
143 |
-
if ('(' === $this->parser->getCurrentToken()->getValue()) {
|
144 |
-
$node = $this->getFunctionNode($token->getValue(), $token->getLine());
|
145 |
-
} else {
|
146 |
-
$node = new Twig_Node_Expression_Name($token->getValue(), $token->getLine());
|
147 |
-
}
|
148 |
-
}
|
149 |
-
break;
|
150 |
-
|
151 |
-
case Twig_Token::NUMBER_TYPE:
|
152 |
-
$this->parser->getStream()->next();
|
153 |
-
$node = new Twig_Node_Expression_Constant($token->getValue(), $token->getLine());
|
154 |
-
break;
|
155 |
-
|
156 |
-
case Twig_Token::STRING_TYPE:
|
157 |
-
case Twig_Token::INTERPOLATION_START_TYPE:
|
158 |
-
$node = $this->parseStringExpression();
|
159 |
-
break;
|
160 |
-
|
161 |
-
case Twig_Token::OPERATOR_TYPE:
|
162 |
-
if (preg_match(Twig_Lexer::REGEX_NAME, $token->getValue(), $matches) && $matches[0] == $token->getValue()) {
|
163 |
-
// in this context, string operators are variable names
|
164 |
-
$this->parser->getStream()->next();
|
165 |
-
$node = new Twig_Node_Expression_Name($token->getValue(), $token->getLine());
|
166 |
-
break;
|
167 |
-
}
|
168 |
-
|
169 |
-
default:
|
170 |
-
if ($token->test(Twig_Token::PUNCTUATION_TYPE, '[')) {
|
171 |
-
$node = $this->parseArrayExpression();
|
172 |
-
} elseif ($token->test(Twig_Token::PUNCTUATION_TYPE, '{')) {
|
173 |
-
$node = $this->parseHashExpression();
|
174 |
-
} else {
|
175 |
-
throw new Twig_Error_Syntax(sprintf('Unexpected token "%s" of value "%s"', Twig_Token::typeToEnglish($token->getType()), $token->getValue()), $token->getLine(), $this->parser->getFilename());
|
176 |
-
}
|
177 |
-
}
|
178 |
-
|
179 |
-
return $this->parsePostfixExpression($node);
|
180 |
-
}
|
181 |
-
|
182 |
-
public function parseStringExpression()
|
183 |
-
{
|
184 |
-
$stream = $this->parser->getStream();
|
185 |
-
|
186 |
-
$nodes = array();
|
187 |
-
// a string cannot be followed by another string in a single expression
|
188 |
-
$nextCanBeString = true;
|
189 |
-
while (true) {
|
190 |
-
if ($nextCanBeString && $token = $stream->nextIf(Twig_Token::STRING_TYPE)) {
|
191 |
-
$nodes[] = new Twig_Node_Expression_Constant($token->getValue(), $token->getLine());
|
192 |
-
$nextCanBeString = false;
|
193 |
-
} elseif ($stream->nextIf(Twig_Token::INTERPOLATION_START_TYPE)) {
|
194 |
-
$nodes[] = $this->parseExpression();
|
195 |
-
$stream->expect(Twig_Token::INTERPOLATION_END_TYPE);
|
196 |
-
$nextCanBeString = true;
|
197 |
-
} else {
|
198 |
-
break;
|
199 |
-
}
|
200 |
-
}
|
201 |
-
|
202 |
-
$expr = array_shift($nodes);
|
203 |
-
foreach ($nodes as $node) {
|
204 |
-
$expr = new Twig_Node_Expression_Binary_Concat($expr, $node, $node->getLine());
|
205 |
-
}
|
206 |
-
|
207 |
-
return $expr;
|
208 |
-
}
|
209 |
-
|
210 |
-
public function parseArrayExpression()
|
211 |
-
{
|
212 |
-
$stream = $this->parser->getStream();
|
213 |
-
$stream->expect(Twig_Token::PUNCTUATION_TYPE, '[', 'An array element was expected');
|
214 |
-
|
215 |
-
$node = new Twig_Node_Expression_Array(array(), $stream->getCurrent()->getLine());
|
216 |
-
$first = true;
|
217 |
-
while (!$stream->test(Twig_Token::PUNCTUATION_TYPE, ']')) {
|
218 |
-
if (!$first) {
|
219 |
-
$stream->expect(Twig_Token::PUNCTUATION_TYPE, ',', 'An array element must be followed by a comma');
|
220 |
-
|
221 |
-
// trailing ,?
|
222 |
-
if ($stream->test(Twig_Token::PUNCTUATION_TYPE, ']')) {
|
223 |
-
break;
|
224 |
-
}
|
225 |
-
}
|
226 |
-
$first = false;
|
227 |
-
|
228 |
-
$node->addElement($this->parseExpression());
|
229 |
-
}
|
230 |
-
$stream->expect(Twig_Token::PUNCTUATION_TYPE, ']', 'An opened array is not properly closed');
|
231 |
-
|
232 |
-
return $node;
|
233 |
-
}
|
234 |
-
|
235 |
-
public function parseHashExpression()
|
236 |
-
{
|
237 |
-
$stream = $this->parser->getStream();
|
238 |
-
$stream->expect(Twig_Token::PUNCTUATION_TYPE, '{', 'A hash element was expected');
|
239 |
-
|
240 |
-
$node = new Twig_Node_Expression_Array(array(), $stream->getCurrent()->getLine());
|
241 |
-
$first = true;
|
242 |
-
while (!$stream->test(Twig_Token::PUNCTUATION_TYPE, '}')) {
|
243 |
-
if (!$first) {
|
244 |
-
$stream->expect(Twig_Token::PUNCTUATION_TYPE, ',', 'A hash value must be followed by a comma');
|
245 |
-
|
246 |
-
// trailing ,?
|
247 |
-
if ($stream->test(Twig_Token::PUNCTUATION_TYPE, '}')) {
|
248 |
-
break;
|
249 |
-
}
|
250 |
-
}
|
251 |
-
$first = false;
|
252 |
-
|
253 |
-
// a hash key can be:
|
254 |
-
//
|
255 |
-
// * a number -- 12
|
256 |
-
// * a string -- 'a'
|
257 |
-
// * a name, which is equivalent to a string -- a
|
258 |
-
// * an expression, which must be enclosed in parentheses -- (1 + 2)
|
259 |
-
if (($token = $stream->nextIf(Twig_Token::STRING_TYPE)) || ($token = $stream->nextIf(Twig_Token::NAME_TYPE)) || $token = $stream->nextIf(Twig_Token::NUMBER_TYPE)) {
|
260 |
-
$key = new Twig_Node_Expression_Constant($token->getValue(), $token->getLine());
|
261 |
-
} elseif ($stream->test(Twig_Token::PUNCTUATION_TYPE, '(')) {
|
262 |
-
$key = $this->parseExpression();
|
263 |
-
} else {
|
264 |
-
$current = $stream->getCurrent();
|
265 |
-
|
266 |
-
throw new Twig_Error_Syntax(sprintf('A hash key must be a quoted string, a number, a name, or an expression enclosed in parentheses (unexpected token "%s" of value "%s"', Twig_Token::typeToEnglish($current->getType()), $current->getValue()), $current->getLine(), $this->parser->getFilename());
|
267 |
-
}
|
268 |
-
|
269 |
-
$stream->expect(Twig_Token::PUNCTUATION_TYPE, ':', 'A hash key must be followed by a colon (:)');
|
270 |
-
$value = $this->parseExpression();
|
271 |
-
|
272 |
-
$node->addElement($value, $key);
|
273 |
-
}
|
274 |
-
$stream->expect(Twig_Token::PUNCTUATION_TYPE, '}', 'An opened hash is not properly closed');
|
275 |
-
|
276 |
-
return $node;
|
277 |
-
}
|
278 |
-
|
279 |
-
public function parsePostfixExpression($node)
|
280 |
-
{
|
281 |
-
while (true) {
|
282 |
-
$token = $this->parser->getCurrentToken();
|
283 |
-
if ($token->getType() == Twig_Token::PUNCTUATION_TYPE) {
|
284 |
-
if ('.' == $token->getValue() || '[' == $token->getValue()) {
|
285 |
-
$node = $this->parseSubscriptExpression($node);
|
286 |
-
} elseif ('|' == $token->getValue()) {
|
287 |
-
$node = $this->parseFilterExpression($node);
|
288 |
-
} else {
|
289 |
-
break;
|
290 |
-
}
|
291 |
-
} else {
|
292 |
-
break;
|
293 |
-
}
|
294 |
-
}
|
295 |
-
|
296 |
-
return $node;
|
297 |
-
}
|
298 |
-
|
299 |
-
public function getFunctionNode($name, $line)
|
300 |
-
{
|
301 |
-
switch ($name) {
|
302 |
-
case 'parent':
|
303 |
-
$args = $this->parseArguments();
|
304 |
-
if (!count($this->parser->getBlockStack())) {
|
305 |
-
throw new Twig_Error_Syntax('Calling "parent" outside a block is forbidden', $line, $this->parser->getFilename());
|
306 |
-
}
|
307 |
-
|
308 |
-
if (!$this->parser->getParent() && !$this->parser->hasTraits()) {
|
309 |
-
throw new Twig_Error_Syntax('Calling "parent" on a template that does not extend nor "use" another template is forbidden', $line, $this->parser->getFilename());
|
310 |
-
}
|
311 |
-
|
312 |
-
return new Twig_Node_Expression_Parent($this->parser->peekBlockStack(), $line);
|
313 |
-
case 'block':
|
314 |
-
return new Twig_Node_Expression_BlockReference($this->parseArguments()->getNode(0), false, $line);
|
315 |
-
case 'attribute':
|
316 |
-
$args = $this->parseArguments();
|
317 |
-
if (count($args) < 2) {
|
318 |
-
throw new Twig_Error_Syntax('The "attribute" function takes at least two arguments (the variable and the attributes)', $line, $this->parser->getFilename());
|
319 |
-
}
|
320 |
-
|
321 |
-
return new Twig_Node_Expression_GetAttr($args->getNode(0), $args->getNode(1), count($args) > 2 ? $args->getNode(2) : new Twig_Node_Expression_Array(array(), $line), Twig_Template::ANY_CALL, $line);
|
322 |
-
default:
|
323 |
-
if (null !== $alias = $this->parser->getImportedSymbol('function', $name)) {
|
324 |
-
$arguments = new Twig_Node_Expression_Array(array(), $line);
|
325 |
-
foreach ($this->parseArguments() as $n) {
|
326 |
-
$arguments->addElement($n);
|
327 |
-
}
|
328 |
-
|
329 |
-
$node = new Twig_Node_Expression_MethodCall($alias['node'], $alias['name'], $arguments, $line);
|
330 |
-
$node->setAttribute('safe', true);
|
331 |
-
|
332 |
-
return $node;
|
333 |
-
}
|
334 |
-
|
335 |
-
$args = $this->parseArguments(true);
|
336 |
-
$class = $this->getFunctionNodeClass($name, $line);
|
337 |
-
|
338 |
-
return new $class($name, $args, $line);
|
339 |
-
}
|
340 |
-
}
|
341 |
-
|
342 |
-
public function parseSubscriptExpression($node)
|
343 |
-
{
|
344 |
-
$stream = $this->parser->getStream();
|
345 |
-
$token = $stream->next();
|
346 |
-
$lineno = $token->getLine();
|
347 |
-
$arguments = new Twig_Node_Expression_Array(array(), $lineno);
|
348 |
-
$type = Twig_Template::ANY_CALL;
|
349 |
-
if ($token->getValue() == '.') {
|
350 |
-
$token = $stream->next();
|
351 |
-
if (
|
352 |
-
$token->getType() == Twig_Token::NAME_TYPE
|
353 |
-
||
|
354 |
-
$token->getType() == Twig_Token::NUMBER_TYPE
|
355 |
-
||
|
356 |
-
($token->getType() == Twig_Token::OPERATOR_TYPE && preg_match(Twig_Lexer::REGEX_NAME, $token->getValue()))
|
357 |
-
) {
|
358 |
-
$arg = new Twig_Node_Expression_Constant($token->getValue(), $lineno);
|
359 |
-
|
360 |
-
if ($stream->test(Twig_Token::PUNCTUATION_TYPE, '(')) {
|
361 |
-
$type = Twig_TemplateInterface::METHOD_CALL;
|
362 |
-
foreach ($this->parseArguments() as $n) {
|
363 |
-
$arguments->addElement($n);
|
364 |
-
}
|
365 |
-
}
|
366 |
-
} else {
|
367 |
-
throw new Twig_Error_Syntax('Expected name or number', $lineno, $this->parser->getFilename());
|
368 |
-
}
|
369 |
-
|
370 |
-
if ($node instanceof Twig_Node_Expression_Name && null !== $this->parser->getImportedSymbol('template', $node->getAttribute('name'))) {
|
371 |
-
if (!$arg instanceof Twig_Node_Expression_Constant) {
|
372 |
-
throw new Twig_Error_Syntax(sprintf('Dynamic macro names are not supported (called on "%s")', $node->getAttribute('name')), $token->getLine(), $this->parser->getFilename());
|
373 |
-
}
|
374 |
-
|
375 |
-
$node = new Twig_Node_Expression_MethodCall($node, 'get'.$arg->getAttribute('value'), $arguments, $lineno);
|
376 |
-
$node->setAttribute('safe', true);
|
377 |
-
|
378 |
-
return $node;
|
379 |
-
}
|
380 |
-
} else {
|
381 |
-
$type = Twig_Template::ARRAY_CALL;
|
382 |
-
|
383 |
-
// slice?
|
384 |
-
$slice = false;
|
385 |
-
if ($stream->test(Twig_Token::PUNCTUATION_TYPE, ':')) {
|
386 |
-
$slice = true;
|
387 |
-
$arg = new Twig_Node_Expression_Constant(0, $token->getLine());
|
388 |
-
} else {
|
389 |
-
$arg = $this->parseExpression();
|
390 |
-
}
|
391 |
-
|
392 |
-
if ($stream->nextIf(Twig_Token::PUNCTUATION_TYPE, ':')) {
|
393 |
-
$slice = true;
|
394 |
-
}
|
395 |
-
|
396 |
-
if ($slice) {
|
397 |
-
if ($stream->test(Twig_Token::PUNCTUATION_TYPE, ']')) {
|
398 |
-
$length = new Twig_Node_Expression_Constant(null, $token->getLine());
|
399 |
-
} else {
|
400 |
-
$length = $this->parseExpression();
|
401 |
-
}
|
402 |
-
|
403 |
-
$class = $this->getFilterNodeClass('slice', $token->getLine());
|
404 |
-
$arguments = new Twig_Node(array($arg, $length));
|
405 |
-
$filter = new $class($node, new Twig_Node_Expression_Constant('slice', $token->getLine()), $arguments, $token->getLine());
|
406 |
-
|
407 |
-
$stream->expect(Twig_Token::PUNCTUATION_TYPE, ']');
|
408 |
-
|
409 |
-
return $filter;
|
410 |
-
}
|
411 |
-
|
412 |
-
$stream->expect(Twig_Token::PUNCTUATION_TYPE, ']');
|
413 |
-
}
|
414 |
-
|
415 |
-
return new Twig_Node_Expression_GetAttr($node, $arg, $arguments, $type, $lineno);
|
416 |
-
}
|
417 |
-
|
418 |
-
public function parseFilterExpression($node)
|
419 |
-
{
|
420 |
-
$this->parser->getStream()->next();
|
421 |
-
|
422 |
-
return $this->parseFilterExpressionRaw($node);
|
423 |
-
}
|
424 |
-
|
425 |
-
public function parseFilterExpressionRaw($node, $tag = null)
|
426 |
-
{
|
427 |
-
while (true) {
|
428 |
-
$token = $this->parser->getStream()->expect(Twig_Token::NAME_TYPE);
|
429 |
-
|
430 |
-
$name = new Twig_Node_Expression_Constant($token->getValue(), $token->getLine());
|
431 |
-
if (!$this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, '(')) {
|
432 |
-
$arguments = new Twig_Node();
|
433 |
-
} else {
|
434 |
-
$arguments = $this->parseArguments(true);
|
435 |
-
}
|
436 |
-
|
437 |
-
$class = $this->getFilterNodeClass($name->getAttribute('value'), $token->getLine());
|
438 |
-
|
439 |
-
$node = new $class($node, $name, $arguments, $token->getLine(), $tag);
|
440 |
-
|
441 |
-
if (!$this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, '|')) {
|
442 |
-
break;
|
443 |
-
}
|
444 |
-
|
445 |
-
$this->parser->getStream()->next();
|
446 |
-
}
|
447 |
-
|
448 |
-
return $node;
|
449 |
-
}
|
450 |
-
|
451 |
-
/**
|
452 |
-
* Parses arguments.
|
453 |
-
*
|
454 |
-
* @param bool $namedArguments Whether to allow named arguments or not
|
455 |
-
* @param bool $definition Whether we are parsing arguments for a function definition
|
456 |
-
*/
|
457 |
-
public function parseArguments($namedArguments = false, $definition = false)
|
458 |
-
{
|
459 |
-
$args = array();
|
460 |
-
$stream = $this->parser->getStream();
|
461 |
-
|
462 |
-
$stream->expect(Twig_Token::PUNCTUATION_TYPE, '(', 'A list of arguments must begin with an opening parenthesis');
|
463 |
-
while (!$stream->test(Twig_Token::PUNCTUATION_TYPE, ')')) {
|
464 |
-
if (!empty($args)) {
|
465 |
-
$stream->expect(Twig_Token::PUNCTUATION_TYPE, ',', 'Arguments must be separated by a comma');
|
466 |
-
}
|
467 |
-
|
468 |
-
if ($definition) {
|
469 |
-
$token = $stream->expect(Twig_Token::NAME_TYPE, null, 'An argument must be a name');
|
470 |
-
$value = new Twig_Node_Expression_Name($token->getValue(), $this->parser->getCurrentToken()->getLine());
|
471 |
-
} else {
|
472 |
-
$value = $this->parseExpression();
|
473 |
-
}
|
474 |
-
|
475 |
-
$name = null;
|
476 |
-
if ($namedArguments && $token = $stream->nextIf(Twig_Token::OPERATOR_TYPE, '=')) {
|
477 |
-
if (!$value instanceof Twig_Node_Expression_Name) {
|
478 |
-
throw new Twig_Error_Syntax(sprintf('A parameter name must be a string, "%s" given', get_class($value)), $token->getLine(), $this->parser->getFilename());
|
479 |
-
}
|
480 |
-
$name = $value->getAttribute('name');
|
481 |
-
|
482 |
-
if ($definition) {
|
483 |
-
$value = $this->parsePrimaryExpression();
|
484 |
-
|
485 |
-
if (!$this->checkConstantExpression($value)) {
|
486 |
-
throw new Twig_Error_Syntax(sprintf('A default value for an argument must be a constant (a boolean, a string, a number, or an array).'), $token->getLine(), $this->parser->getFilename());
|
487 |
-
}
|
488 |
-
} else {
|
489 |
-
$value = $this->parseExpression();
|
490 |
-
}
|
491 |
-
}
|
492 |
-
|
493 |
-
if ($definition) {
|
494 |
-
if (null === $name) {
|
495 |
-
$name = $value->getAttribute('name');
|
496 |
-
$value = new Twig_Node_Expression_Constant(null, $this->parser->getCurrentToken()->getLine());
|
497 |
-
}
|
498 |
-
$args[$name] = $value;
|
499 |
-
} else {
|
500 |
-
if (null === $name) {
|
501 |
-
$args[] = $value;
|
502 |
-
} else {
|
503 |
-
$args[$name] = $value;
|
504 |
-
}
|
505 |
-
}
|
506 |
-
}
|
507 |
-
$stream->expect(Twig_Token::PUNCTUATION_TYPE, ')', 'A list of arguments must be closed by a parenthesis');
|
508 |
-
|
509 |
-
return new Twig_Node($args);
|
510 |
-
}
|
511 |
-
|
512 |
-
public function parseAssignmentExpression()
|
513 |
-
{
|
514 |
-
$targets = array();
|
515 |
-
while (true) {
|
516 |
-
$token = $this->parser->getStream()->expect(Twig_Token::NAME_TYPE, null, 'Only variables can be assigned to');
|
517 |
-
if (in_array($token->getValue(), array('true', 'false', 'none'))) {
|
518 |
-
throw new Twig_Error_Syntax(sprintf('You cannot assign a value to "%s"', $token->getValue()), $token->getLine(), $this->parser->getFilename());
|
519 |
-
}
|
520 |
-
$targets[] = new Twig_Node_Expression_AssignName($token->getValue(), $token->getLine());
|
521 |
-
|
522 |
-
if (!$this->parser->getStream()->nextIf(Twig_Token::PUNCTUATION_TYPE, ',')) {
|
523 |
-
break;
|
524 |
-
}
|
525 |
-
}
|
526 |
-
|
527 |
-
return new Twig_Node($targets);
|
528 |
-
}
|
529 |
-
|
530 |
-
public function parseMultitargetExpression()
|
531 |
-
{
|
532 |
-
$targets = array();
|
533 |
-
while (true) {
|
534 |
-
$targets[] = $this->parseExpression();
|
535 |
-
if (!$this->parser->getStream()->nextIf(Twig_Token::PUNCTUATION_TYPE, ',')) {
|
536 |
-
break;
|
537 |
-
}
|
538 |
-
}
|
539 |
-
|
540 |
-
return new Twig_Node($targets);
|
541 |
-
}
|
542 |
-
|
543 |
-
protected function getFunctionNodeClass($name, $line)
|
544 |
-
{
|
545 |
-
$env = $this->parser->getEnvironment();
|
546 |
-
|
547 |
-
if (false === $function = $env->getFunction($name)) {
|
548 |
-
$message = sprintf('The function "%s" does not exist', $name);
|
549 |
-
if ($alternatives = $env->computeAlternatives($name, array_keys($env->getFunctions()))) {
|
550 |
-
$message = sprintf('%s. Did you mean "%s"', $message, implode('", "', $alternatives));
|
551 |
-
}
|
552 |
-
|
553 |
-
throw new Twig_Error_Syntax($message, $line, $this->parser->getFilename());
|
554 |
-
}
|
555 |
-
|
556 |
-
if ($function instanceof Twig_SimpleFunction) {
|
557 |
-
return $function->getNodeClass();
|
558 |
-
}
|
559 |
-
|
560 |
-
return $function instanceof Twig_Function_Node ? $function->getClass() : 'Twig_Node_Expression_Function';
|
561 |
-
}
|
562 |
-
|
563 |
-
protected function getFilterNodeClass($name, $line)
|
564 |
-
{
|
565 |
-
$env = $this->parser->getEnvironment();
|
566 |
-
|
567 |
-
if (false === $filter = $env->getFilter($name)) {
|
568 |
-
$message = sprintf('The filter "%s" does not exist', $name);
|
569 |
-
if ($alternatives = $env->computeAlternatives($name, array_keys($env->getFilters()))) {
|
570 |
-
$message = sprintf('%s. Did you mean "%s"', $message, implode('", "', $alternatives));
|
571 |
-
}
|
572 |
-
|
573 |
-
throw new Twig_Error_Syntax($message, $line, $this->parser->getFilename());
|
574 |
-
}
|
575 |
-
|
576 |
-
if ($filter instanceof Twig_SimpleFilter) {
|
577 |
-
return $filter->getNodeClass();
|
578 |
-
}
|
579 |
-
|
580 |
-
return $filter instanceof Twig_Filter_Node ? $filter->getClass() : 'Twig_Node_Expression_Filter';
|
581 |
-
}
|
582 |
-
|
583 |
-
// checks that the node only contains "constant" elements
|
584 |
-
protected function checkConstantExpression(Twig_NodeInterface $node)
|
585 |
-
{
|
586 |
-
if (!($node instanceof Twig_Node_Expression_Constant || $node instanceof Twig_Node_Expression_Array)) {
|
587 |
-
return false;
|
588 |
-
}
|
589 |
-
|
590 |
-
foreach ($node as $n) {
|
591 |
-
if (!$this->checkConstantExpression($n)) {
|
592 |
-
return false;
|
593 |
-
}
|
594 |
-
}
|
595 |
-
|
596 |
-
return true;
|
597 |
-
}
|
598 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2009 Fabien Potencier
|
7 |
+
* (c) 2009 Armin Ronacher
|
8 |
+
*
|
9 |
+
* For the full copyright and license information, please view the LICENSE
|
10 |
+
* file that was distributed with this source code.
|
11 |
+
*/
|
12 |
+
|
13 |
+
/**
|
14 |
+
* Parses expressions.
|
15 |
+
*
|
16 |
+
* This parser implements a "Precedence climbing" algorithm.
|
17 |
+
*
|
18 |
+
* @see http://www.engr.mun.ca/~theo/Misc/exp_parsing.htm
|
19 |
+
* @see http://en.wikipedia.org/wiki/Operator-precedence_parser
|
20 |
+
*
|
21 |
+
* @author Fabien Potencier <fabien@symfony.com>
|
22 |
+
*/
|
23 |
+
class Twig_ExpressionParser
|
24 |
+
{
|
25 |
+
const OPERATOR_LEFT = 1;
|
26 |
+
const OPERATOR_RIGHT = 2;
|
27 |
+
|
28 |
+
protected $parser;
|
29 |
+
protected $unaryOperators;
|
30 |
+
protected $binaryOperators;
|
31 |
+
|
32 |
+
public function __construct(Twig_Parser $parser, array $unaryOperators, array $binaryOperators)
|
33 |
+
{
|
34 |
+
$this->parser = $parser;
|
35 |
+
$this->unaryOperators = $unaryOperators;
|
36 |
+
$this->binaryOperators = $binaryOperators;
|
37 |
+
}
|
38 |
+
|
39 |
+
public function parseExpression($precedence = 0)
|
40 |
+
{
|
41 |
+
$expr = $this->getPrimary();
|
42 |
+
$token = $this->parser->getCurrentToken();
|
43 |
+
while ($this->isBinary($token) && $this->binaryOperators[$token->getValue()]['precedence'] >= $precedence) {
|
44 |
+
$op = $this->binaryOperators[$token->getValue()];
|
45 |
+
$this->parser->getStream()->next();
|
46 |
+
|
47 |
+
if (isset($op['callable'])) {
|
48 |
+
$expr = call_user_func($op['callable'], $this->parser, $expr);
|
49 |
+
} else {
|
50 |
+
$expr1 = $this->parseExpression(self::OPERATOR_LEFT === $op['associativity'] ? $op['precedence'] + 1 : $op['precedence']);
|
51 |
+
$class = $op['class'];
|
52 |
+
$expr = new $class($expr, $expr1, $token->getLine());
|
53 |
+
}
|
54 |
+
|
55 |
+
$token = $this->parser->getCurrentToken();
|
56 |
+
}
|
57 |
+
|
58 |
+
if (0 === $precedence) {
|
59 |
+
return $this->parseConditionalExpression($expr);
|
60 |
+
}
|
61 |
+
|
62 |
+
return $expr;
|
63 |
+
}
|
64 |
+
|
65 |
+
protected function getPrimary()
|
66 |
+
{
|
67 |
+
$token = $this->parser->getCurrentToken();
|
68 |
+
|
69 |
+
if ($this->isUnary($token)) {
|
70 |
+
$operator = $this->unaryOperators[$token->getValue()];
|
71 |
+
$this->parser->getStream()->next();
|
72 |
+
$expr = $this->parseExpression($operator['precedence']);
|
73 |
+
$class = $operator['class'];
|
74 |
+
|
75 |
+
return $this->parsePostfixExpression(new $class($expr, $token->getLine()));
|
76 |
+
} elseif ($token->test(Twig_Token::PUNCTUATION_TYPE, '(')) {
|
77 |
+
$this->parser->getStream()->next();
|
78 |
+
$expr = $this->parseExpression();
|
79 |
+
$this->parser->getStream()->expect(Twig_Token::PUNCTUATION_TYPE, ')', 'An opened parenthesis is not properly closed');
|
80 |
+
|
81 |
+
return $this->parsePostfixExpression($expr);
|
82 |
+
}
|
83 |
+
|
84 |
+
return $this->parsePrimaryExpression();
|
85 |
+
}
|
86 |
+
|
87 |
+
protected function parseConditionalExpression($expr)
|
88 |
+
{
|
89 |
+
while ($this->parser->getStream()->nextIf(Twig_Token::PUNCTUATION_TYPE, '?')) {
|
90 |
+
if (!$this->parser->getStream()->nextIf(Twig_Token::PUNCTUATION_TYPE, ':')) {
|
91 |
+
$expr2 = $this->parseExpression();
|
92 |
+
if ($this->parser->getStream()->nextIf(Twig_Token::PUNCTUATION_TYPE, ':')) {
|
93 |
+
$expr3 = $this->parseExpression();
|
94 |
+
} else {
|
95 |
+
$expr3 = new Twig_Node_Expression_Constant('', $this->parser->getCurrentToken()->getLine());
|
96 |
+
}
|
97 |
+
} else {
|
98 |
+
$expr2 = $expr;
|
99 |
+
$expr3 = $this->parseExpression();
|
100 |
+
}
|
101 |
+
|
102 |
+
$expr = new Twig_Node_Expression_Conditional($expr, $expr2, $expr3, $this->parser->getCurrentToken()->getLine());
|
103 |
+
}
|
104 |
+
|
105 |
+
return $expr;
|
106 |
+
}
|
107 |
+
|
108 |
+
protected function isUnary(Twig_Token $token)
|
109 |
+
{
|
110 |
+
return $token->test(Twig_Token::OPERATOR_TYPE) && isset($this->unaryOperators[$token->getValue()]);
|
111 |
+
}
|
112 |
+
|
113 |
+
protected function isBinary(Twig_Token $token)
|
114 |
+
{
|
115 |
+
return $token->test(Twig_Token::OPERATOR_TYPE) && isset($this->binaryOperators[$token->getValue()]);
|
116 |
+
}
|
117 |
+
|
118 |
+
public function parsePrimaryExpression()
|
119 |
+
{
|
120 |
+
$token = $this->parser->getCurrentToken();
|
121 |
+
switch ($token->getType()) {
|
122 |
+
case Twig_Token::NAME_TYPE:
|
123 |
+
$this->parser->getStream()->next();
|
124 |
+
switch ($token->getValue()) {
|
125 |
+
case 'true':
|
126 |
+
case 'TRUE':
|
127 |
+
$node = new Twig_Node_Expression_Constant(true, $token->getLine());
|
128 |
+
break;
|
129 |
+
|
130 |
+
case 'false':
|
131 |
+
case 'FALSE':
|
132 |
+
$node = new Twig_Node_Expression_Constant(false, $token->getLine());
|
133 |
+
break;
|
134 |
+
|
135 |
+
case 'none':
|
136 |
+
case 'NONE':
|
137 |
+
case 'null':
|
138 |
+
case 'NULL':
|
139 |
+
$node = new Twig_Node_Expression_Constant(null, $token->getLine());
|
140 |
+
break;
|
141 |
+
|
142 |
+
default:
|
143 |
+
if ('(' === $this->parser->getCurrentToken()->getValue()) {
|
144 |
+
$node = $this->getFunctionNode($token->getValue(), $token->getLine());
|
145 |
+
} else {
|
146 |
+
$node = new Twig_Node_Expression_Name($token->getValue(), $token->getLine());
|
147 |
+
}
|
148 |
+
}
|
149 |
+
break;
|
150 |
+
|
151 |
+
case Twig_Token::NUMBER_TYPE:
|
152 |
+
$this->parser->getStream()->next();
|
153 |
+
$node = new Twig_Node_Expression_Constant($token->getValue(), $token->getLine());
|
154 |
+
break;
|
155 |
+
|
156 |
+
case Twig_Token::STRING_TYPE:
|
157 |
+
case Twig_Token::INTERPOLATION_START_TYPE:
|
158 |
+
$node = $this->parseStringExpression();
|
159 |
+
break;
|
160 |
+
|
161 |
+
case Twig_Token::OPERATOR_TYPE:
|
162 |
+
if (preg_match(Twig_Lexer::REGEX_NAME, $token->getValue(), $matches) && $matches[0] == $token->getValue()) {
|
163 |
+
// in this context, string operators are variable names
|
164 |
+
$this->parser->getStream()->next();
|
165 |
+
$node = new Twig_Node_Expression_Name($token->getValue(), $token->getLine());
|
166 |
+
break;
|
167 |
+
}
|
168 |
+
|
169 |
+
default:
|
170 |
+
if ($token->test(Twig_Token::PUNCTUATION_TYPE, '[')) {
|
171 |
+
$node = $this->parseArrayExpression();
|
172 |
+
} elseif ($token->test(Twig_Token::PUNCTUATION_TYPE, '{')) {
|
173 |
+
$node = $this->parseHashExpression();
|
174 |
+
} else {
|
175 |
+
throw new Twig_Error_Syntax(sprintf('Unexpected token "%s" of value "%s"', Twig_Token::typeToEnglish($token->getType()), $token->getValue()), $token->getLine(), $this->parser->getFilename());
|
176 |
+
}
|
177 |
+
}
|
178 |
+
|
179 |
+
return $this->parsePostfixExpression($node);
|
180 |
+
}
|
181 |
+
|
182 |
+
public function parseStringExpression()
|
183 |
+
{
|
184 |
+
$stream = $this->parser->getStream();
|
185 |
+
|
186 |
+
$nodes = array();
|
187 |
+
// a string cannot be followed by another string in a single expression
|
188 |
+
$nextCanBeString = true;
|
189 |
+
while (true) {
|
190 |
+
if ($nextCanBeString && $token = $stream->nextIf(Twig_Token::STRING_TYPE)) {
|
191 |
+
$nodes[] = new Twig_Node_Expression_Constant($token->getValue(), $token->getLine());
|
192 |
+
$nextCanBeString = false;
|
193 |
+
} elseif ($stream->nextIf(Twig_Token::INTERPOLATION_START_TYPE)) {
|
194 |
+
$nodes[] = $this->parseExpression();
|
195 |
+
$stream->expect(Twig_Token::INTERPOLATION_END_TYPE);
|
196 |
+
$nextCanBeString = true;
|
197 |
+
} else {
|
198 |
+
break;
|
199 |
+
}
|
200 |
+
}
|
201 |
+
|
202 |
+
$expr = array_shift($nodes);
|
203 |
+
foreach ($nodes as $node) {
|
204 |
+
$expr = new Twig_Node_Expression_Binary_Concat($expr, $node, $node->getLine());
|
205 |
+
}
|
206 |
+
|
207 |
+
return $expr;
|
208 |
+
}
|
209 |
+
|
210 |
+
public function parseArrayExpression()
|
211 |
+
{
|
212 |
+
$stream = $this->parser->getStream();
|
213 |
+
$stream->expect(Twig_Token::PUNCTUATION_TYPE, '[', 'An array element was expected');
|
214 |
+
|
215 |
+
$node = new Twig_Node_Expression_Array(array(), $stream->getCurrent()->getLine());
|
216 |
+
$first = true;
|
217 |
+
while (!$stream->test(Twig_Token::PUNCTUATION_TYPE, ']')) {
|
218 |
+
if (!$first) {
|
219 |
+
$stream->expect(Twig_Token::PUNCTUATION_TYPE, ',', 'An array element must be followed by a comma');
|
220 |
+
|
221 |
+
// trailing ,?
|
222 |
+
if ($stream->test(Twig_Token::PUNCTUATION_TYPE, ']')) {
|
223 |
+
break;
|
224 |
+
}
|
225 |
+
}
|
226 |
+
$first = false;
|
227 |
+
|
228 |
+
$node->addElement($this->parseExpression());
|
229 |
+
}
|
230 |
+
$stream->expect(Twig_Token::PUNCTUATION_TYPE, ']', 'An opened array is not properly closed');
|
231 |
+
|
232 |
+
return $node;
|
233 |
+
}
|
234 |
+
|
235 |
+
public function parseHashExpression()
|
236 |
+
{
|
237 |
+
$stream = $this->parser->getStream();
|
238 |
+
$stream->expect(Twig_Token::PUNCTUATION_TYPE, '{', 'A hash element was expected');
|
239 |
+
|
240 |
+
$node = new Twig_Node_Expression_Array(array(), $stream->getCurrent()->getLine());
|
241 |
+
$first = true;
|
242 |
+
while (!$stream->test(Twig_Token::PUNCTUATION_TYPE, '}')) {
|
243 |
+
if (!$first) {
|
244 |
+
$stream->expect(Twig_Token::PUNCTUATION_TYPE, ',', 'A hash value must be followed by a comma');
|
245 |
+
|
246 |
+
// trailing ,?
|
247 |
+
if ($stream->test(Twig_Token::PUNCTUATION_TYPE, '}')) {
|
248 |
+
break;
|
249 |
+
}
|
250 |
+
}
|
251 |
+
$first = false;
|
252 |
+
|
253 |
+
// a hash key can be:
|
254 |
+
//
|
255 |
+
// * a number -- 12
|
256 |
+
// * a string -- 'a'
|
257 |
+
// * a name, which is equivalent to a string -- a
|
258 |
+
// * an expression, which must be enclosed in parentheses -- (1 + 2)
|
259 |
+
if (($token = $stream->nextIf(Twig_Token::STRING_TYPE)) || ($token = $stream->nextIf(Twig_Token::NAME_TYPE)) || $token = $stream->nextIf(Twig_Token::NUMBER_TYPE)) {
|
260 |
+
$key = new Twig_Node_Expression_Constant($token->getValue(), $token->getLine());
|
261 |
+
} elseif ($stream->test(Twig_Token::PUNCTUATION_TYPE, '(')) {
|
262 |
+
$key = $this->parseExpression();
|
263 |
+
} else {
|
264 |
+
$current = $stream->getCurrent();
|
265 |
+
|
266 |
+
throw new Twig_Error_Syntax(sprintf('A hash key must be a quoted string, a number, a name, or an expression enclosed in parentheses (unexpected token "%s" of value "%s"', Twig_Token::typeToEnglish($current->getType()), $current->getValue()), $current->getLine(), $this->parser->getFilename());
|
267 |
+
}
|
268 |
+
|
269 |
+
$stream->expect(Twig_Token::PUNCTUATION_TYPE, ':', 'A hash key must be followed by a colon (:)');
|
270 |
+
$value = $this->parseExpression();
|
271 |
+
|
272 |
+
$node->addElement($value, $key);
|
273 |
+
}
|
274 |
+
$stream->expect(Twig_Token::PUNCTUATION_TYPE, '}', 'An opened hash is not properly closed');
|
275 |
+
|
276 |
+
return $node;
|
277 |
+
}
|
278 |
+
|
279 |
+
public function parsePostfixExpression($node)
|
280 |
+
{
|
281 |
+
while (true) {
|
282 |
+
$token = $this->parser->getCurrentToken();
|
283 |
+
if ($token->getType() == Twig_Token::PUNCTUATION_TYPE) {
|
284 |
+
if ('.' == $token->getValue() || '[' == $token->getValue()) {
|
285 |
+
$node = $this->parseSubscriptExpression($node);
|
286 |
+
} elseif ('|' == $token->getValue()) {
|
287 |
+
$node = $this->parseFilterExpression($node);
|
288 |
+
} else {
|
289 |
+
break;
|
290 |
+
}
|
291 |
+
} else {
|
292 |
+
break;
|
293 |
+
}
|
294 |
+
}
|
295 |
+
|
296 |
+
return $node;
|
297 |
+
}
|
298 |
+
|
299 |
+
public function getFunctionNode($name, $line)
|
300 |
+
{
|
301 |
+
switch ($name) {
|
302 |
+
case 'parent':
|
303 |
+
$args = $this->parseArguments();
|
304 |
+
if (!count($this->parser->getBlockStack())) {
|
305 |
+
throw new Twig_Error_Syntax('Calling "parent" outside a block is forbidden', $line, $this->parser->getFilename());
|
306 |
+
}
|
307 |
+
|
308 |
+
if (!$this->parser->getParent() && !$this->parser->hasTraits()) {
|
309 |
+
throw new Twig_Error_Syntax('Calling "parent" on a template that does not extend nor "use" another template is forbidden', $line, $this->parser->getFilename());
|
310 |
+
}
|
311 |
+
|
312 |
+
return new Twig_Node_Expression_Parent($this->parser->peekBlockStack(), $line);
|
313 |
+
case 'block':
|
314 |
+
return new Twig_Node_Expression_BlockReference($this->parseArguments()->getNode(0), false, $line);
|
315 |
+
case 'attribute':
|
316 |
+
$args = $this->parseArguments();
|
317 |
+
if (count($args) < 2) {
|
318 |
+
throw new Twig_Error_Syntax('The "attribute" function takes at least two arguments (the variable and the attributes)', $line, $this->parser->getFilename());
|
319 |
+
}
|
320 |
+
|
321 |
+
return new Twig_Node_Expression_GetAttr($args->getNode(0), $args->getNode(1), count($args) > 2 ? $args->getNode(2) : new Twig_Node_Expression_Array(array(), $line), Twig_Template::ANY_CALL, $line);
|
322 |
+
default:
|
323 |
+
if (null !== $alias = $this->parser->getImportedSymbol('function', $name)) {
|
324 |
+
$arguments = new Twig_Node_Expression_Array(array(), $line);
|
325 |
+
foreach ($this->parseArguments() as $n) {
|
326 |
+
$arguments->addElement($n);
|
327 |
+
}
|
328 |
+
|
329 |
+
$node = new Twig_Node_Expression_MethodCall($alias['node'], $alias['name'], $arguments, $line);
|
330 |
+
$node->setAttribute('safe', true);
|
331 |
+
|
332 |
+
return $node;
|
333 |
+
}
|
334 |
+
|
335 |
+
$args = $this->parseArguments(true);
|
336 |
+
$class = $this->getFunctionNodeClass($name, $line);
|
337 |
+
|
338 |
+
return new $class($name, $args, $line);
|
339 |
+
}
|
340 |
+
}
|
341 |
+
|
342 |
+
public function parseSubscriptExpression($node)
|
343 |
+
{
|
344 |
+
$stream = $this->parser->getStream();
|
345 |
+
$token = $stream->next();
|
346 |
+
$lineno = $token->getLine();
|
347 |
+
$arguments = new Twig_Node_Expression_Array(array(), $lineno);
|
348 |
+
$type = Twig_Template::ANY_CALL;
|
349 |
+
if ($token->getValue() == '.') {
|
350 |
+
$token = $stream->next();
|
351 |
+
if (
|
352 |
+
$token->getType() == Twig_Token::NAME_TYPE
|
353 |
+
||
|
354 |
+
$token->getType() == Twig_Token::NUMBER_TYPE
|
355 |
+
||
|
356 |
+
($token->getType() == Twig_Token::OPERATOR_TYPE && preg_match(Twig_Lexer::REGEX_NAME, $token->getValue()))
|
357 |
+
) {
|
358 |
+
$arg = new Twig_Node_Expression_Constant($token->getValue(), $lineno);
|
359 |
+
|
360 |
+
if ($stream->test(Twig_Token::PUNCTUATION_TYPE, '(')) {
|
361 |
+
$type = Twig_TemplateInterface::METHOD_CALL;
|
362 |
+
foreach ($this->parseArguments() as $n) {
|
363 |
+
$arguments->addElement($n);
|
364 |
+
}
|
365 |
+
}
|
366 |
+
} else {
|
367 |
+
throw new Twig_Error_Syntax('Expected name or number', $lineno, $this->parser->getFilename());
|
368 |
+
}
|
369 |
+
|
370 |
+
if ($node instanceof Twig_Node_Expression_Name && null !== $this->parser->getImportedSymbol('template', $node->getAttribute('name'))) {
|
371 |
+
if (!$arg instanceof Twig_Node_Expression_Constant) {
|
372 |
+
throw new Twig_Error_Syntax(sprintf('Dynamic macro names are not supported (called on "%s")', $node->getAttribute('name')), $token->getLine(), $this->parser->getFilename());
|
373 |
+
}
|
374 |
+
|
375 |
+
$node = new Twig_Node_Expression_MethodCall($node, 'get'.$arg->getAttribute('value'), $arguments, $lineno);
|
376 |
+
$node->setAttribute('safe', true);
|
377 |
+
|
378 |
+
return $node;
|
379 |
+
}
|
380 |
+
} else {
|
381 |
+
$type = Twig_Template::ARRAY_CALL;
|
382 |
+
|
383 |
+
// slice?
|
384 |
+
$slice = false;
|
385 |
+
if ($stream->test(Twig_Token::PUNCTUATION_TYPE, ':')) {
|
386 |
+
$slice = true;
|
387 |
+
$arg = new Twig_Node_Expression_Constant(0, $token->getLine());
|
388 |
+
} else {
|
389 |
+
$arg = $this->parseExpression();
|
390 |
+
}
|
391 |
+
|
392 |
+
if ($stream->nextIf(Twig_Token::PUNCTUATION_TYPE, ':')) {
|
393 |
+
$slice = true;
|
394 |
+
}
|
395 |
+
|
396 |
+
if ($slice) {
|
397 |
+
if ($stream->test(Twig_Token::PUNCTUATION_TYPE, ']')) {
|
398 |
+
$length = new Twig_Node_Expression_Constant(null, $token->getLine());
|
399 |
+
} else {
|
400 |
+
$length = $this->parseExpression();
|
401 |
+
}
|
402 |
+
|
403 |
+
$class = $this->getFilterNodeClass('slice', $token->getLine());
|
404 |
+
$arguments = new Twig_Node(array($arg, $length));
|
405 |
+
$filter = new $class($node, new Twig_Node_Expression_Constant('slice', $token->getLine()), $arguments, $token->getLine());
|
406 |
+
|
407 |
+
$stream->expect(Twig_Token::PUNCTUATION_TYPE, ']');
|
408 |
+
|
409 |
+
return $filter;
|
410 |
+
}
|
411 |
+
|
412 |
+
$stream->expect(Twig_Token::PUNCTUATION_TYPE, ']');
|
413 |
+
}
|
414 |
+
|
415 |
+
return new Twig_Node_Expression_GetAttr($node, $arg, $arguments, $type, $lineno);
|
416 |
+
}
|
417 |
+
|
418 |
+
public function parseFilterExpression($node)
|
419 |
+
{
|
420 |
+
$this->parser->getStream()->next();
|
421 |
+
|
422 |
+
return $this->parseFilterExpressionRaw($node);
|
423 |
+
}
|
424 |
+
|
425 |
+
public function parseFilterExpressionRaw($node, $tag = null)
|
426 |
+
{
|
427 |
+
while (true) {
|
428 |
+
$token = $this->parser->getStream()->expect(Twig_Token::NAME_TYPE);
|
429 |
+
|
430 |
+
$name = new Twig_Node_Expression_Constant($token->getValue(), $token->getLine());
|
431 |
+
if (!$this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, '(')) {
|
432 |
+
$arguments = new Twig_Node();
|
433 |
+
} else {
|
434 |
+
$arguments = $this->parseArguments(true);
|
435 |
+
}
|
436 |
+
|
437 |
+
$class = $this->getFilterNodeClass($name->getAttribute('value'), $token->getLine());
|
438 |
+
|
439 |
+
$node = new $class($node, $name, $arguments, $token->getLine(), $tag);
|
440 |
+
|
441 |
+
if (!$this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, '|')) {
|
442 |
+
break;
|
443 |
+
}
|
444 |
+
|
445 |
+
$this->parser->getStream()->next();
|
446 |
+
}
|
447 |
+
|
448 |
+
return $node;
|
449 |
+
}
|
450 |
+
|
451 |
+
/**
|
452 |
+
* Parses arguments.
|
453 |
+
*
|
454 |
+
* @param bool $namedArguments Whether to allow named arguments or not
|
455 |
+
* @param bool $definition Whether we are parsing arguments for a function definition
|
456 |
+
*/
|
457 |
+
public function parseArguments($namedArguments = false, $definition = false)
|
458 |
+
{
|
459 |
+
$args = array();
|
460 |
+
$stream = $this->parser->getStream();
|
461 |
+
|
462 |
+
$stream->expect(Twig_Token::PUNCTUATION_TYPE, '(', 'A list of arguments must begin with an opening parenthesis');
|
463 |
+
while (!$stream->test(Twig_Token::PUNCTUATION_TYPE, ')')) {
|
464 |
+
if (!empty($args)) {
|
465 |
+
$stream->expect(Twig_Token::PUNCTUATION_TYPE, ',', 'Arguments must be separated by a comma');
|
466 |
+
}
|
467 |
+
|
468 |
+
if ($definition) {
|
469 |
+
$token = $stream->expect(Twig_Token::NAME_TYPE, null, 'An argument must be a name');
|
470 |
+
$value = new Twig_Node_Expression_Name($token->getValue(), $this->parser->getCurrentToken()->getLine());
|
471 |
+
} else {
|
472 |
+
$value = $this->parseExpression();
|
473 |
+
}
|
474 |
+
|
475 |
+
$name = null;
|
476 |
+
if ($namedArguments && $token = $stream->nextIf(Twig_Token::OPERATOR_TYPE, '=')) {
|
477 |
+
if (!$value instanceof Twig_Node_Expression_Name) {
|
478 |
+
throw new Twig_Error_Syntax(sprintf('A parameter name must be a string, "%s" given', get_class($value)), $token->getLine(), $this->parser->getFilename());
|
479 |
+
}
|
480 |
+
$name = $value->getAttribute('name');
|
481 |
+
|
482 |
+
if ($definition) {
|
483 |
+
$value = $this->parsePrimaryExpression();
|
484 |
+
|
485 |
+
if (!$this->checkConstantExpression($value)) {
|
486 |
+
throw new Twig_Error_Syntax(sprintf('A default value for an argument must be a constant (a boolean, a string, a number, or an array).'), $token->getLine(), $this->parser->getFilename());
|
487 |
+
}
|
488 |
+
} else {
|
489 |
+
$value = $this->parseExpression();
|
490 |
+
}
|
491 |
+
}
|
492 |
+
|
493 |
+
if ($definition) {
|
494 |
+
if (null === $name) {
|
495 |
+
$name = $value->getAttribute('name');
|
496 |
+
$value = new Twig_Node_Expression_Constant(null, $this->parser->getCurrentToken()->getLine());
|
497 |
+
}
|
498 |
+
$args[$name] = $value;
|
499 |
+
} else {
|
500 |
+
if (null === $name) {
|
501 |
+
$args[] = $value;
|
502 |
+
} else {
|
503 |
+
$args[$name] = $value;
|
504 |
+
}
|
505 |
+
}
|
506 |
+
}
|
507 |
+
$stream->expect(Twig_Token::PUNCTUATION_TYPE, ')', 'A list of arguments must be closed by a parenthesis');
|
508 |
+
|
509 |
+
return new Twig_Node($args);
|
510 |
+
}
|
511 |
+
|
512 |
+
public function parseAssignmentExpression()
|
513 |
+
{
|
514 |
+
$targets = array();
|
515 |
+
while (true) {
|
516 |
+
$token = $this->parser->getStream()->expect(Twig_Token::NAME_TYPE, null, 'Only variables can be assigned to');
|
517 |
+
if (in_array($token->getValue(), array('true', 'false', 'none'))) {
|
518 |
+
throw new Twig_Error_Syntax(sprintf('You cannot assign a value to "%s"', $token->getValue()), $token->getLine(), $this->parser->getFilename());
|
519 |
+
}
|
520 |
+
$targets[] = new Twig_Node_Expression_AssignName($token->getValue(), $token->getLine());
|
521 |
+
|
522 |
+
if (!$this->parser->getStream()->nextIf(Twig_Token::PUNCTUATION_TYPE, ',')) {
|
523 |
+
break;
|
524 |
+
}
|
525 |
+
}
|
526 |
+
|
527 |
+
return new Twig_Node($targets);
|
528 |
+
}
|
529 |
+
|
530 |
+
public function parseMultitargetExpression()
|
531 |
+
{
|
532 |
+
$targets = array();
|
533 |
+
while (true) {
|
534 |
+
$targets[] = $this->parseExpression();
|
535 |
+
if (!$this->parser->getStream()->nextIf(Twig_Token::PUNCTUATION_TYPE, ',')) {
|
536 |
+
break;
|
537 |
+
}
|
538 |
+
}
|
539 |
+
|
540 |
+
return new Twig_Node($targets);
|
541 |
+
}
|
542 |
+
|
543 |
+
protected function getFunctionNodeClass($name, $line)
|
544 |
+
{
|
545 |
+
$env = $this->parser->getEnvironment();
|
546 |
+
|
547 |
+
if (false === $function = $env->getFunction($name)) {
|
548 |
+
$message = sprintf('The function "%s" does not exist', $name);
|
549 |
+
if ($alternatives = $env->computeAlternatives($name, array_keys($env->getFunctions()))) {
|
550 |
+
$message = sprintf('%s. Did you mean "%s"', $message, implode('", "', $alternatives));
|
551 |
+
}
|
552 |
+
|
553 |
+
throw new Twig_Error_Syntax($message, $line, $this->parser->getFilename());
|
554 |
+
}
|
555 |
+
|
556 |
+
if ($function instanceof Twig_SimpleFunction) {
|
557 |
+
return $function->getNodeClass();
|
558 |
+
}
|
559 |
+
|
560 |
+
return $function instanceof Twig_Function_Node ? $function->getClass() : 'Twig_Node_Expression_Function';
|
561 |
+
}
|
562 |
+
|
563 |
+
protected function getFilterNodeClass($name, $line)
|
564 |
+
{
|
565 |
+
$env = $this->parser->getEnvironment();
|
566 |
+
|
567 |
+
if (false === $filter = $env->getFilter($name)) {
|
568 |
+
$message = sprintf('The filter "%s" does not exist', $name);
|
569 |
+
if ($alternatives = $env->computeAlternatives($name, array_keys($env->getFilters()))) {
|
570 |
+
$message = sprintf('%s. Did you mean "%s"', $message, implode('", "', $alternatives));
|
571 |
+
}
|
572 |
+
|
573 |
+
throw new Twig_Error_Syntax($message, $line, $this->parser->getFilename());
|
574 |
+
}
|
575 |
+
|
576 |
+
if ($filter instanceof Twig_SimpleFilter) {
|
577 |
+
return $filter->getNodeClass();
|
578 |
+
}
|
579 |
+
|
580 |
+
return $filter instanceof Twig_Filter_Node ? $filter->getClass() : 'Twig_Node_Expression_Filter';
|
581 |
+
}
|
582 |
+
|
583 |
+
// checks that the node only contains "constant" elements
|
584 |
+
protected function checkConstantExpression(Twig_NodeInterface $node)
|
585 |
+
{
|
586 |
+
if (!($node instanceof Twig_Node_Expression_Constant || $node instanceof Twig_Node_Expression_Array)) {
|
587 |
+
return false;
|
588 |
+
}
|
589 |
+
|
590 |
+
foreach ($node as $n) {
|
591 |
+
if (!$this->checkConstantExpression($n)) {
|
592 |
+
return false;
|
593 |
+
}
|
594 |
+
}
|
595 |
+
|
596 |
+
return true;
|
597 |
+
}
|
598 |
+
}
|
classes/Twig/Extension.php
CHANGED
@@ -1,93 +1,93 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2009 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
abstract class Twig_Extension implements Twig_ExtensionInterface
|
12 |
-
{
|
13 |
-
/**
|
14 |
-
* Initializes the runtime environment.
|
15 |
-
*
|
16 |
-
* This is where you can load some file that contains filter functions for instance.
|
17 |
-
*
|
18 |
-
* @param Twig_Environment $environment The current Twig_Environment instance
|
19 |
-
*/
|
20 |
-
public function initRuntime(Twig_Environment $environment)
|
21 |
-
{
|
22 |
-
}
|
23 |
-
|
24 |
-
/**
|
25 |
-
* Returns the token parser instances to add to the existing list.
|
26 |
-
*
|
27 |
-
* @return array An array of Twig_TokenParserInterface or Twig_TokenParserBrokerInterface instances
|
28 |
-
*/
|
29 |
-
public function getTokenParsers()
|
30 |
-
{
|
31 |
-
return array();
|
32 |
-
}
|
33 |
-
|
34 |
-
/**
|
35 |
-
* Returns the node visitor instances to add to the existing list.
|
36 |
-
*
|
37 |
-
* @return Twig_NodeVisitorInterface[] An array of Twig_NodeVisitorInterface instances
|
38 |
-
*/
|
39 |
-
public function getNodeVisitors()
|
40 |
-
{
|
41 |
-
return array();
|
42 |
-
}
|
43 |
-
|
44 |
-
/**
|
45 |
-
* Returns a list of filters to add to the existing list.
|
46 |
-
*
|
47 |
-
* @return array An array of filters
|
48 |
-
*/
|
49 |
-
public function getFilters()
|
50 |
-
{
|
51 |
-
return array();
|
52 |
-
}
|
53 |
-
|
54 |
-
/**
|
55 |
-
* Returns a list of tests to add to the existing list.
|
56 |
-
*
|
57 |
-
* @return array An array of tests
|
58 |
-
*/
|
59 |
-
public function getTests()
|
60 |
-
{
|
61 |
-
return array();
|
62 |
-
}
|
63 |
-
|
64 |
-
/**
|
65 |
-
* Returns a list of functions to add to the existing list.
|
66 |
-
*
|
67 |
-
* @return array An array of functions
|
68 |
-
*/
|
69 |
-
public function getFunctions()
|
70 |
-
{
|
71 |
-
return array();
|
72 |
-
}
|
73 |
-
|
74 |
-
/**
|
75 |
-
* Returns a list of operators to add to the existing list.
|
76 |
-
*
|
77 |
-
* @return array An array of operators
|
78 |
-
*/
|
79 |
-
public function getOperators()
|
80 |
-
{
|
81 |
-
return array();
|
82 |
-
}
|
83 |
-
|
84 |
-
/**
|
85 |
-
* Returns a list of global variables to add to the existing list.
|
86 |
-
*
|
87 |
-
* @return array An array of global variables
|
88 |
-
*/
|
89 |
-
public function getGlobals()
|
90 |
-
{
|
91 |
-
return array();
|
92 |
-
}
|
93 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2009 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
abstract class Twig_Extension implements Twig_ExtensionInterface
|
12 |
+
{
|
13 |
+
/**
|
14 |
+
* Initializes the runtime environment.
|
15 |
+
*
|
16 |
+
* This is where you can load some file that contains filter functions for instance.
|
17 |
+
*
|
18 |
+
* @param Twig_Environment $environment The current Twig_Environment instance
|
19 |
+
*/
|
20 |
+
public function initRuntime(Twig_Environment $environment)
|
21 |
+
{
|
22 |
+
}
|
23 |
+
|
24 |
+
/**
|
25 |
+
* Returns the token parser instances to add to the existing list.
|
26 |
+
*
|
27 |
+
* @return array An array of Twig_TokenParserInterface or Twig_TokenParserBrokerInterface instances
|
28 |
+
*/
|
29 |
+
public function getTokenParsers()
|
30 |
+
{
|
31 |
+
return array();
|
32 |
+
}
|
33 |
+
|
34 |
+
/**
|
35 |
+
* Returns the node visitor instances to add to the existing list.
|
36 |
+
*
|
37 |
+
* @return Twig_NodeVisitorInterface[] An array of Twig_NodeVisitorInterface instances
|
38 |
+
*/
|
39 |
+
public function getNodeVisitors()
|
40 |
+
{
|
41 |
+
return array();
|
42 |
+
}
|
43 |
+
|
44 |
+
/**
|
45 |
+
* Returns a list of filters to add to the existing list.
|
46 |
+
*
|
47 |
+
* @return array An array of filters
|
48 |
+
*/
|
49 |
+
public function getFilters()
|
50 |
+
{
|
51 |
+
return array();
|
52 |
+
}
|
53 |
+
|
54 |
+
/**
|
55 |
+
* Returns a list of tests to add to the existing list.
|
56 |
+
*
|
57 |
+
* @return array An array of tests
|
58 |
+
*/
|
59 |
+
public function getTests()
|
60 |
+
{
|
61 |
+
return array();
|
62 |
+
}
|
63 |
+
|
64 |
+
/**
|
65 |
+
* Returns a list of functions to add to the existing list.
|
66 |
+
*
|
67 |
+
* @return array An array of functions
|
68 |
+
*/
|
69 |
+
public function getFunctions()
|
70 |
+
{
|
71 |
+
return array();
|
72 |
+
}
|
73 |
+
|
74 |
+
/**
|
75 |
+
* Returns a list of operators to add to the existing list.
|
76 |
+
*
|
77 |
+
* @return array An array of operators
|
78 |
+
*/
|
79 |
+
public function getOperators()
|
80 |
+
{
|
81 |
+
return array();
|
82 |
+
}
|
83 |
+
|
84 |
+
/**
|
85 |
+
* Returns a list of global variables to add to the existing list.
|
86 |
+
*
|
87 |
+
* @return array An array of global variables
|
88 |
+
*/
|
89 |
+
public function getGlobals()
|
90 |
+
{
|
91 |
+
return array();
|
92 |
+
}
|
93 |
+
}
|
classes/Twig/Extension/Core.php
CHANGED
@@ -1,1462 +1,1462 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
if (!defined('ENT_SUBSTITUTE')) {
|
4 |
-
// use 0 as hhvm does not support several flags yet
|
5 |
-
define('ENT_SUBSTITUTE', 0);
|
6 |
-
}
|
7 |
-
|
8 |
-
/*
|
9 |
-
* This file is part of Twig.
|
10 |
-
*
|
11 |
-
* (c) 2009 Fabien Potencier
|
12 |
-
*
|
13 |
-
* For the full copyright and license information, please view the LICENSE
|
14 |
-
* file that was distributed with this source code.
|
15 |
-
*/
|
16 |
-
class Twig_Extension_Core extends Twig_Extension
|
17 |
-
{
|
18 |
-
protected $dateFormats = array('F j, Y H:i', '%d days');
|
19 |
-
protected $numberFormat = array(0, '.', ',');
|
20 |
-
protected $timezone = null;
|
21 |
-
protected $escapers = array();
|
22 |
-
|
23 |
-
/**
|
24 |
-
* Defines a new escaper to be used via the escape filter.
|
25 |
-
*
|
26 |
-
* @param string $strategy The strategy name that should be used as a strategy in the escape call
|
27 |
-
* @param callable $callable A valid PHP callable
|
28 |
-
*/
|
29 |
-
public function setEscaper($strategy, $callable)
|
30 |
-
{
|
31 |
-
$this->escapers[$strategy] = $callable;
|
32 |
-
}
|
33 |
-
|
34 |
-
/**
|
35 |
-
* Gets all defined escapers.
|
36 |
-
*
|
37 |
-
* @return array An array of escapers
|
38 |
-
*/
|
39 |
-
public function getEscapers()
|
40 |
-
{
|
41 |
-
return $this->escapers;
|
42 |
-
}
|
43 |
-
|
44 |
-
/**
|
45 |
-
* Sets the default format to be used by the date filter.
|
46 |
-
*
|
47 |
-
* @param string $format The default date format string
|
48 |
-
* @param string $dateIntervalFormat The default date interval format string
|
49 |
-
*/
|
50 |
-
public function setDateFormat($format = null, $dateIntervalFormat = null)
|
51 |
-
{
|
52 |
-
if (null !== $format) {
|
53 |
-
$this->dateFormats[0] = $format;
|
54 |
-
}
|
55 |
-
|
56 |
-
if (null !== $dateIntervalFormat) {
|
57 |
-
$this->dateFormats[1] = $dateIntervalFormat;
|
58 |
-
}
|
59 |
-
}
|
60 |
-
|
61 |
-
/**
|
62 |
-
* Gets the default format to be used by the date filter.
|
63 |
-
*
|
64 |
-
* @return array The default date format string and the default date interval format string
|
65 |
-
*/
|
66 |
-
public function getDateFormat()
|
67 |
-
{
|
68 |
-
return $this->dateFormats;
|
69 |
-
}
|
70 |
-
|
71 |
-
/**
|
72 |
-
* Sets the default timezone to be used by the date filter.
|
73 |
-
*
|
74 |
-
* @param DateTimeZone|string $timezone The default timezone string or a DateTimeZone object
|
75 |
-
*/
|
76 |
-
public function setTimezone($timezone)
|
77 |
-
{
|
78 |
-
$this->timezone = $timezone instanceof DateTimeZone ? $timezone : new DateTimeZone($timezone);
|
79 |
-
}
|
80 |
-
|
81 |
-
/**
|
82 |
-
* Gets the default timezone to be used by the date filter.
|
83 |
-
*
|
84 |
-
* @return DateTimeZone The default timezone currently in use
|
85 |
-
*/
|
86 |
-
public function getTimezone()
|
87 |
-
{
|
88 |
-
if (null === $this->timezone) {
|
89 |
-
$this->timezone = new DateTimeZone(date_default_timezone_get());
|
90 |
-
}
|
91 |
-
|
92 |
-
return $this->timezone;
|
93 |
-
}
|
94 |
-
|
95 |
-
/**
|
96 |
-
* Sets the default format to be used by the number_format filter.
|
97 |
-
*
|
98 |
-
* @param int $decimal The number of decimal places to use.
|
99 |
-
* @param string $decimalPoint The character(s) to use for the decimal point.
|
100 |
-
* @param string $thousandSep The character(s) to use for the thousands separator.
|
101 |
-
*/
|
102 |
-
public function setNumberFormat($decimal, $decimalPoint, $thousandSep)
|
103 |
-
{
|
104 |
-
$this->numberFormat = array($decimal, $decimalPoint, $thousandSep);
|
105 |
-
}
|
106 |
-
|
107 |
-
/**
|
108 |
-
* Get the default format used by the number_format filter.
|
109 |
-
*
|
110 |
-
* @return array The arguments for number_format()
|
111 |
-
*/
|
112 |
-
public function getNumberFormat()
|
113 |
-
{
|
114 |
-
return $this->numberFormat;
|
115 |
-
}
|
116 |
-
|
117 |
-
/**
|
118 |
-
* Returns the token parser instance to add to the existing list.
|
119 |
-
*
|
120 |
-
* @return Twig_TokenParser[] An array of Twig_TokenParser instances
|
121 |
-
*/
|
122 |
-
public function getTokenParsers()
|
123 |
-
{
|
124 |
-
return array(
|
125 |
-
new Twig_TokenParser_For(),
|
126 |
-
new Twig_TokenParser_If(),
|
127 |
-
new Twig_TokenParser_Extends(),
|
128 |
-
new Twig_TokenParser_Include(),
|
129 |
-
new Twig_TokenParser_Block(),
|
130 |
-
new Twig_TokenParser_Use(),
|
131 |
-
new Twig_TokenParser_Filter(),
|
132 |
-
new Twig_TokenParser_Macro(),
|
133 |
-
new Twig_TokenParser_Import(),
|
134 |
-
new Twig_TokenParser_From(),
|
135 |
-
new Twig_TokenParser_Set(),
|
136 |
-
new Twig_TokenParser_Spaceless(),
|
137 |
-
new Twig_TokenParser_Flush(),
|
138 |
-
new Twig_TokenParser_Do(),
|
139 |
-
new Twig_TokenParser_Embed(),
|
140 |
-
);
|
141 |
-
}
|
142 |
-
|
143 |
-
/**
|
144 |
-
* Returns a list of filters to add to the existing list.
|
145 |
-
*
|
146 |
-
* @return array An array of filters
|
147 |
-
*/
|
148 |
-
public function getFilters()
|
149 |
-
{
|
150 |
-
$filters = array(
|
151 |
-
// formatting filters
|
152 |
-
new Twig_SimpleFilter('date', 'twig_date_format_filter', array('needs_environment' => true)),
|
153 |
-
new Twig_SimpleFilter('date_modify', 'twig_date_modify_filter', array('needs_environment' => true)),
|
154 |
-
new Twig_SimpleFilter('format', 'sprintf'),
|
155 |
-
new Twig_SimpleFilter('replace', 'strtr'),
|
156 |
-
new Twig_SimpleFilter('number_format', 'twig_number_format_filter', array('needs_environment' => true)),
|
157 |
-
new Twig_SimpleFilter('abs', 'abs'),
|
158 |
-
new Twig_SimpleFilter('round', 'twig_round'),
|
159 |
-
|
160 |
-
// encoding
|
161 |
-
new Twig_SimpleFilter('url_encode', 'twig_urlencode_filter'),
|
162 |
-
new Twig_SimpleFilter('json_encode', 'twig_jsonencode_filter'),
|
163 |
-
new Twig_SimpleFilter('convert_encoding', 'twig_convert_encoding'),
|
164 |
-
|
165 |
-
// string filters
|
166 |
-
new Twig_SimpleFilter('title', 'twig_title_string_filter', array('needs_environment' => true)),
|
167 |
-
new Twig_SimpleFilter('capitalize', 'twig_capitalize_string_filter', array('needs_environment' => true)),
|
168 |
-
new Twig_SimpleFilter('upper', 'strtoupper'),
|
169 |
-
new Twig_SimpleFilter('lower', 'strtolower'),
|
170 |
-
new Twig_SimpleFilter('striptags', 'strip_tags'),
|
171 |
-
new Twig_SimpleFilter('trim', 'trim'),
|
172 |
-
new Twig_SimpleFilter('nl2br', 'nl2br', array('pre_escape' => 'html', 'is_safe' => array('html'))),
|
173 |
-
|
174 |
-
// array helpers
|
175 |
-
new Twig_SimpleFilter('join', 'twig_join_filter'),
|
176 |
-
new Twig_SimpleFilter('split', 'twig_split_filter'),
|
177 |
-
new Twig_SimpleFilter('sort', 'twig_sort_filter'),
|
178 |
-
new Twig_SimpleFilter('merge', 'twig_array_merge'),
|
179 |
-
new Twig_SimpleFilter('batch', 'twig_array_batch'),
|
180 |
-
|
181 |
-
// string/array filters
|
182 |
-
new Twig_SimpleFilter('reverse', 'twig_reverse_filter', array('needs_environment' => true)),
|
183 |
-
new Twig_SimpleFilter('length', 'twig_length_filter', array('needs_environment' => true)),
|
184 |
-
new Twig_SimpleFilter('slice', 'twig_slice', array('needs_environment' => true)),
|
185 |
-
new Twig_SimpleFilter('first', 'twig_first', array('needs_environment' => true)),
|
186 |
-
new Twig_SimpleFilter('last', 'twig_last', array('needs_environment' => true)),
|
187 |
-
|
188 |
-
// iteration and runtime
|
189 |
-
new Twig_SimpleFilter('default', '_twig_default_filter', array('node_class' => 'Twig_Node_Expression_Filter_Default')),
|
190 |
-
new Twig_SimpleFilter('keys', 'twig_get_array_keys_filter'),
|
191 |
-
|
192 |
-
// escaping
|
193 |
-
new Twig_SimpleFilter('escape', 'twig_escape_filter', array('needs_environment' => true, 'is_safe_callback' => 'twig_escape_filter_is_safe')),
|
194 |
-
new Twig_SimpleFilter('e', 'twig_escape_filter', array('needs_environment' => true, 'is_safe_callback' => 'twig_escape_filter_is_safe')),
|
195 |
-
);
|
196 |
-
|
197 |
-
if (function_exists('mb_get_info')) {
|
198 |
-
$filters[] = new Twig_SimpleFilter('upper', 'twig_upper_filter', array('needs_environment' => true));
|
199 |
-
$filters[] = new Twig_SimpleFilter('lower', 'twig_lower_filter', array('needs_environment' => true));
|
200 |
-
}
|
201 |
-
|
202 |
-
return $filters;
|
203 |
-
}
|
204 |
-
|
205 |
-
/**
|
206 |
-
* Returns a list of global functions to add to the existing list.
|
207 |
-
*
|
208 |
-
* @return array An array of global functions
|
209 |
-
*/
|
210 |
-
public function getFunctions()
|
211 |
-
{
|
212 |
-
return array(
|
213 |
-
new Twig_SimpleFunction('max', 'max'),
|
214 |
-
new Twig_SimpleFunction('min', 'min'),
|
215 |
-
new Twig_SimpleFunction('range', 'range'),
|
216 |
-
new Twig_SimpleFunction('constant', 'twig_constant'),
|
217 |
-
new Twig_SimpleFunction('cycle', 'twig_cycle'),
|
218 |
-
new Twig_SimpleFunction('random', 'twig_random', array('needs_environment' => true)),
|
219 |
-
new Twig_SimpleFunction('date', 'twig_date_converter', array('needs_environment' => true)),
|
220 |
-
new Twig_SimpleFunction('include', 'twig_include', array('needs_environment' => true, 'needs_context' => true, 'is_safe' => array('all'))),
|
221 |
-
new Twig_SimpleFunction('source', 'twig_source', array('needs_environment' => true, 'is_safe' => array('all'))),
|
222 |
-
);
|
223 |
-
}
|
224 |
-
|
225 |
-
/**
|
226 |
-
* Returns a list of tests to add to the existing list.
|
227 |
-
*
|
228 |
-
* @return array An array of tests
|
229 |
-
*/
|
230 |
-
public function getTests()
|
231 |
-
{
|
232 |
-
return array(
|
233 |
-
new Twig_SimpleTest('even', null, array('node_class' => 'Twig_Node_Expression_Test_Even')),
|
234 |
-
new Twig_SimpleTest('odd', null, array('node_class' => 'Twig_Node_Expression_Test_Odd')),
|
235 |
-
new Twig_SimpleTest('defined', null, array('node_class' => 'Twig_Node_Expression_Test_Defined')),
|
236 |
-
new Twig_SimpleTest('sameas', null, array('node_class' => 'Twig_Node_Expression_Test_Sameas')),
|
237 |
-
new Twig_SimpleTest('same as', null, array('node_class' => 'Twig_Node_Expression_Test_Sameas')),
|
238 |
-
new Twig_SimpleTest('none', null, array('node_class' => 'Twig_Node_Expression_Test_Null')),
|
239 |
-
new Twig_SimpleTest('null', null, array('node_class' => 'Twig_Node_Expression_Test_Null')),
|
240 |
-
new Twig_SimpleTest('divisibleby', null, array('node_class' => 'Twig_Node_Expression_Test_Divisibleby')),
|
241 |
-
new Twig_SimpleTest('divisible by', null, array('node_class' => 'Twig_Node_Expression_Test_Divisibleby')),
|
242 |
-
new Twig_SimpleTest('constant', null, array('node_class' => 'Twig_Node_Expression_Test_Constant')),
|
243 |
-
new Twig_SimpleTest('empty', 'twig_test_empty'),
|
244 |
-
new Twig_SimpleTest('iterable', 'twig_test_iterable'),
|
245 |
-
);
|
246 |
-
}
|
247 |
-
|
248 |
-
/**
|
249 |
-
* Returns a list of operators to add to the existing list.
|
250 |
-
*
|
251 |
-
* @return array An array of operators
|
252 |
-
*/
|
253 |
-
public function getOperators()
|
254 |
-
{
|
255 |
-
return array(
|
256 |
-
array(
|
257 |
-
'not' => array('precedence' => 50, 'class' => 'Twig_Node_Expression_Unary_Not'),
|
258 |
-
'-' => array('precedence' => 500, 'class' => 'Twig_Node_Expression_Unary_Neg'),
|
259 |
-
'+' => array('precedence' => 500, 'class' => 'Twig_Node_Expression_Unary_Pos'),
|
260 |
-
),
|
261 |
-
array(
|
262 |
-
'or' => array('precedence' => 10, 'class' => 'Twig_Node_Expression_Binary_Or', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
|
263 |
-
'and' => array('precedence' => 15, 'class' => 'Twig_Node_Expression_Binary_And', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
|
264 |
-
'b-or' => array('precedence' => 16, 'class' => 'Twig_Node_Expression_Binary_BitwiseOr', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
|
265 |
-
'b-xor' => array('precedence' => 17, 'class' => 'Twig_Node_Expression_Binary_BitwiseXor', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
|
266 |
-
'b-and' => array('precedence' => 18, 'class' => 'Twig_Node_Expression_Binary_BitwiseAnd', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
|
267 |
-
'==' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_Equal', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
|
268 |
-
'!=' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_NotEqual', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
|
269 |
-
'<' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_Less', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
|
270 |
-
'>' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_Greater', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
|
271 |
-
'>=' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_GreaterEqual', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
|
272 |
-
'<=' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_LessEqual', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
|
273 |
-
'not in' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_NotIn', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
|
274 |
-
'in' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_In', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
|
275 |
-
'matches' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_Matches', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
|
276 |
-
'starts with' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_StartsWith', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
|
277 |
-
'ends with' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_EndsWith', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
|
278 |
-
'..' => array('precedence' => 25, 'class' => 'Twig_Node_Expression_Binary_Range', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
|
279 |
-
'+' => array('precedence' => 30, 'class' => 'Twig_Node_Expression_Binary_Add', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
|
280 |
-
'-' => array('precedence' => 30, 'class' => 'Twig_Node_Expression_Binary_Sub', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
|
281 |
-
'~' => array('precedence' => 40, 'class' => 'Twig_Node_Expression_Binary_Concat', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
|
282 |
-
'*' => array('precedence' => 60, 'class' => 'Twig_Node_Expression_Binary_Mul', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
|
283 |
-
'/' => array('precedence' => 60, 'class' => 'Twig_Node_Expression_Binary_Div', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
|
284 |
-
'//' => array('precedence' => 60, 'class' => 'Twig_Node_Expression_Binary_FloorDiv', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
|
285 |
-
'%' => array('precedence' => 60, 'class' => 'Twig_Node_Expression_Binary_Mod', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
|
286 |
-
'is' => array('precedence' => 100, 'callable' => array($this, 'parseTestExpression'), 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
|
287 |
-
'is not' => array('precedence' => 100, 'callable' => array($this, 'parseNotTestExpression'), 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
|
288 |
-
'**' => array('precedence' => 200, 'class' => 'Twig_Node_Expression_Binary_Power', 'associativity' => Twig_ExpressionParser::OPERATOR_RIGHT),
|
289 |
-
),
|
290 |
-
);
|
291 |
-
}
|
292 |
-
|
293 |
-
public function parseNotTestExpression(Twig_Parser $parser, Twig_NodeInterface $node)
|
294 |
-
{
|
295 |
-
return new Twig_Node_Expression_Unary_Not($this->parseTestExpression($parser, $node), $parser->getCurrentToken()->getLine());
|
296 |
-
}
|
297 |
-
|
298 |
-
public function parseTestExpression(Twig_Parser $parser, Twig_NodeInterface $node)
|
299 |
-
{
|
300 |
-
$stream = $parser->getStream();
|
301 |
-
$name = $stream->expect(Twig_Token::NAME_TYPE)->getValue();
|
302 |
-
$class = $this->getTestNodeClass($parser, $name, $node->getLine());
|
303 |
-
$arguments = null;
|
304 |
-
if ($stream->test(Twig_Token::PUNCTUATION_TYPE, '(')) {
|
305 |
-
$arguments = $parser->getExpressionParser()->parseArguments(true);
|
306 |
-
}
|
307 |
-
|
308 |
-
return new $class($node, $name, $arguments, $parser->getCurrentToken()->getLine());
|
309 |
-
}
|
310 |
-
|
311 |
-
protected function getTestNodeClass(Twig_Parser $parser, $name, $line)
|
312 |
-
{
|
313 |
-
$env = $parser->getEnvironment();
|
314 |
-
$testMap = $env->getTests();
|
315 |
-
$testName = null;
|
316 |
-
if (isset($testMap[$name])) {
|
317 |
-
$testName = $name;
|
318 |
-
} elseif ($parser->getStream()->test(Twig_Token::NAME_TYPE)) {
|
319 |
-
// try 2-words tests
|
320 |
-
$name = $name.' '.$parser->getCurrentToken()->getValue();
|
321 |
-
|
322 |
-
if (isset($testMap[$name])) {
|
323 |
-
$parser->getStream()->next();
|
324 |
-
|
325 |
-
$testName = $name;
|
326 |
-
}
|
327 |
-
}
|
328 |
-
|
329 |
-
if (null === $testName) {
|
330 |
-
$message = sprintf('The test "%s" does not exist', $name);
|
331 |
-
if ($alternatives = $env->computeAlternatives($name, array_keys($env->getTests()))) {
|
332 |
-
$message = sprintf('%s. Did you mean "%s"', $message, implode('", "', $alternatives));
|
333 |
-
}
|
334 |
-
|
335 |
-
throw new Twig_Error_Syntax($message, $line, $parser->getFilename());
|
336 |
-
}
|
337 |
-
|
338 |
-
if ($testMap[$name] instanceof Twig_SimpleTest) {
|
339 |
-
return $testMap[$name]->getNodeClass();
|
340 |
-
}
|
341 |
-
|
342 |
-
return $testMap[$name] instanceof Twig_Test_Node ? $testMap[$name]->getClass() : 'Twig_Node_Expression_Test';
|
343 |
-
}
|
344 |
-
|
345 |
-
/**
|
346 |
-
* Returns the name of the extension.
|
347 |
-
*
|
348 |
-
* @return string The extension name
|
349 |
-
*/
|
350 |
-
public function getName()
|
351 |
-
{
|
352 |
-
return 'core';
|
353 |
-
}
|
354 |
-
}
|
355 |
-
|
356 |
-
/**
|
357 |
-
* Cycles over a value.
|
358 |
-
*
|
359 |
-
* @param ArrayAccess|array $values An array or an ArrayAccess instance
|
360 |
-
* @param int $position The cycle position
|
361 |
-
*
|
362 |
-
* @return string The next value in the cycle
|
363 |
-
*/
|
364 |
-
function twig_cycle($values, $position)
|
365 |
-
{
|
366 |
-
if (!is_array($values) && !$values instanceof ArrayAccess) {
|
367 |
-
return $values;
|
368 |
-
}
|
369 |
-
|
370 |
-
return $values[$position % count($values)];
|
371 |
-
}
|
372 |
-
|
373 |
-
/**
|
374 |
-
* Returns a random value depending on the supplied parameter type:
|
375 |
-
* - a random item from a Traversable or array
|
376 |
-
* - a random character from a string
|
377 |
-
* - a random integer between 0 and the integer parameter
|
378 |
-
*
|
379 |
-
* @param Twig_Environment $env A Twig_Environment instance
|
380 |
-
* @param Traversable|array|int|string $values The values to pick a random item from
|
381 |
-
*
|
382 |
-
* @throws Twig_Error_Runtime When $values is an empty array (does not apply to an empty string which is returned as is).
|
383 |
-
*
|
384 |
-
* @return mixed A random value from the given sequence
|
385 |
-
*/
|
386 |
-
function twig_random(Twig_Environment $env, $values = null)
|
387 |
-
{
|
388 |
-
if (null === $values) {
|
389 |
-
return mt_rand();
|
390 |
-
}
|
391 |
-
|
392 |
-
if (is_int($values) || is_float($values)) {
|
393 |
-
return $values < 0 ? mt_rand($values, 0) : mt_rand(0, $values);
|
394 |
-
}
|
395 |
-
|
396 |
-
if ($values instanceof Traversable) {
|
397 |
-
$values = iterator_to_array($values);
|
398 |
-
} elseif (is_string($values)) {
|
399 |
-
if ('' === $values) {
|
400 |
-
return '';
|
401 |
-
}
|
402 |
-
if (null !== $charset = $env->getCharset()) {
|
403 |
-
if ('UTF-8' != $charset) {
|
404 |
-
$values = twig_convert_encoding($values, 'UTF-8', $charset);
|
405 |
-
}
|
406 |
-
|
407 |
-
// unicode version of str_split()
|
408 |
-
// split at all positions, but not after the start and not before the end
|
409 |
-
$values = preg_split('/(?<!^)(?!$)/u', $values);
|
410 |
-
|
411 |
-
if ('UTF-8' != $charset) {
|
412 |
-
foreach ($values as $i => $value) {
|
413 |
-
$values[$i] = twig_convert_encoding($value, $charset, 'UTF-8');
|
414 |
-
}
|
415 |
-
}
|
416 |
-
} else {
|
417 |
-
return $values[mt_rand(0, strlen($values) - 1)];
|
418 |
-
}
|
419 |
-
}
|
420 |
-
|
421 |
-
if (!is_array($values)) {
|
422 |
-
return $values;
|
423 |
-
}
|
424 |
-
|
425 |
-
if (0 === count($values)) {
|
426 |
-
throw new Twig_Error_Runtime('The random function cannot pick from an empty array.');
|
427 |
-
}
|
428 |
-
|
429 |
-
return $values[array_rand($values, 1)];
|
430 |
-
}
|
431 |
-
|
432 |
-
/**
|
433 |
-
* Converts a date to the given format.
|
434 |
-
*
|
435 |
-
* <pre>
|
436 |
-
* {{ post.published_at|date("m/d/Y") }}
|
437 |
-
* </pre>
|
438 |
-
*
|
439 |
-
* @param Twig_Environment $env A Twig_Environment instance
|
440 |
-
* @param DateTime|DateInterval|string $date A date
|
441 |
-
* @param string $format A format
|
442 |
-
* @param DateTimeZone|string $timezone A timezone
|
443 |
-
*
|
444 |
-
* @return string The formatted date
|
445 |
-
*/
|
446 |
-
function twig_date_format_filter(Twig_Environment $env, $date, $format = null, $timezone = null)
|
447 |
-
{
|
448 |
-
if (null === $format) {
|
449 |
-
$formats = $env->getExtension('core')->getDateFormat();
|
450 |
-
$format = $date instanceof DateInterval ? $formats[1] : $formats[0];
|
451 |
-
}
|
452 |
-
|
453 |
-
if ($date instanceof DateInterval) {
|
454 |
-
return $date->format($format);
|
455 |
-
}
|
456 |
-
|
457 |
-
return twig_date_converter($env, $date, $timezone)->format($format);
|
458 |
-
}
|
459 |
-
|
460 |
-
/**
|
461 |
-
* Returns a new date object modified
|
462 |
-
*
|
463 |
-
* <pre>
|
464 |
-
* {{ post.published_at|date_modify("-1day")|date("m/d/Y") }}
|
465 |
-
* </pre>
|
466 |
-
*
|
467 |
-
* @param Twig_Environment $env A Twig_Environment instance
|
468 |
-
* @param DateTime|string $date A date
|
469 |
-
* @param string $modifier A modifier string
|
470 |
-
*
|
471 |
-
* @return DateTime A new date object
|
472 |
-
*/
|
473 |
-
function twig_date_modify_filter(Twig_Environment $env, $date, $modifier)
|
474 |
-
{
|
475 |
-
$date = twig_date_converter($env, $date, false);
|
476 |
-
$date->modify($modifier);
|
477 |
-
|
478 |
-
return $date;
|
479 |
-
}
|
480 |
-
|
481 |
-
/**
|
482 |
-
* Converts an input to a DateTime instance.
|
483 |
-
*
|
484 |
-
* <pre>
|
485 |
-
* {% if date(user.created_at) < date('+2days') %}
|
486 |
-
* {# do something #}
|
487 |
-
* {% endif %}
|
488 |
-
* </pre>
|
489 |
-
*
|
490 |
-
* @param Twig_Environment $env A Twig_Environment instance
|
491 |
-
* @param DateTime|string $date A date
|
492 |
-
* @param DateTimeZone|string $timezone A timezone
|
493 |
-
*
|
494 |
-
* @return DateTime A DateTime instance
|
495 |
-
*/
|
496 |
-
function twig_date_converter(Twig_Environment $env, $date = null, $timezone = null)
|
497 |
-
{
|
498 |
-
// determine the timezone
|
499 |
-
if (!$timezone) {
|
500 |
-
$defaultTimezone = $env->getExtension('core')->getTimezone();
|
501 |
-
} elseif (!$timezone instanceof DateTimeZone) {
|
502 |
-
$defaultTimezone = new DateTimeZone($timezone);
|
503 |
-
} else {
|
504 |
-
$defaultTimezone = $timezone;
|
505 |
-
}
|
506 |
-
|
507 |
-
// immutable dates
|
508 |
-
if ($date instanceof DateTimeImmutable) {
|
509 |
-
return false !== $timezone ? $date->setTimezone($defaultTimezone) : $date;
|
510 |
-
}
|
511 |
-
|
512 |
-
if ($date instanceof DateTime || $date instanceof DateTimeInterface) {
|
513 |
-
$date = clone $date;
|
514 |
-
if (false !== $timezone) {
|
515 |
-
$date->setTimezone($defaultTimezone);
|
516 |
-
}
|
517 |
-
|
518 |
-
return $date;
|
519 |
-
}
|
520 |
-
|
521 |
-
$asString = (string) $date;
|
522 |
-
if (ctype_digit($asString) || (!empty($asString) && '-' === $asString[0] && ctype_digit(substr($asString, 1)))) {
|
523 |
-
$date = '@'.$date;
|
524 |
-
}
|
525 |
-
|
526 |
-
$date = new DateTime($date, $defaultTimezone);
|
527 |
-
if (false !== $timezone) {
|
528 |
-
$date->setTimezone($defaultTimezone);
|
529 |
-
}
|
530 |
-
|
531 |
-
return $date;
|
532 |
-
}
|
533 |
-
|
534 |
-
/**
|
535 |
-
* Rounds a number.
|
536 |
-
*
|
537 |
-
* @param int|float $value The value to round
|
538 |
-
* @param int|float $precision The rounding precision
|
539 |
-
* @param string $method The method to use for rounding
|
540 |
-
*
|
541 |
-
* @return int|float The rounded number
|
542 |
-
*/
|
543 |
-
function twig_round($value, $precision = 0, $method = 'common')
|
544 |
-
{
|
545 |
-
if ('common' == $method) {
|
546 |
-
return round($value, $precision);
|
547 |
-
}
|
548 |
-
|
549 |
-
if ('ceil' != $method && 'floor' != $method) {
|
550 |
-
throw new Twig_Error_Runtime('The round filter only supports the "common", "ceil", and "floor" methods.');
|
551 |
-
}
|
552 |
-
|
553 |
-
return $method($value * pow(10, $precision)) / pow(10, $precision);
|
554 |
-
}
|
555 |
-
|
556 |
-
/**
|
557 |
-
* Number format filter.
|
558 |
-
*
|
559 |
-
* All of the formatting options can be left null, in that case the defaults will
|
560 |
-
* be used. Supplying any of the parameters will override the defaults set in the
|
561 |
-
* environment object.
|
562 |
-
*
|
563 |
-
* @param Twig_Environment $env A Twig_Environment instance
|
564 |
-
* @param mixed $number A float/int/string of the number to format
|
565 |
-
* @param int $decimal The number of decimal points to display.
|
566 |
-
* @param string $decimalPoint The character(s) to use for the decimal point.
|
567 |
-
* @param string $thousandSep The character(s) to use for the thousands separator.
|
568 |
-
*
|
569 |
-
* @return string The formatted number
|
570 |
-
*/
|
571 |
-
function twig_number_format_filter(Twig_Environment $env, $number, $decimal = null, $decimalPoint = null, $thousandSep = null)
|
572 |
-
{
|
573 |
-
$defaults = $env->getExtension('core')->getNumberFormat();
|
574 |
-
if (null === $decimal) {
|
575 |
-
$decimal = $defaults[0];
|
576 |
-
}
|
577 |
-
|
578 |
-
if (null === $decimalPoint) {
|
579 |
-
$decimalPoint = $defaults[1];
|
580 |
-
}
|
581 |
-
|
582 |
-
if (null === $thousandSep) {
|
583 |
-
$thousandSep = $defaults[2];
|
584 |
-
}
|
585 |
-
|
586 |
-
return number_format((float) $number, $decimal, $decimalPoint, $thousandSep);
|
587 |
-
}
|
588 |
-
|
589 |
-
/**
|
590 |
-
* URL encodes (RFC 3986) a string as a path segment or an array as a query string.
|
591 |
-
*
|
592 |
-
* @param string|array $url A URL or an array of query parameters
|
593 |
-
*
|
594 |
-
* @return string The URL encoded value
|
595 |
-
*/
|
596 |
-
function twig_urlencode_filter($url)
|
597 |
-
{
|
598 |
-
if (is_array($url)) {
|
599 |
-
if (defined('PHP_QUERY_RFC3986')) {
|
600 |
-
return http_build_query($url, '', '&', PHP_QUERY_RFC3986);
|
601 |
-
}
|
602 |
-
|
603 |
-
return http_build_query($url, '', '&');
|
604 |
-
}
|
605 |
-
|
606 |
-
return rawurlencode($url);
|
607 |
-
}
|
608 |
-
|
609 |
-
if (version_compare(PHP_VERSION, '5.3.0', '<')) {
|
610 |
-
/**
|
611 |
-
* JSON encodes a variable.
|
612 |
-
*
|
613 |
-
* @param mixed $value The value to encode.
|
614 |
-
* @param int $options Not used on PHP 5.2.x
|
615 |
-
*
|
616 |
-
* @return mixed The JSON encoded value
|
617 |
-
*/
|
618 |
-
function twig_jsonencode_filter($value, $options = 0)
|
619 |
-
{
|
620 |
-
if ($value instanceof Twig_Markup) {
|
621 |
-
$value = (string) $value;
|
622 |
-
} elseif (is_array($value)) {
|
623 |
-
array_walk_recursive($value, '_twig_markup2string');
|
624 |
-
}
|
625 |
-
|
626 |
-
return json_encode($value);
|
627 |
-
}
|
628 |
-
} else {
|
629 |
-
/**
|
630 |
-
* JSON encodes a variable.
|
631 |
-
*
|
632 |
-
* @param mixed $value The value to encode.
|
633 |
-
* @param int $options Bitmask consisting of JSON_HEX_QUOT, JSON_HEX_TAG, JSON_HEX_AMP, JSON_HEX_APOS, JSON_NUMERIC_CHECK, JSON_PRETTY_PRINT, JSON_UNESCAPED_SLASHES, JSON_FORCE_OBJECT
|
634 |
-
*
|
635 |
-
* @return mixed The JSON encoded value
|
636 |
-
*/
|
637 |
-
function twig_jsonencode_filter($value, $options = 0)
|
638 |
-
{
|
639 |
-
if ($value instanceof Twig_Markup) {
|
640 |
-
$value = (string) $value;
|
641 |
-
} elseif (is_array($value)) {
|
642 |
-
array_walk_recursive($value, '_twig_markup2string');
|
643 |
-
}
|
644 |
-
|
645 |
-
return json_encode($value, $options);
|
646 |
-
}
|
647 |
-
}
|
648 |
-
|
649 |
-
function _twig_markup2string(&$value)
|
650 |
-
{
|
651 |
-
if ($value instanceof Twig_Markup) {
|
652 |
-
$value = (string) $value;
|
653 |
-
}
|
654 |
-
}
|
655 |
-
|
656 |
-
/**
|
657 |
-
* Merges an array with another one.
|
658 |
-
*
|
659 |
-
* <pre>
|
660 |
-
* {% set items = { 'apple': 'fruit', 'orange': 'fruit' } %}
|
661 |
-
*
|
662 |
-
* {% set items = items|merge({ 'peugeot': 'car' }) %}
|
663 |
-
*
|
664 |
-
* {# items now contains { 'apple': 'fruit', 'orange': 'fruit', 'peugeot': 'car' } #}
|
665 |
-
* </pre>
|
666 |
-
*
|
667 |
-
* @param array $arr1 An array
|
668 |
-
* @param array $arr2 An array
|
669 |
-
*
|
670 |
-
* @return array The merged array
|
671 |
-
*/
|
672 |
-
function twig_array_merge($arr1, $arr2)
|
673 |
-
{
|
674 |
-
if (!is_array($arr1) || !is_array($arr2)) {
|
675 |
-
throw new Twig_Error_Runtime('The merge filter only works with arrays or hashes.');
|
676 |
-
}
|
677 |
-
|
678 |
-
return array_merge($arr1, $arr2);
|
679 |
-
}
|
680 |
-
|
681 |
-
/**
|
682 |
-
* Slices a variable.
|
683 |
-
*
|
684 |
-
* @param Twig_Environment $env A Twig_Environment instance
|
685 |
-
* @param mixed $item A variable
|
686 |
-
* @param int $start Start of the slice
|
687 |
-
* @param int $length Size of the slice
|
688 |
-
* @param bool $preserveKeys Whether to preserve key or not (when the input is an array)
|
689 |
-
*
|
690 |
-
* @return mixed The sliced variable
|
691 |
-
*/
|
692 |
-
function twig_slice(Twig_Environment $env, $item, $start, $length = null, $preserveKeys = false)
|
693 |
-
{
|
694 |
-
if ($item instanceof Traversable) {
|
695 |
-
$item = iterator_to_array($item, false);
|
696 |
-
}
|
697 |
-
|
698 |
-
if (is_array($item)) {
|
699 |
-
return array_slice($item, $start, $length, $preserveKeys);
|
700 |
-
}
|
701 |
-
|
702 |
-
$item = (string) $item;
|
703 |
-
|
704 |
-
if (function_exists('mb_get_info') && null !== $charset = $env->getCharset()) {
|
705 |
-
return mb_substr($item, $start, null === $length ? mb_strlen($item, $charset) - $start : $length, $charset);
|
706 |
-
}
|
707 |
-
|
708 |
-
return null === $length ? substr($item, $start) : substr($item, $start, $length);
|
709 |
-
}
|
710 |
-
|
711 |
-
/**
|
712 |
-
* Returns the first element of the item.
|
713 |
-
*
|
714 |
-
* @param Twig_Environment $env A Twig_Environment instance
|
715 |
-
* @param mixed $item A variable
|
716 |
-
*
|
717 |
-
* @return mixed The first element of the item
|
718 |
-
*/
|
719 |
-
function twig_first(Twig_Environment $env, $item)
|
720 |
-
{
|
721 |
-
$elements = twig_slice($env, $item, 0, 1, false);
|
722 |
-
|
723 |
-
return is_string($elements) ? $elements : current($elements);
|
724 |
-
}
|
725 |
-
|
726 |
-
/**
|
727 |
-
* Returns the last element of the item.
|
728 |
-
*
|
729 |
-
* @param Twig_Environment $env A Twig_Environment instance
|
730 |
-
* @param mixed $item A variable
|
731 |
-
*
|
732 |
-
* @return mixed The last element of the item
|
733 |
-
*/
|
734 |
-
function twig_last(Twig_Environment $env, $item)
|
735 |
-
{
|
736 |
-
$elements = twig_slice($env, $item, -1, 1, false);
|
737 |
-
|
738 |
-
return is_string($elements) ? $elements : current($elements);
|
739 |
-
}
|
740 |
-
|
741 |
-
/**
|
742 |
-
* Joins the values to a string.
|
743 |
-
*
|
744 |
-
* The separator between elements is an empty string per default, you can define it with the optional parameter.
|
745 |
-
*
|
746 |
-
* <pre>
|
747 |
-
* {{ [1, 2, 3]|join('|') }}
|
748 |
-
* {# returns 1|2|3 #}
|
749 |
-
*
|
750 |
-
* {{ [1, 2, 3]|join }}
|
751 |
-
* {# returns 123 #}
|
752 |
-
* </pre>
|
753 |
-
*
|
754 |
-
* @param array $value An array
|
755 |
-
* @param string $glue The separator
|
756 |
-
*
|
757 |
-
* @return string The concatenated string
|
758 |
-
*/
|
759 |
-
function twig_join_filter($value, $glue = '')
|
760 |
-
{
|
761 |
-
if ($value instanceof Traversable) {
|
762 |
-
$value = iterator_to_array($value, false);
|
763 |
-
}
|
764 |
-
|
765 |
-
return implode($glue, (array) $value);
|
766 |
-
}
|
767 |
-
|
768 |
-
/**
|
769 |
-
* Splits the string into an array.
|
770 |
-
*
|
771 |
-
* <pre>
|
772 |
-
* {{ "one,two,three"|split(',') }}
|
773 |
-
* {# returns [one, two, three] #}
|
774 |
-
*
|
775 |
-
* {{ "one,two,three,four,five"|split(',', 3) }}
|
776 |
-
* {# returns [one, two, "three,four,five"] #}
|
777 |
-
*
|
778 |
-
* {{ "123"|split('') }}
|
779 |
-
* {# returns [1, 2, 3] #}
|
780 |
-
*
|
781 |
-
* {{ "aabbcc"|split('', 2) }}
|
782 |
-
* {# returns [aa, bb, cc] #}
|
783 |
-
* </pre>
|
784 |
-
*
|
785 |
-
* @param string $value A string
|
786 |
-
* @param string $delimiter The delimiter
|
787 |
-
* @param int $limit The limit
|
788 |
-
*
|
789 |
-
* @return array The split string as an array
|
790 |
-
*/
|
791 |
-
function twig_split_filter($value, $delimiter, $limit = null)
|
792 |
-
{
|
793 |
-
if (empty($delimiter)) {
|
794 |
-
return str_split($value, null === $limit ? 1 : $limit);
|
795 |
-
}
|
796 |
-
|
797 |
-
return null === $limit ? explode($delimiter, $value) : explode($delimiter, $value, $limit);
|
798 |
-
}
|
799 |
-
|
800 |
-
// The '_default' filter is used internally to avoid using the ternary operator
|
801 |
-
// which costs a lot for big contexts (before PHP 5.4). So, on average,
|
802 |
-
// a function call is cheaper.
|
803 |
-
function _twig_default_filter($value, $default = '')
|
804 |
-
{
|
805 |
-
if (twig_test_empty($value)) {
|
806 |
-
return $default;
|
807 |
-
}
|
808 |
-
|
809 |
-
return $value;
|
810 |
-
}
|
811 |
-
|
812 |
-
/**
|
813 |
-
* Returns the keys for the given array.
|
814 |
-
*
|
815 |
-
* It is useful when you want to iterate over the keys of an array:
|
816 |
-
*
|
817 |
-
* <pre>
|
818 |
-
* {% for key in array|keys %}
|
819 |
-
* {# ... #}
|
820 |
-
* {% endfor %}
|
821 |
-
* </pre>
|
822 |
-
*
|
823 |
-
* @param array $array An array
|
824 |
-
*
|
825 |
-
* @return array The keys
|
826 |
-
*/
|
827 |
-
function twig_get_array_keys_filter($array)
|
828 |
-
{
|
829 |
-
if (is_object($array) && $array instanceof Traversable) {
|
830 |
-
return array_keys(iterator_to_array($array));
|
831 |
-
}
|
832 |
-
|
833 |
-
if (!is_array($array)) {
|
834 |
-
return array();
|
835 |
-
}
|
836 |
-
|
837 |
-
return array_keys($array);
|
838 |
-
}
|
839 |
-
|
840 |
-
/**
|
841 |
-
* Reverses a variable.
|
842 |
-
*
|
843 |
-
* @param Twig_Environment $env A Twig_Environment instance
|
844 |
-
* @param array|Traversable|string $item An array, a Traversable instance, or a string
|
845 |
-
* @param bool $preserveKeys Whether to preserve key or not
|
846 |
-
*
|
847 |
-
* @return mixed The reversed input
|
848 |
-
*/
|
849 |
-
function twig_reverse_filter(Twig_Environment $env, $item, $preserveKeys = false)
|
850 |
-
{
|
851 |
-
if (is_object($item) && $item instanceof Traversable) {
|
852 |
-
return array_reverse(iterator_to_array($item), $preserveKeys);
|
853 |
-
}
|
854 |
-
|
855 |
-
if (is_array($item)) {
|
856 |
-
return array_reverse($item, $preserveKeys);
|
857 |
-
}
|
858 |
-
|
859 |
-
if (null !== $charset = $env->getCharset()) {
|
860 |
-
$string = (string) $item;
|
861 |
-
|
862 |
-
if ('UTF-8' != $charset) {
|
863 |
-
$item = twig_convert_encoding($string, 'UTF-8', $charset);
|
864 |
-
}
|
865 |
-
|
866 |
-
preg_match_all('/./us', $item, $matches);
|
867 |
-
|
868 |
-
$string = implode('', array_reverse($matches[0]));
|
869 |
-
|
870 |
-
if ('UTF-8' != $charset) {
|
871 |
-
$string = twig_convert_encoding($string, $charset, 'UTF-8');
|
872 |
-
}
|
873 |
-
|
874 |
-
return $string;
|
875 |
-
}
|
876 |
-
|
877 |
-
return strrev((string) $item);
|
878 |
-
}
|
879 |
-
|
880 |
-
/**
|
881 |
-
* Sorts an array.
|
882 |
-
*
|
883 |
-
* @param array $array An array
|
884 |
-
*/
|
885 |
-
function twig_sort_filter($array)
|
886 |
-
{
|
887 |
-
asort($array);
|
888 |
-
|
889 |
-
return $array;
|
890 |
-
}
|
891 |
-
|
892 |
-
/* used internally */
|
893 |
-
function twig_in_filter($value, $compare)
|
894 |
-
{
|
895 |
-
if (is_array($compare)) {
|
896 |
-
return in_array($value, $compare, is_object($value));
|
897 |
-
} elseif (is_string($compare)) {
|
898 |
-
if (!strlen($value)) {
|
899 |
-
return empty($compare);
|
900 |
-
}
|
901 |
-
|
902 |
-
return false !== strpos($compare, (string) $value);
|
903 |
-
} elseif ($compare instanceof Traversable) {
|
904 |
-
return in_array($value, iterator_to_array($compare, false), is_object($value));
|
905 |
-
}
|
906 |
-
|
907 |
-
return false;
|
908 |
-
}
|
909 |
-
|
910 |
-
/**
|
911 |
-
* Escapes a string.
|
912 |
-
*
|
913 |
-
* @param Twig_Environment $env A Twig_Environment instance
|
914 |
-
* @param string $string The value to be escaped
|
915 |
-
* @param string $strategy The escaping strategy
|
916 |
-
* @param string $charset The charset
|
917 |
-
* @param bool $autoescape Whether the function is called by the auto-escaping feature (true) or by the developer (false)
|
918 |
-
*/
|
919 |
-
function twig_escape_filter(Twig_Environment $env, $string, $strategy = 'html', $charset = null, $autoescape = false)
|
920 |
-
{
|
921 |
-
if ($autoescape && $string instanceof Twig_Markup) {
|
922 |
-
return $string;
|
923 |
-
}
|
924 |
-
|
925 |
-
if (!is_string($string)) {
|
926 |
-
if (is_object($string) && method_exists($string, '__toString')) {
|
927 |
-
$string = (string) $string;
|
928 |
-
} else {
|
929 |
-
return $string;
|
930 |
-
}
|
931 |
-
}
|
932 |
-
|
933 |
-
if (null === $charset) {
|
934 |
-
$charset = $env->getCharset();
|
935 |
-
}
|
936 |
-
|
937 |
-
switch ($strategy) {
|
938 |
-
case 'html':
|
939 |
-
// see http://php.net/htmlspecialchars
|
940 |
-
|
941 |
-
// Using a static variable to avoid initializing the array
|
942 |
-
// each time the function is called. Moving the declaration on the
|
943 |
-
// top of the function slow downs other escaping strategies.
|
944 |
-
static $htmlspecialcharsCharsets;
|
945 |
-
|
946 |
-
if (null === $htmlspecialcharsCharsets) {
|
947 |
-
if ('hiphop' === substr(PHP_VERSION, -6)) {
|
948 |
-
$htmlspecialcharsCharsets = array('utf-8' => true, 'UTF-8' => true);
|
949 |
-
} else {
|
950 |
-
$htmlspecialcharsCharsets = array(
|
951 |
-
'ISO-8859-1' => true, 'ISO8859-1' => true,
|
952 |
-
'ISO-8859-15' => true, 'ISO8859-15' => true,
|
953 |
-
'utf-8' => true, 'UTF-8' => true,
|
954 |
-
'CP866' => true, 'IBM866' => true, '866' => true,
|
955 |
-
'CP1251' => true, 'WINDOWS-1251' => true, 'WIN-1251' => true,
|
956 |
-
'1251' => true,
|
957 |
-
'CP1252' => true, 'WINDOWS-1252' => true, '1252' => true,
|
958 |
-
'KOI8-R' => true, 'KOI8-RU' => true, 'KOI8R' => true,
|
959 |
-
'BIG5' => true, '950' => true,
|
960 |
-
'GB2312' => true, '936' => true,
|
961 |
-
'BIG5-HKSCS' => true,
|
962 |
-
'SHIFT_JIS' => true, 'SJIS' => true, '932' => true,
|
963 |
-
'EUC-JP' => true, 'EUCJP' => true,
|
964 |
-
'ISO8859-5' => true, 'ISO-8859-5' => true, 'MACROMAN' => true,
|
965 |
-
);
|
966 |
-
}
|
967 |
-
}
|
968 |
-
|
969 |
-
if (isset($htmlspecialcharsCharsets[$charset])) {
|
970 |
-
return htmlspecialchars($string, ENT_QUOTES | ENT_SUBSTITUTE, $charset);
|
971 |
-
}
|
972 |
-
|
973 |
-
if (isset($htmlspecialcharsCharsets[strtoupper($charset)])) {
|
974 |
-
// cache the lowercase variant for future iterations
|
975 |
-
$htmlspecialcharsCharsets[$charset] = true;
|
976 |
-
|
977 |
-
return htmlspecialchars($string, ENT_QUOTES | ENT_SUBSTITUTE, $charset);
|
978 |
-
}
|
979 |
-
|
980 |
-
$string = twig_convert_encoding($string, 'UTF-8', $charset);
|
981 |
-
$string = htmlspecialchars($string, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
|
982 |
-
|
983 |
-
return twig_convert_encoding($string, $charset, 'UTF-8');
|
984 |
-
|
985 |
-
case 'js':
|
986 |
-
// escape all non-alphanumeric characters
|
987 |
-
// into their \xHH or \uHHHH representations
|
988 |
-
if ('UTF-8' != $charset) {
|
989 |
-
$string = twig_convert_encoding($string, 'UTF-8', $charset);
|
990 |
-
}
|
991 |
-
|
992 |
-
if (0 == strlen($string) ? false : (1 == preg_match('/^./su', $string) ? false : true)) {
|
993 |
-
throw new Twig_Error_Runtime('The string to escape is not a valid UTF-8 string.');
|
994 |
-
}
|
995 |
-
|
996 |
-
$string = preg_replace_callback('#[^a-zA-Z0-9,\._]#Su', '_twig_escape_js_callback', $string);
|
997 |
-
|
998 |
-
if ('UTF-8' != $charset) {
|
999 |
-
$string = twig_convert_encoding($string, $charset, 'UTF-8');
|
1000 |
-
}
|
1001 |
-
|
1002 |
-
return $string;
|
1003 |
-
|
1004 |
-
case 'css':
|
1005 |
-
if ('UTF-8' != $charset) {
|
1006 |
-
$string = twig_convert_encoding($string, 'UTF-8', $charset);
|
1007 |
-
}
|
1008 |
-
|
1009 |
-
if (0 == strlen($string) ? false : (1 == preg_match('/^./su', $string) ? false : true)) {
|
1010 |
-
throw new Twig_Error_Runtime('The string to escape is not a valid UTF-8 string.');
|
1011 |
-
}
|
1012 |
-
|
1013 |
-
$string = preg_replace_callback('#[^a-zA-Z0-9]#Su', '_twig_escape_css_callback', $string);
|
1014 |
-
|
1015 |
-
if ('UTF-8' != $charset) {
|
1016 |
-
$string = twig_convert_encoding($string, $charset, 'UTF-8');
|
1017 |
-
}
|
1018 |
-
|
1019 |
-
return $string;
|
1020 |
-
|
1021 |
-
case 'html_attr':
|
1022 |
-
if ('UTF-8' != $charset) {
|
1023 |
-
$string = twig_convert_encoding($string, 'UTF-8', $charset);
|
1024 |
-
}
|
1025 |
-
|
1026 |
-
if (0 == strlen($string) ? false : (1 == preg_match('/^./su', $string) ? false : true)) {
|
1027 |
-
throw new Twig_Error_Runtime('The string to escape is not a valid UTF-8 string.');
|
1028 |
-
}
|
1029 |
-
|
1030 |
-
$string = preg_replace_callback('#[^a-zA-Z0-9,\.\-_]#Su', '_twig_escape_html_attr_callback', $string);
|
1031 |
-
|
1032 |
-
if ('UTF-8' != $charset) {
|
1033 |
-
$string = twig_convert_encoding($string, $charset, 'UTF-8');
|
1034 |
-
}
|
1035 |
-
|
1036 |
-
return $string;
|
1037 |
-
|
1038 |
-
case 'url':
|
1039 |
-
// hackish test to avoid version_compare that is much slower, this works unless PHP releases a 5.10.*
|
1040 |
-
// at that point however PHP 5.2.* support can be removed
|
1041 |
-
if (PHP_VERSION < '5.3.0') {
|
1042 |
-
return str_replace('%7E', '~', rawurlencode($string));
|
1043 |
-
}
|
1044 |
-
|
1045 |
-
return rawurlencode($string);
|
1046 |
-
|
1047 |
-
default:
|
1048 |
-
static $escapers;
|
1049 |
-
|
1050 |
-
if (null === $escapers) {
|
1051 |
-
$escapers = $env->getExtension('core')->getEscapers();
|
1052 |
-
}
|
1053 |
-
|
1054 |
-
if (isset($escapers[$strategy])) {
|
1055 |
-
return call_user_func($escapers[$strategy], $env, $string, $charset);
|
1056 |
-
}
|
1057 |
-
|
1058 |
-
$validStrategies = implode(', ', array_merge(array('html', 'js', 'url', 'css', 'html_attr'), array_keys($escapers)));
|
1059 |
-
|
1060 |
-
throw new Twig_Error_Runtime(sprintf('Invalid escaping strategy "%s" (valid ones: %s).', $strategy, $validStrategies));
|
1061 |
-
}
|
1062 |
-
}
|
1063 |
-
|
1064 |
-
/* used internally */
|
1065 |
-
function twig_escape_filter_is_safe(Twig_Node $filterArgs)
|
1066 |
-
{
|
1067 |
-
foreach ($filterArgs as $arg) {
|
1068 |
-
if ($arg instanceof Twig_Node_Expression_Constant) {
|
1069 |
-
return array($arg->getAttribute('value'));
|
1070 |
-
}
|
1071 |
-
|
1072 |
-
return array();
|
1073 |
-
}
|
1074 |
-
|
1075 |
-
return array('html');
|
1076 |
-
}
|
1077 |
-
|
1078 |
-
if (function_exists('mb_convert_encoding')) {
|
1079 |
-
function twig_convert_encoding($string, $to, $from)
|
1080 |
-
{
|
1081 |
-
return mb_convert_encoding($string, $to, $from);
|
1082 |
-
}
|
1083 |
-
} elseif (function_exists('iconv')) {
|
1084 |
-
function twig_convert_encoding($string, $to, $from)
|
1085 |
-
{
|
1086 |
-
return iconv($from, $to, $string);
|
1087 |
-
}
|
1088 |
-
} else {
|
1089 |
-
function twig_convert_encoding($string, $to, $from)
|
1090 |
-
{
|
1091 |
-
throw new Twig_Error_Runtime('No suitable convert encoding function (use UTF-8 as your encoding or install the iconv or mbstring extension).');
|
1092 |
-
}
|
1093 |
-
}
|
1094 |
-
|
1095 |
-
function _twig_escape_js_callback($matches)
|
1096 |
-
{
|
1097 |
-
$char = $matches[0];
|
1098 |
-
|
1099 |
-
// \xHH
|
1100 |
-
if (!isset($char[1])) {
|
1101 |
-
return '\\x'.strtoupper(substr('00'.bin2hex($char), -2));
|
1102 |
-
}
|
1103 |
-
|
1104 |
-
// \uHHHH
|
1105 |
-
$char = twig_convert_encoding($char, 'UTF-16BE', 'UTF-8');
|
1106 |
-
|
1107 |
-
return '\\u'.strtoupper(substr('0000'.bin2hex($char), -4));
|
1108 |
-
}
|
1109 |
-
|
1110 |
-
function _twig_escape_css_callback($matches)
|
1111 |
-
{
|
1112 |
-
$char = $matches[0];
|
1113 |
-
|
1114 |
-
// \xHH
|
1115 |
-
if (!isset($char[1])) {
|
1116 |
-
$hex = ltrim(strtoupper(bin2hex($char)), '0');
|
1117 |
-
if (0 === strlen($hex)) {
|
1118 |
-
$hex = '0';
|
1119 |
-
}
|
1120 |
-
|
1121 |
-
return '\\'.$hex.' ';
|
1122 |
-
}
|
1123 |
-
|
1124 |
-
// \uHHHH
|
1125 |
-
$char = twig_convert_encoding($char, 'UTF-16BE', 'UTF-8');
|
1126 |
-
|
1127 |
-
return '\\'.ltrim(strtoupper(bin2hex($char)), '0').' ';
|
1128 |
-
}
|
1129 |
-
|
1130 |
-
/**
|
1131 |
-
* This function is adapted from code coming from Zend Framework.
|
1132 |
-
*
|
1133 |
-
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
|
1134 |
-
* @license http://framework.zend.com/license/new-bsd New BSD License
|
1135 |
-
*/
|
1136 |
-
function _twig_escape_html_attr_callback($matches)
|
1137 |
-
{
|
1138 |
-
/*
|
1139 |
-
* While HTML supports far more named entities, the lowest common denominator
|
1140 |
-
* has become HTML5's XML Serialisation which is restricted to the those named
|
1141 |
-
* entities that XML supports. Using HTML entities would result in this error:
|
1142 |
-
* XML Parsing Error: undefined entity
|
1143 |
-
*/
|
1144 |
-
static $entityMap = array(
|
1145 |
-
34 => 'quot', /* quotation mark */
|
1146 |
-
38 => 'amp', /* ampersand */
|
1147 |
-
60 => 'lt', /* less-than sign */
|
1148 |
-
62 => 'gt', /* greater-than sign */
|
1149 |
-
);
|
1150 |
-
|
1151 |
-
$chr = $matches[0];
|
1152 |
-
$ord = ord($chr);
|
1153 |
-
|
1154 |
-
/**
|
1155 |
-
* The following replaces characters undefined in HTML with the
|
1156 |
-
* hex entity for the Unicode replacement character.
|
1157 |
-
*/
|
1158 |
-
if (($ord <= 0x1f && $chr != "\t" && $chr != "\n" && $chr != "\r") || ($ord >= 0x7f && $ord <= 0x9f)) {
|
1159 |
-
return '�';
|
1160 |
-
}
|
1161 |
-
|
1162 |
-
/**
|
1163 |
-
* Check if the current character to escape has a name entity we should
|
1164 |
-
* replace it with while grabbing the hex value of the character.
|
1165 |
-
*/
|
1166 |
-
if (strlen($chr) == 1) {
|
1167 |
-
$hex = strtoupper(substr('00'.bin2hex($chr), -2));
|
1168 |
-
} else {
|
1169 |
-
$chr = twig_convert_encoding($chr, 'UTF-16BE', 'UTF-8');
|
1170 |
-
$hex = strtoupper(substr('0000'.bin2hex($chr), -4));
|
1171 |
-
}
|
1172 |
-
|
1173 |
-
$int = hexdec($hex);
|
1174 |
-
if (array_key_exists($int, $entityMap)) {
|
1175 |
-
return sprintf('&%s;', $entityMap[$int]);
|
1176 |
-
}
|
1177 |
-
|
1178 |
-
/**
|
1179 |
-
* Per OWASP recommendations, we'll use hex entities for any other
|
1180 |
-
* characters where a named entity does not exist.
|
1181 |
-
*/
|
1182 |
-
|
1183 |
-
return sprintf('&#x%s;', $hex);
|
1184 |
-
}
|
1185 |
-
|
1186 |
-
// add multibyte extensions if possible
|
1187 |
-
if (function_exists('mb_get_info')) {
|
1188 |
-
/**
|
1189 |
-
* Returns the length of a variable.
|
1190 |
-
*
|
1191 |
-
* @param Twig_Environment $env A Twig_Environment instance
|
1192 |
-
* @param mixed $thing A variable
|
1193 |
-
*
|
1194 |
-
* @return int The length of the value
|
1195 |
-
*/
|
1196 |
-
function twig_length_filter(Twig_Environment $env, $thing)
|
1197 |
-
{
|
1198 |
-
return is_scalar($thing) ? mb_strlen($thing, $env->getCharset()) : count($thing);
|
1199 |
-
}
|
1200 |
-
|
1201 |
-
/**
|
1202 |
-
* Converts a string to uppercase.
|
1203 |
-
*
|
1204 |
-
* @param Twig_Environment $env A Twig_Environment instance
|
1205 |
-
* @param string $string A string
|
1206 |
-
*
|
1207 |
-
* @return string The uppercased string
|
1208 |
-
*/
|
1209 |
-
function twig_upper_filter(Twig_Environment $env, $string)
|
1210 |
-
{
|
1211 |
-
if (null !== ($charset = $env->getCharset())) {
|
1212 |
-
return mb_strtoupper($string, $charset);
|
1213 |
-
}
|
1214 |
-
|
1215 |
-
return strtoupper($string);
|
1216 |
-
}
|
1217 |
-
|
1218 |
-
/**
|
1219 |
-
* Converts a string to lowercase.
|
1220 |
-
*
|
1221 |
-
* @param Twig_Environment $env A Twig_Environment instance
|
1222 |
-
* @param string $string A string
|
1223 |
-
*
|
1224 |
-
* @return string The lowercased string
|
1225 |
-
*/
|
1226 |
-
function twig_lower_filter(Twig_Environment $env, $string)
|
1227 |
-
{
|
1228 |
-
if (null !== ($charset = $env->getCharset())) {
|
1229 |
-
return mb_strtolower($string, $charset);
|
1230 |
-
}
|
1231 |
-
|
1232 |
-
return strtolower($string);
|
1233 |
-
}
|
1234 |
-
|
1235 |
-
/**
|
1236 |
-
* Returns a titlecased string.
|
1237 |
-
*
|
1238 |
-
* @param Twig_Environment $env A Twig_Environment instance
|
1239 |
-
* @param string $string A string
|
1240 |
-
*
|
1241 |
-
* @return string The titlecased string
|
1242 |
-
*/
|
1243 |
-
function twig_title_string_filter(Twig_Environment $env, $string)
|
1244 |
-
{
|
1245 |
-
if (null !== ($charset = $env->getCharset())) {
|
1246 |
-
return mb_convert_case($string, MB_CASE_TITLE, $charset);
|
1247 |
-
}
|
1248 |
-
|
1249 |
-
return ucwords(strtolower($string));
|
1250 |
-
}
|
1251 |
-
|
1252 |
-
/**
|
1253 |
-
* Returns a capitalized string.
|
1254 |
-
*
|
1255 |
-
* @param Twig_Environment $env A Twig_Environment instance
|
1256 |
-
* @param string $string A string
|
1257 |
-
*
|
1258 |
-
* @return string The capitalized string
|
1259 |
-
*/
|
1260 |
-
function twig_capitalize_string_filter(Twig_Environment $env, $string)
|
1261 |
-
{
|
1262 |
-
if (null !== ($charset = $env->getCharset())) {
|
1263 |
-
return mb_strtoupper(mb_substr($string, 0, 1, $charset), $charset).
|
1264 |
-
mb_strtolower(mb_substr($string, 1, mb_strlen($string, $charset), $charset), $charset);
|
1265 |
-
}
|
1266 |
-
|
1267 |
-
return ucfirst(strtolower($string));
|
1268 |
-
}
|
1269 |
-
}
|
1270 |
-
// and byte fallback
|
1271 |
-
else {
|
1272 |
-
/**
|
1273 |
-
* Returns the length of a variable.
|
1274 |
-
*
|
1275 |
-
* @param Twig_Environment $env A Twig_Environment instance
|
1276 |
-
* @param mixed $thing A variable
|
1277 |
-
*
|
1278 |
-
* @return int The length of the value
|
1279 |
-
*/
|
1280 |
-
function twig_length_filter(Twig_Environment $env, $thing)
|
1281 |
-
{
|
1282 |
-
return is_scalar($thing) ? strlen($thing) : count($thing);
|
1283 |
-
}
|
1284 |
-
|
1285 |
-
/**
|
1286 |
-
* Returns a titlecased string.
|
1287 |
-
*
|
1288 |
-
* @param Twig_Environment $env A Twig_Environment instance
|
1289 |
-
* @param string $string A string
|
1290 |
-
*
|
1291 |
-
* @return string The titlecased string
|
1292 |
-
*/
|
1293 |
-
function twig_title_string_filter(Twig_Environment $env, $string)
|
1294 |
-
{
|
1295 |
-
return ucwords(strtolower($string));
|
1296 |
-
}
|
1297 |
-
|
1298 |
-
/**
|
1299 |
-
* Returns a capitalized string.
|
1300 |
-
*
|
1301 |
-
* @param Twig_Environment $env A Twig_Environment instance
|
1302 |
-
* @param string $string A string
|
1303 |
-
*
|
1304 |
-
* @return string The capitalized string
|
1305 |
-
*/
|
1306 |
-
function twig_capitalize_string_filter(Twig_Environment $env, $string)
|
1307 |
-
{
|
1308 |
-
return ucfirst(strtolower($string));
|
1309 |
-
}
|
1310 |
-
}
|
1311 |
-
|
1312 |
-
/* used internally */
|
1313 |
-
function twig_ensure_traversable($seq)
|
1314 |
-
{
|
1315 |
-
if ($seq instanceof Traversable || is_array($seq)) {
|
1316 |
-
return $seq;
|
1317 |
-
}
|
1318 |
-
|
1319 |
-
return array();
|
1320 |
-
}
|
1321 |
-
|
1322 |
-
/**
|
1323 |
-
* Checks if a variable is empty.
|
1324 |
-
*
|
1325 |
-
* <pre>
|
1326 |
-
* {# evaluates to true if the foo variable is null, false, or the empty string #}
|
1327 |
-
* {% if foo is empty %}
|
1328 |
-
* {# ... #}
|
1329 |
-
* {% endif %}
|
1330 |
-
* </pre>
|
1331 |
-
*
|
1332 |
-
* @param mixed $value A variable
|
1333 |
-
*
|
1334 |
-
* @return bool true if the value is empty, false otherwise
|
1335 |
-
*/
|
1336 |
-
function twig_test_empty($value)
|
1337 |
-
{
|
1338 |
-
if ($value instanceof Countable) {
|
1339 |
-
return 0 == count($value);
|
1340 |
-
}
|
1341 |
-
|
1342 |
-
return '' === $value || false === $value || null === $value || array() === $value;
|
1343 |
-
}
|
1344 |
-
|
1345 |
-
/**
|
1346 |
-
* Checks if a variable is traversable.
|
1347 |
-
*
|
1348 |
-
* <pre>
|
1349 |
-
* {# evaluates to true if the foo variable is an array or a traversable object #}
|
1350 |
-
* {% if foo is traversable %}
|
1351 |
-
* {# ... #}
|
1352 |
-
* {% endif %}
|
1353 |
-
* </pre>
|
1354 |
-
*
|
1355 |
-
* @param mixed $value A variable
|
1356 |
-
*
|
1357 |
-
* @return bool true if the value is traversable
|
1358 |
-
*/
|
1359 |
-
function twig_test_iterable($value)
|
1360 |
-
{
|
1361 |
-
return $value instanceof Traversable || is_array($value);
|
1362 |
-
}
|
1363 |
-
|
1364 |
-
/**
|
1365 |
-
* Renders a template.
|
1366 |
-
*
|
1367 |
-
* @param string|array $template The template to render or an array of templates to try consecutively
|
1368 |
-
* @param array $variables The variables to pass to the template
|
1369 |
-
* @param bool $with_context Whether to pass the current context variables or not
|
1370 |
-
* @param bool $ignore_missing Whether to ignore missing templates or not
|
1371 |
-
* @param bool $sandboxed Whether to sandbox the template or not
|
1372 |
-
*
|
1373 |
-
* @return string The rendered template
|
1374 |
-
*/
|
1375 |
-
function twig_include(Twig_Environment $env, $context, $template, $variables = array(), $withContext = true, $ignoreMissing = false, $sandboxed = false)
|
1376 |
-
{
|
1377 |
-
$alreadySandboxed = false;
|
1378 |
-
$sandbox = null;
|
1379 |
-
if ($withContext) {
|
1380 |
-
$variables = array_merge($context, $variables);
|
1381 |
-
}
|
1382 |
-
|
1383 |
-
if ($isSandboxed = $sandboxed && $env->hasExtension('sandbox')) {
|
1384 |
-
$sandbox = $env->getExtension('sandbox');
|
1385 |
-
if (!$alreadySandboxed = $sandbox->isSandboxed()) {
|
1386 |
-
$sandbox->enableSandbox();
|
1387 |
-
}
|
1388 |
-
}
|
1389 |
-
|
1390 |
-
try {
|
1391 |
-
return $env->resolveTemplate($template)->render($variables);
|
1392 |
-
} catch (Twig_Error_Loader $e) {
|
1393 |
-
if (!$ignoreMissing) {
|
1394 |
-
throw $e;
|
1395 |
-
}
|
1396 |
-
}
|
1397 |
-
|
1398 |
-
if ($isSandboxed && !$alreadySandboxed) {
|
1399 |
-
$sandbox->disableSandbox();
|
1400 |
-
}
|
1401 |
-
}
|
1402 |
-
|
1403 |
-
/**
|
1404 |
-
* Returns a template content without rendering it.
|
1405 |
-
*
|
1406 |
-
* @param string $name The template name
|
1407 |
-
*
|
1408 |
-
* @return string The template source
|
1409 |
-
*/
|
1410 |
-
function twig_source(Twig_Environment $env, $name)
|
1411 |
-
{
|
1412 |
-
return $env->getLoader()->getSource($name);
|
1413 |
-
}
|
1414 |
-
|
1415 |
-
/**
|
1416 |
-
* Provides the ability to get constants from instances as well as class/global constants.
|
1417 |
-
*
|
1418 |
-
* @param string $constant The name of the constant
|
1419 |
-
* @param null|object $object The object to get the constant from
|
1420 |
-
*
|
1421 |
-
* @return string
|
1422 |
-
*/
|
1423 |
-
function twig_constant($constant, $object = null)
|
1424 |
-
{
|
1425 |
-
if (null !== $object) {
|
1426 |
-
$constant = get_class($object).'::'.$constant;
|
1427 |
-
}
|
1428 |
-
|
1429 |
-
return constant($constant);
|
1430 |
-
}
|
1431 |
-
|
1432 |
-
/**
|
1433 |
-
* Batches item.
|
1434 |
-
*
|
1435 |
-
* @param array $items An array of items
|
1436 |
-
* @param int $size The size of the batch
|
1437 |
-
* @param mixed $fill A value used to fill missing items
|
1438 |
-
*
|
1439 |
-
* @return array
|
1440 |
-
*/
|
1441 |
-
function twig_array_batch($items, $size, $fill = null)
|
1442 |
-
{
|
1443 |
-
if ($items instanceof Traversable) {
|
1444 |
-
$items = iterator_to_array($items, false);
|
1445 |
-
}
|
1446 |
-
|
1447 |
-
$size = ceil($size);
|
1448 |
-
|
1449 |
-
$result = array_chunk($items, $size, true);
|
1450 |
-
|
1451 |
-
if (null !== $fill) {
|
1452 |
-
$last = count($result) - 1;
|
1453 |
-
if ($fillCount = $size - count($result[$last])) {
|
1454 |
-
$result[$last] = array_merge(
|
1455 |
-
$result[$last],
|
1456 |
-
array_fill(0, $fillCount, $fill)
|
1457 |
-
);
|
1458 |
-
}
|
1459 |
-
}
|
1460 |
-
|
1461 |
-
return $result;
|
1462 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
if (!defined('ENT_SUBSTITUTE')) {
|
4 |
+
// use 0 as hhvm does not support several flags yet
|
5 |
+
define('ENT_SUBSTITUTE', 0);
|
6 |
+
}
|
7 |
+
|
8 |
+
/*
|
9 |
+
* This file is part of Twig.
|
10 |
+
*
|
11 |
+
* (c) 2009 Fabien Potencier
|
12 |
+
*
|
13 |
+
* For the full copyright and license information, please view the LICENSE
|
14 |
+
* file that was distributed with this source code.
|
15 |
+
*/
|
16 |
+
class Twig_Extension_Core extends Twig_Extension
|
17 |
+
{
|
18 |
+
protected $dateFormats = array('F j, Y H:i', '%d days');
|
19 |
+
protected $numberFormat = array(0, '.', ',');
|
20 |
+
protected $timezone = null;
|
21 |
+
protected $escapers = array();
|
22 |
+
|
23 |
+
/**
|
24 |
+
* Defines a new escaper to be used via the escape filter.
|
25 |
+
*
|
26 |
+
* @param string $strategy The strategy name that should be used as a strategy in the escape call
|
27 |
+
* @param callable $callable A valid PHP callable
|
28 |
+
*/
|
29 |
+
public function setEscaper($strategy, $callable)
|
30 |
+
{
|
31 |
+
$this->escapers[$strategy] = $callable;
|
32 |
+
}
|
33 |
+
|
34 |
+
/**
|
35 |
+
* Gets all defined escapers.
|
36 |
+
*
|
37 |
+
* @return array An array of escapers
|
38 |
+
*/
|
39 |
+
public function getEscapers()
|
40 |
+
{
|
41 |
+
return $this->escapers;
|
42 |
+
}
|
43 |
+
|
44 |
+
/**
|
45 |
+
* Sets the default format to be used by the date filter.
|
46 |
+
*
|
47 |
+
* @param string $format The default date format string
|
48 |
+
* @param string $dateIntervalFormat The default date interval format string
|
49 |
+
*/
|
50 |
+
public function setDateFormat($format = null, $dateIntervalFormat = null)
|
51 |
+
{
|
52 |
+
if (null !== $format) {
|
53 |
+
$this->dateFormats[0] = $format;
|
54 |
+
}
|
55 |
+
|
56 |
+
if (null !== $dateIntervalFormat) {
|
57 |
+
$this->dateFormats[1] = $dateIntervalFormat;
|
58 |
+
}
|
59 |
+
}
|
60 |
+
|
61 |
+
/**
|
62 |
+
* Gets the default format to be used by the date filter.
|
63 |
+
*
|
64 |
+
* @return array The default date format string and the default date interval format string
|
65 |
+
*/
|
66 |
+
public function getDateFormat()
|
67 |
+
{
|
68 |
+
return $this->dateFormats;
|
69 |
+
}
|
70 |
+
|
71 |
+
/**
|
72 |
+
* Sets the default timezone to be used by the date filter.
|
73 |
+
*
|
74 |
+
* @param DateTimeZone|string $timezone The default timezone string or a DateTimeZone object
|
75 |
+
*/
|
76 |
+
public function setTimezone($timezone)
|
77 |
+
{
|
78 |
+
$this->timezone = $timezone instanceof DateTimeZone ? $timezone : new DateTimeZone($timezone);
|
79 |
+
}
|
80 |
+
|
81 |
+
/**
|
82 |
+
* Gets the default timezone to be used by the date filter.
|
83 |
+
*
|
84 |
+
* @return DateTimeZone The default timezone currently in use
|
85 |
+
*/
|
86 |
+
public function getTimezone()
|
87 |
+
{
|
88 |
+
if (null === $this->timezone) {
|
89 |
+
$this->timezone = new DateTimeZone(date_default_timezone_get());
|
90 |
+
}
|
91 |
+
|
92 |
+
return $this->timezone;
|
93 |
+
}
|
94 |
+
|
95 |
+
/**
|
96 |
+
* Sets the default format to be used by the number_format filter.
|
97 |
+
*
|
98 |
+
* @param int $decimal The number of decimal places to use.
|
99 |
+
* @param string $decimalPoint The character(s) to use for the decimal point.
|
100 |
+
* @param string $thousandSep The character(s) to use for the thousands separator.
|
101 |
+
*/
|
102 |
+
public function setNumberFormat($decimal, $decimalPoint, $thousandSep)
|
103 |
+
{
|
104 |
+
$this->numberFormat = array($decimal, $decimalPoint, $thousandSep);
|
105 |
+
}
|
106 |
+
|
107 |
+
/**
|
108 |
+
* Get the default format used by the number_format filter.
|
109 |
+
*
|
110 |
+
* @return array The arguments for number_format()
|
111 |
+
*/
|
112 |
+
public function getNumberFormat()
|
113 |
+
{
|
114 |
+
return $this->numberFormat;
|
115 |
+
}
|
116 |
+
|
117 |
+
/**
|
118 |
+
* Returns the token parser instance to add to the existing list.
|
119 |
+
*
|
120 |
+
* @return Twig_TokenParser[] An array of Twig_TokenParser instances
|
121 |
+
*/
|
122 |
+
public function getTokenParsers()
|
123 |
+
{
|
124 |
+
return array(
|
125 |
+
new Twig_TokenParser_For(),
|
126 |
+
new Twig_TokenParser_If(),
|
127 |
+
new Twig_TokenParser_Extends(),
|
128 |
+
new Twig_TokenParser_Include(),
|
129 |
+
new Twig_TokenParser_Block(),
|
130 |
+
new Twig_TokenParser_Use(),
|
131 |
+
new Twig_TokenParser_Filter(),
|
132 |
+
new Twig_TokenParser_Macro(),
|
133 |
+
new Twig_TokenParser_Import(),
|
134 |
+
new Twig_TokenParser_From(),
|
135 |
+
new Twig_TokenParser_Set(),
|
136 |
+
new Twig_TokenParser_Spaceless(),
|
137 |
+
new Twig_TokenParser_Flush(),
|
138 |
+
new Twig_TokenParser_Do(),
|
139 |
+
new Twig_TokenParser_Embed(),
|
140 |
+
);
|
141 |
+
}
|
142 |
+
|
143 |
+
/**
|
144 |
+
* Returns a list of filters to add to the existing list.
|
145 |
+
*
|
146 |
+
* @return array An array of filters
|
147 |
+
*/
|
148 |
+
public function getFilters()
|
149 |
+
{
|
150 |
+
$filters = array(
|
151 |
+
// formatting filters
|
152 |
+
new Twig_SimpleFilter('date', 'twig_date_format_filter', array('needs_environment' => true)),
|
153 |
+
new Twig_SimpleFilter('date_modify', 'twig_date_modify_filter', array('needs_environment' => true)),
|
154 |
+
new Twig_SimpleFilter('format', 'sprintf'),
|
155 |
+
new Twig_SimpleFilter('replace', 'strtr'),
|
156 |
+
new Twig_SimpleFilter('number_format', 'twig_number_format_filter', array('needs_environment' => true)),
|
157 |
+
new Twig_SimpleFilter('abs', 'abs'),
|
158 |
+
new Twig_SimpleFilter('round', 'twig_round'),
|
159 |
+
|
160 |
+
// encoding
|
161 |
+
new Twig_SimpleFilter('url_encode', 'twig_urlencode_filter'),
|
162 |
+
new Twig_SimpleFilter('json_encode', 'twig_jsonencode_filter'),
|
163 |
+
new Twig_SimpleFilter('convert_encoding', 'twig_convert_encoding'),
|
164 |
+
|
165 |
+
// string filters
|
166 |
+
new Twig_SimpleFilter('title', 'twig_title_string_filter', array('needs_environment' => true)),
|
167 |
+
new Twig_SimpleFilter('capitalize', 'twig_capitalize_string_filter', array('needs_environment' => true)),
|
168 |
+
new Twig_SimpleFilter('upper', 'strtoupper'),
|
169 |
+
new Twig_SimpleFilter('lower', 'strtolower'),
|
170 |
+
new Twig_SimpleFilter('striptags', 'strip_tags'),
|
171 |
+
new Twig_SimpleFilter('trim', 'trim'),
|
172 |
+
new Twig_SimpleFilter('nl2br', 'nl2br', array('pre_escape' => 'html', 'is_safe' => array('html'))),
|
173 |
+
|
174 |
+
// array helpers
|
175 |
+
new Twig_SimpleFilter('join', 'twig_join_filter'),
|
176 |
+
new Twig_SimpleFilter('split', 'twig_split_filter'),
|
177 |
+
new Twig_SimpleFilter('sort', 'twig_sort_filter'),
|
178 |
+
new Twig_SimpleFilter('merge', 'twig_array_merge'),
|
179 |
+
new Twig_SimpleFilter('batch', 'twig_array_batch'),
|
180 |
+
|
181 |
+
// string/array filters
|
182 |
+
new Twig_SimpleFilter('reverse', 'twig_reverse_filter', array('needs_environment' => true)),
|
183 |
+
new Twig_SimpleFilter('length', 'twig_length_filter', array('needs_environment' => true)),
|
184 |
+
new Twig_SimpleFilter('slice', 'twig_slice', array('needs_environment' => true)),
|
185 |
+
new Twig_SimpleFilter('first', 'twig_first', array('needs_environment' => true)),
|
186 |
+
new Twig_SimpleFilter('last', 'twig_last', array('needs_environment' => true)),
|
187 |
+
|
188 |
+
// iteration and runtime
|
189 |
+
new Twig_SimpleFilter('default', '_twig_default_filter', array('node_class' => 'Twig_Node_Expression_Filter_Default')),
|
190 |
+
new Twig_SimpleFilter('keys', 'twig_get_array_keys_filter'),
|
191 |
+
|
192 |
+
// escaping
|
193 |
+
new Twig_SimpleFilter('escape', 'twig_escape_filter', array('needs_environment' => true, 'is_safe_callback' => 'twig_escape_filter_is_safe')),
|
194 |
+
new Twig_SimpleFilter('e', 'twig_escape_filter', array('needs_environment' => true, 'is_safe_callback' => 'twig_escape_filter_is_safe')),
|
195 |
+
);
|
196 |
+
|
197 |
+
if (function_exists('mb_get_info')) {
|
198 |
+
$filters[] = new Twig_SimpleFilter('upper', 'twig_upper_filter', array('needs_environment' => true));
|
199 |
+
$filters[] = new Twig_SimpleFilter('lower', 'twig_lower_filter', array('needs_environment' => true));
|
200 |
+
}
|
201 |
+
|
202 |
+
return $filters;
|
203 |
+
}
|
204 |
+
|
205 |
+
/**
|
206 |
+
* Returns a list of global functions to add to the existing list.
|
207 |
+
*
|
208 |
+
* @return array An array of global functions
|
209 |
+
*/
|
210 |
+
public function getFunctions()
|
211 |
+
{
|
212 |
+
return array(
|
213 |
+
new Twig_SimpleFunction('max', 'max'),
|
214 |
+
new Twig_SimpleFunction('min', 'min'),
|
215 |
+
new Twig_SimpleFunction('range', 'range'),
|
216 |
+
new Twig_SimpleFunction('constant', 'twig_constant'),
|
217 |
+
new Twig_SimpleFunction('cycle', 'twig_cycle'),
|
218 |
+
new Twig_SimpleFunction('random', 'twig_random', array('needs_environment' => true)),
|
219 |
+
new Twig_SimpleFunction('date', 'twig_date_converter', array('needs_environment' => true)),
|
220 |
+
new Twig_SimpleFunction('include', 'twig_include', array('needs_environment' => true, 'needs_context' => true, 'is_safe' => array('all'))),
|
221 |
+
new Twig_SimpleFunction('source', 'twig_source', array('needs_environment' => true, 'is_safe' => array('all'))),
|
222 |
+
);
|
223 |
+
}
|
224 |
+
|
225 |
+
/**
|
226 |
+
* Returns a list of tests to add to the existing list.
|
227 |
+
*
|
228 |
+
* @return array An array of tests
|
229 |
+
*/
|
230 |
+
public function getTests()
|
231 |
+
{
|
232 |
+
return array(
|
233 |
+
new Twig_SimpleTest('even', null, array('node_class' => 'Twig_Node_Expression_Test_Even')),
|
234 |
+
new Twig_SimpleTest('odd', null, array('node_class' => 'Twig_Node_Expression_Test_Odd')),
|
235 |
+
new Twig_SimpleTest('defined', null, array('node_class' => 'Twig_Node_Expression_Test_Defined')),
|
236 |
+
new Twig_SimpleTest('sameas', null, array('node_class' => 'Twig_Node_Expression_Test_Sameas')),
|
237 |
+
new Twig_SimpleTest('same as', null, array('node_class' => 'Twig_Node_Expression_Test_Sameas')),
|
238 |
+
new Twig_SimpleTest('none', null, array('node_class' => 'Twig_Node_Expression_Test_Null')),
|
239 |
+
new Twig_SimpleTest('null', null, array('node_class' => 'Twig_Node_Expression_Test_Null')),
|
240 |
+
new Twig_SimpleTest('divisibleby', null, array('node_class' => 'Twig_Node_Expression_Test_Divisibleby')),
|
241 |
+
new Twig_SimpleTest('divisible by', null, array('node_class' => 'Twig_Node_Expression_Test_Divisibleby')),
|
242 |
+
new Twig_SimpleTest('constant', null, array('node_class' => 'Twig_Node_Expression_Test_Constant')),
|
243 |
+
new Twig_SimpleTest('empty', 'twig_test_empty'),
|
244 |
+
new Twig_SimpleTest('iterable', 'twig_test_iterable'),
|
245 |
+
);
|
246 |
+
}
|
247 |
+
|
248 |
+
/**
|
249 |
+
* Returns a list of operators to add to the existing list.
|
250 |
+
*
|
251 |
+
* @return array An array of operators
|
252 |
+
*/
|
253 |
+
public function getOperators()
|
254 |
+
{
|
255 |
+
return array(
|
256 |
+
array(
|
257 |
+
'not' => array('precedence' => 50, 'class' => 'Twig_Node_Expression_Unary_Not'),
|
258 |
+
'-' => array('precedence' => 500, 'class' => 'Twig_Node_Expression_Unary_Neg'),
|
259 |
+
'+' => array('precedence' => 500, 'class' => 'Twig_Node_Expression_Unary_Pos'),
|
260 |
+
),
|
261 |
+
array(
|
262 |
+
'or' => array('precedence' => 10, 'class' => 'Twig_Node_Expression_Binary_Or', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
|
263 |
+
'and' => array('precedence' => 15, 'class' => 'Twig_Node_Expression_Binary_And', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
|
264 |
+
'b-or' => array('precedence' => 16, 'class' => 'Twig_Node_Expression_Binary_BitwiseOr', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
|
265 |
+
'b-xor' => array('precedence' => 17, 'class' => 'Twig_Node_Expression_Binary_BitwiseXor', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
|
266 |
+
'b-and' => array('precedence' => 18, 'class' => 'Twig_Node_Expression_Binary_BitwiseAnd', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
|
267 |
+
'==' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_Equal', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
|
268 |
+
'!=' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_NotEqual', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
|
269 |
+
'<' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_Less', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
|
270 |
+
'>' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_Greater', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
|
271 |
+
'>=' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_GreaterEqual', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
|
272 |
+
'<=' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_LessEqual', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
|
273 |
+
'not in' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_NotIn', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
|
274 |
+
'in' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_In', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
|
275 |
+
'matches' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_Matches', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
|
276 |
+
'starts with' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_StartsWith', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
|
277 |
+
'ends with' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_EndsWith', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
|
278 |
+
'..' => array('precedence' => 25, 'class' => 'Twig_Node_Expression_Binary_Range', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
|
279 |
+
'+' => array('precedence' => 30, 'class' => 'Twig_Node_Expression_Binary_Add', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
|
280 |
+
'-' => array('precedence' => 30, 'class' => 'Twig_Node_Expression_Binary_Sub', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
|
281 |
+
'~' => array('precedence' => 40, 'class' => 'Twig_Node_Expression_Binary_Concat', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
|
282 |
+
'*' => array('precedence' => 60, 'class' => 'Twig_Node_Expression_Binary_Mul', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
|
283 |
+
'/' => array('precedence' => 60, 'class' => 'Twig_Node_Expression_Binary_Div', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
|
284 |
+
'//' => array('precedence' => 60, 'class' => 'Twig_Node_Expression_Binary_FloorDiv', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
|
285 |
+
'%' => array('precedence' => 60, 'class' => 'Twig_Node_Expression_Binary_Mod', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
|
286 |
+
'is' => array('precedence' => 100, 'callable' => array($this, 'parseTestExpression'), 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
|
287 |
+
'is not' => array('precedence' => 100, 'callable' => array($this, 'parseNotTestExpression'), 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
|
288 |
+
'**' => array('precedence' => 200, 'class' => 'Twig_Node_Expression_Binary_Power', 'associativity' => Twig_ExpressionParser::OPERATOR_RIGHT),
|
289 |
+
),
|
290 |
+
);
|
291 |
+
}
|
292 |
+
|
293 |
+
public function parseNotTestExpression(Twig_Parser $parser, Twig_NodeInterface $node)
|
294 |
+
{
|
295 |
+
return new Twig_Node_Expression_Unary_Not($this->parseTestExpression($parser, $node), $parser->getCurrentToken()->getLine());
|
296 |
+
}
|
297 |
+
|
298 |
+
public function parseTestExpression(Twig_Parser $parser, Twig_NodeInterface $node)
|
299 |
+
{
|
300 |
+
$stream = $parser->getStream();
|
301 |
+
$name = $stream->expect(Twig_Token::NAME_TYPE)->getValue();
|
302 |
+
$class = $this->getTestNodeClass($parser, $name, $node->getLine());
|
303 |
+
$arguments = null;
|
304 |
+
if ($stream->test(Twig_Token::PUNCTUATION_TYPE, '(')) {
|
305 |
+
$arguments = $parser->getExpressionParser()->parseArguments(true);
|
306 |
+
}
|
307 |
+
|
308 |
+
return new $class($node, $name, $arguments, $parser->getCurrentToken()->getLine());
|
309 |
+
}
|
310 |
+
|
311 |
+
protected function getTestNodeClass(Twig_Parser $parser, $name, $line)
|
312 |
+
{
|
313 |
+
$env = $parser->getEnvironment();
|
314 |
+
$testMap = $env->getTests();
|
315 |
+
$testName = null;
|
316 |
+
if (isset($testMap[$name])) {
|
317 |
+
$testName = $name;
|
318 |
+
} elseif ($parser->getStream()->test(Twig_Token::NAME_TYPE)) {
|
319 |
+
// try 2-words tests
|
320 |
+
$name = $name.' '.$parser->getCurrentToken()->getValue();
|
321 |
+
|
322 |
+
if (isset($testMap[$name])) {
|
323 |
+
$parser->getStream()->next();
|
324 |
+
|
325 |
+
$testName = $name;
|
326 |
+
}
|
327 |
+
}
|
328 |
+
|
329 |
+
if (null === $testName) {
|
330 |
+
$message = sprintf('The test "%s" does not exist', $name);
|
331 |
+
if ($alternatives = $env->computeAlternatives($name, array_keys($env->getTests()))) {
|
332 |
+
$message = sprintf('%s. Did you mean "%s"', $message, implode('", "', $alternatives));
|
333 |
+
}
|
334 |
+
|
335 |
+
throw new Twig_Error_Syntax($message, $line, $parser->getFilename());
|
336 |
+
}
|
337 |
+
|
338 |
+
if ($testMap[$name] instanceof Twig_SimpleTest) {
|
339 |
+
return $testMap[$name]->getNodeClass();
|
340 |
+
}
|
341 |
+
|
342 |
+
return $testMap[$name] instanceof Twig_Test_Node ? $testMap[$name]->getClass() : 'Twig_Node_Expression_Test';
|
343 |
+
}
|
344 |
+
|
345 |
+
/**
|
346 |
+
* Returns the name of the extension.
|
347 |
+
*
|
348 |
+
* @return string The extension name
|
349 |
+
*/
|
350 |
+
public function getName()
|
351 |
+
{
|
352 |
+
return 'core';
|
353 |
+
}
|
354 |
+
}
|
355 |
+
|
356 |
+
/**
|
357 |
+
* Cycles over a value.
|
358 |
+
*
|
359 |
+
* @param ArrayAccess|array $values An array or an ArrayAccess instance
|
360 |
+
* @param int $position The cycle position
|
361 |
+
*
|
362 |
+
* @return string The next value in the cycle
|
363 |
+
*/
|
364 |
+
function twig_cycle($values, $position)
|
365 |
+
{
|
366 |
+
if (!is_array($values) && !$values instanceof ArrayAccess) {
|
367 |
+
return $values;
|
368 |
+
}
|
369 |
+
|
370 |
+
return $values[$position % count($values)];
|
371 |
+
}
|
372 |
+
|
373 |
+
/**
|
374 |
+
* Returns a random value depending on the supplied parameter type:
|
375 |
+
* - a random item from a Traversable or array
|
376 |
+
* - a random character from a string
|
377 |
+
* - a random integer between 0 and the integer parameter
|
378 |
+
*
|
379 |
+
* @param Twig_Environment $env A Twig_Environment instance
|
380 |
+
* @param Traversable|array|int|string $values The values to pick a random item from
|
381 |
+
*
|
382 |
+
* @throws Twig_Error_Runtime When $values is an empty array (does not apply to an empty string which is returned as is).
|
383 |
+
*
|
384 |
+
* @return mixed A random value from the given sequence
|
385 |
+
*/
|
386 |
+
function twig_random(Twig_Environment $env, $values = null)
|
387 |
+
{
|
388 |
+
if (null === $values) {
|
389 |
+
return mt_rand();
|
390 |
+
}
|
391 |
+
|
392 |
+
if (is_int($values) || is_float($values)) {
|
393 |
+
return $values < 0 ? mt_rand($values, 0) : mt_rand(0, $values);
|
394 |
+
}
|
395 |
+
|
396 |
+
if ($values instanceof Traversable) {
|
397 |
+
$values = iterator_to_array($values);
|
398 |
+
} elseif (is_string($values)) {
|
399 |
+
if ('' === $values) {
|
400 |
+
return '';
|
401 |
+
}
|
402 |
+
if (null !== $charset = $env->getCharset()) {
|
403 |
+
if ('UTF-8' != $charset) {
|
404 |
+
$values = twig_convert_encoding($values, 'UTF-8', $charset);
|
405 |
+
}
|
406 |
+
|
407 |
+
// unicode version of str_split()
|
408 |
+
// split at all positions, but not after the start and not before the end
|
409 |
+
$values = preg_split('/(?<!^)(?!$)/u', $values);
|
410 |
+
|
411 |
+
if ('UTF-8' != $charset) {
|
412 |
+
foreach ($values as $i => $value) {
|
413 |
+
$values[$i] = twig_convert_encoding($value, $charset, 'UTF-8');
|
414 |
+
}
|
415 |
+
}
|
416 |
+
} else {
|
417 |
+
return $values[mt_rand(0, strlen($values) - 1)];
|
418 |
+
}
|
419 |
+
}
|
420 |
+
|
421 |
+
if (!is_array($values)) {
|
422 |
+
return $values;
|
423 |
+
}
|
424 |
+
|
425 |
+
if (0 === count($values)) {
|
426 |
+
throw new Twig_Error_Runtime('The random function cannot pick from an empty array.');
|
427 |
+
}
|
428 |
+
|
429 |
+
return $values[array_rand($values, 1)];
|
430 |
+
}
|
431 |
+
|
432 |
+
/**
|
433 |
+
* Converts a date to the given format.
|
434 |
+
*
|
435 |
+
* <pre>
|
436 |
+
* {{ post.published_at|date("m/d/Y") }}
|
437 |
+
* </pre>
|
438 |
+
*
|
439 |
+
* @param Twig_Environment $env A Twig_Environment instance
|
440 |
+
* @param DateTime|DateInterval|string $date A date
|
441 |
+
* @param string $format A format
|
442 |
+
* @param DateTimeZone|string $timezone A timezone
|
443 |
+
*
|
444 |
+
* @return string The formatted date
|
445 |
+
*/
|
446 |
+
function twig_date_format_filter(Twig_Environment $env, $date, $format = null, $timezone = null)
|
447 |
+
{
|
448 |
+
if (null === $format) {
|
449 |
+
$formats = $env->getExtension('core')->getDateFormat();
|
450 |
+
$format = $date instanceof DateInterval ? $formats[1] : $formats[0];
|
451 |
+
}
|
452 |
+
|
453 |
+
if ($date instanceof DateInterval) {
|
454 |
+
return $date->format($format);
|
455 |
+
}
|
456 |
+
|
457 |
+
return twig_date_converter($env, $date, $timezone)->format($format);
|
458 |
+
}
|
459 |
+
|
460 |
+
/**
|
461 |
+
* Returns a new date object modified
|
462 |
+
*
|
463 |
+
* <pre>
|
464 |
+
* {{ post.published_at|date_modify("-1day")|date("m/d/Y") }}
|
465 |
+
* </pre>
|
466 |
+
*
|
467 |
+
* @param Twig_Environment $env A Twig_Environment instance
|
468 |
+
* @param DateTime|string $date A date
|
469 |
+
* @param string $modifier A modifier string
|
470 |
+
*
|
471 |
+
* @return DateTime A new date object
|
472 |
+
*/
|
473 |
+
function twig_date_modify_filter(Twig_Environment $env, $date, $modifier)
|
474 |
+
{
|
475 |
+
$date = twig_date_converter($env, $date, false);
|
476 |
+
$date->modify($modifier);
|
477 |
+
|
478 |
+
return $date;
|
479 |
+
}
|
480 |
+
|
481 |
+
/**
|
482 |
+
* Converts an input to a DateTime instance.
|
483 |
+
*
|
484 |
+
* <pre>
|
485 |
+
* {% if date(user.created_at) < date('+2days') %}
|
486 |
+
* {# do something #}
|
487 |
+
* {% endif %}
|
488 |
+
* </pre>
|
489 |
+
*
|
490 |
+
* @param Twig_Environment $env A Twig_Environment instance
|
491 |
+
* @param DateTime|string $date A date
|
492 |
+
* @param DateTimeZone|string $timezone A timezone
|
493 |
+
*
|
494 |
+
* @return DateTime A DateTime instance
|
495 |
+
*/
|
496 |
+
function twig_date_converter(Twig_Environment $env, $date = null, $timezone = null)
|
497 |
+
{
|
498 |
+
// determine the timezone
|
499 |
+
if (!$timezone) {
|
500 |
+
$defaultTimezone = $env->getExtension('core')->getTimezone();
|
501 |
+
} elseif (!$timezone instanceof DateTimeZone) {
|
502 |
+
$defaultTimezone = new DateTimeZone($timezone);
|
503 |
+
} else {
|
504 |
+
$defaultTimezone = $timezone;
|
505 |
+
}
|
506 |
+
|
507 |
+
// immutable dates
|
508 |
+
if ($date instanceof DateTimeImmutable) {
|
509 |
+
return false !== $timezone ? $date->setTimezone($defaultTimezone) : $date;
|
510 |
+
}
|
511 |
+
|
512 |
+
if ($date instanceof DateTime || $date instanceof DateTimeInterface) {
|
513 |
+
$date = clone $date;
|
514 |
+
if (false !== $timezone) {
|
515 |
+
$date->setTimezone($defaultTimezone);
|
516 |
+
}
|
517 |
+
|
518 |
+
return $date;
|
519 |
+
}
|
520 |
+
|
521 |
+
$asString = (string) $date;
|
522 |
+
if (ctype_digit($asString) || (!empty($asString) && '-' === $asString[0] && ctype_digit(substr($asString, 1)))) {
|
523 |
+
$date = '@'.$date;
|
524 |
+
}
|
525 |
+
|
526 |
+
$date = new DateTime($date, $defaultTimezone);
|
527 |
+
if (false !== $timezone) {
|
528 |
+
$date->setTimezone($defaultTimezone);
|
529 |
+
}
|
530 |
+
|
531 |
+
return $date;
|
532 |
+
}
|
533 |
+
|
534 |
+
/**
|
535 |
+
* Rounds a number.
|
536 |
+
*
|
537 |
+
* @param int|float $value The value to round
|
538 |
+
* @param int|float $precision The rounding precision
|
539 |
+
* @param string $method The method to use for rounding
|
540 |
+
*
|
541 |
+
* @return int|float The rounded number
|
542 |
+
*/
|
543 |
+
function twig_round($value, $precision = 0, $method = 'common')
|
544 |
+
{
|
545 |
+
if ('common' == $method) {
|
546 |
+
return round($value, $precision);
|
547 |
+
}
|
548 |
+
|
549 |
+
if ('ceil' != $method && 'floor' != $method) {
|
550 |
+
throw new Twig_Error_Runtime('The round filter only supports the "common", "ceil", and "floor" methods.');
|
551 |
+
}
|
552 |
+
|
553 |
+
return $method($value * pow(10, $precision)) / pow(10, $precision);
|
554 |
+
}
|
555 |
+
|
556 |
+
/**
|
557 |
+
* Number format filter.
|
558 |
+
*
|
559 |
+
* All of the formatting options can be left null, in that case the defaults will
|
560 |
+
* be used. Supplying any of the parameters will override the defaults set in the
|
561 |
+
* environment object.
|
562 |
+
*
|
563 |
+
* @param Twig_Environment $env A Twig_Environment instance
|
564 |
+
* @param mixed $number A float/int/string of the number to format
|
565 |
+
* @param int $decimal The number of decimal points to display.
|
566 |
+
* @param string $decimalPoint The character(s) to use for the decimal point.
|
567 |
+
* @param string $thousandSep The character(s) to use for the thousands separator.
|
568 |
+
*
|
569 |
+
* @return string The formatted number
|
570 |
+
*/
|
571 |
+
function twig_number_format_filter(Twig_Environment $env, $number, $decimal = null, $decimalPoint = null, $thousandSep = null)
|
572 |
+
{
|
573 |
+
$defaults = $env->getExtension('core')->getNumberFormat();
|
574 |
+
if (null === $decimal) {
|
575 |
+
$decimal = $defaults[0];
|
576 |
+
}
|
577 |
+
|
578 |
+
if (null === $decimalPoint) {
|
579 |
+
$decimalPoint = $defaults[1];
|
580 |
+
}
|
581 |
+
|
582 |
+
if (null === $thousandSep) {
|
583 |
+
$thousandSep = $defaults[2];
|
584 |
+
}
|
585 |
+
|
586 |
+
return number_format((float) $number, $decimal, $decimalPoint, $thousandSep);
|
587 |
+
}
|
588 |
+
|
589 |
+
/**
|
590 |
+
* URL encodes (RFC 3986) a string as a path segment or an array as a query string.
|
591 |
+
*
|
592 |
+
* @param string|array $url A URL or an array of query parameters
|
593 |
+
*
|
594 |
+
* @return string The URL encoded value
|
595 |
+
*/
|
596 |
+
function twig_urlencode_filter($url)
|
597 |
+
{
|
598 |
+
if (is_array($url)) {
|
599 |
+
if (defined('PHP_QUERY_RFC3986')) {
|
600 |
+
return http_build_query($url, '', '&', PHP_QUERY_RFC3986);
|
601 |
+
}
|
602 |
+
|
603 |
+
return http_build_query($url, '', '&');
|
604 |
+
}
|
605 |
+
|
606 |
+
return rawurlencode($url);
|
607 |
+
}
|
608 |
+
|
609 |
+
if (version_compare(PHP_VERSION, '5.3.0', '<')) {
|
610 |
+
/**
|
611 |
+
* JSON encodes a variable.
|
612 |
+
*
|
613 |
+
* @param mixed $value The value to encode.
|
614 |
+
* @param int $options Not used on PHP 5.2.x
|
615 |
+
*
|
616 |
+
* @return mixed The JSON encoded value
|
617 |
+
*/
|
618 |
+
function twig_jsonencode_filter($value, $options = 0)
|
619 |
+
{
|
620 |
+
if ($value instanceof Twig_Markup) {
|
621 |
+
$value = (string) $value;
|
622 |
+
} elseif (is_array($value)) {
|
623 |
+
array_walk_recursive($value, '_twig_markup2string');
|
624 |
+
}
|
625 |
+
|
626 |
+
return json_encode($value);
|
627 |
+
}
|
628 |
+
} else {
|
629 |
+
/**
|
630 |
+
* JSON encodes a variable.
|
631 |
+
*
|
632 |
+
* @param mixed $value The value to encode.
|
633 |
+
* @param int $options Bitmask consisting of JSON_HEX_QUOT, JSON_HEX_TAG, JSON_HEX_AMP, JSON_HEX_APOS, JSON_NUMERIC_CHECK, JSON_PRETTY_PRINT, JSON_UNESCAPED_SLASHES, JSON_FORCE_OBJECT
|
634 |
+
*
|
635 |
+
* @return mixed The JSON encoded value
|
636 |
+
*/
|
637 |
+
function twig_jsonencode_filter($value, $options = 0)
|
638 |
+
{
|
639 |
+
if ($value instanceof Twig_Markup) {
|
640 |
+
$value = (string) $value;
|
641 |
+
} elseif (is_array($value)) {
|
642 |
+
array_walk_recursive($value, '_twig_markup2string');
|
643 |
+
}
|
644 |
+
|
645 |
+
return json_encode($value, $options);
|
646 |
+
}
|
647 |
+
}
|
648 |
+
|
649 |
+
function _twig_markup2string(&$value)
|
650 |
+
{
|
651 |
+
if ($value instanceof Twig_Markup) {
|
652 |
+
$value = (string) $value;
|
653 |
+
}
|
654 |
+
}
|
655 |
+
|
656 |
+
/**
|
657 |
+
* Merges an array with another one.
|
658 |
+
*
|
659 |
+
* <pre>
|
660 |
+
* {% set items = { 'apple': 'fruit', 'orange': 'fruit' } %}
|
661 |
+
*
|
662 |
+
* {% set items = items|merge({ 'peugeot': 'car' }) %}
|
663 |
+
*
|
664 |
+
* {# items now contains { 'apple': 'fruit', 'orange': 'fruit', 'peugeot': 'car' } #}
|
665 |
+
* </pre>
|
666 |
+
*
|
667 |
+
* @param array $arr1 An array
|
668 |
+
* @param array $arr2 An array
|
669 |
+
*
|
670 |
+
* @return array The merged array
|
671 |
+
*/
|
672 |
+
function twig_array_merge($arr1, $arr2)
|
673 |
+
{
|
674 |
+
if (!is_array($arr1) || !is_array($arr2)) {
|
675 |
+
throw new Twig_Error_Runtime('The merge filter only works with arrays or hashes.');
|
676 |
+
}
|
677 |
+
|
678 |
+
return array_merge($arr1, $arr2);
|
679 |
+
}
|
680 |
+
|
681 |
+
/**
|
682 |
+
* Slices a variable.
|
683 |
+
*
|
684 |
+
* @param Twig_Environment $env A Twig_Environment instance
|
685 |
+
* @param mixed $item A variable
|
686 |
+
* @param int $start Start of the slice
|
687 |
+
* @param int $length Size of the slice
|
688 |
+
* @param bool $preserveKeys Whether to preserve key or not (when the input is an array)
|
689 |
+
*
|
690 |
+
* @return mixed The sliced variable
|
691 |
+
*/
|
692 |
+
function twig_slice(Twig_Environment $env, $item, $start, $length = null, $preserveKeys = false)
|
693 |
+
{
|
694 |
+
if ($item instanceof Traversable) {
|
695 |
+
$item = iterator_to_array($item, false);
|
696 |
+
}
|
697 |
+
|
698 |
+
if (is_array($item)) {
|
699 |
+
return array_slice($item, $start, $length, $preserveKeys);
|
700 |
+
}
|
701 |
+
|
702 |
+
$item = (string) $item;
|
703 |
+
|
704 |
+
if (function_exists('mb_get_info') && null !== $charset = $env->getCharset()) {
|
705 |
+
return mb_substr($item, $start, null === $length ? mb_strlen($item, $charset) - $start : $length, $charset);
|
706 |
+
}
|
707 |
+
|
708 |
+
return null === $length ? substr($item, $start) : substr($item, $start, $length);
|
709 |
+
}
|
710 |
+
|
711 |
+
/**
|
712 |
+
* Returns the first element of the item.
|
713 |
+
*
|
714 |
+
* @param Twig_Environment $env A Twig_Environment instance
|
715 |
+
* @param mixed $item A variable
|
716 |
+
*
|
717 |
+
* @return mixed The first element of the item
|
718 |
+
*/
|
719 |
+
function twig_first(Twig_Environment $env, $item)
|
720 |
+
{
|
721 |
+
$elements = twig_slice($env, $item, 0, 1, false);
|
722 |
+
|
723 |
+
return is_string($elements) ? $elements : current($elements);
|
724 |
+
}
|
725 |
+
|
726 |
+
/**
|
727 |
+
* Returns the last element of the item.
|
728 |
+
*
|
729 |
+
* @param Twig_Environment $env A Twig_Environment instance
|
730 |
+
* @param mixed $item A variable
|
731 |
+
*
|
732 |
+
* @return mixed The last element of the item
|
733 |
+
*/
|
734 |
+
function twig_last(Twig_Environment $env, $item)
|
735 |
+
{
|
736 |
+
$elements = twig_slice($env, $item, -1, 1, false);
|
737 |
+
|
738 |
+
return is_string($elements) ? $elements : current($elements);
|
739 |
+
}
|
740 |
+
|
741 |
+
/**
|
742 |
+
* Joins the values to a string.
|
743 |
+
*
|
744 |
+
* The separator between elements is an empty string per default, you can define it with the optional parameter.
|
745 |
+
*
|
746 |
+
* <pre>
|
747 |
+
* {{ [1, 2, 3]|join('|') }}
|
748 |
+
* {# returns 1|2|3 #}
|
749 |
+
*
|
750 |
+
* {{ [1, 2, 3]|join }}
|
751 |
+
* {# returns 123 #}
|
752 |
+
* </pre>
|
753 |
+
*
|
754 |
+
* @param array $value An array
|
755 |
+
* @param string $glue The separator
|
756 |
+
*
|
757 |
+
* @return string The concatenated string
|
758 |
+
*/
|
759 |
+
function twig_join_filter($value, $glue = '')
|
760 |
+
{
|
761 |
+
if ($value instanceof Traversable) {
|
762 |
+
$value = iterator_to_array($value, false);
|
763 |
+
}
|
764 |
+
|
765 |
+
return implode($glue, (array) $value);
|
766 |
+
}
|
767 |
+
|
768 |
+
/**
|
769 |
+
* Splits the string into an array.
|
770 |
+
*
|
771 |
+
* <pre>
|
772 |
+
* {{ "one,two,three"|split(',') }}
|
773 |
+
* {# returns [one, two, three] #}
|
774 |
+
*
|
775 |
+
* {{ "one,two,three,four,five"|split(',', 3) }}
|
776 |
+
* {# returns [one, two, "three,four,five"] #}
|
777 |
+
*
|
778 |
+
* {{ "123"|split('') }}
|
779 |
+
* {# returns [1, 2, 3] #}
|
780 |
+
*
|
781 |
+
* {{ "aabbcc"|split('', 2) }}
|
782 |
+
* {# returns [aa, bb, cc] #}
|
783 |
+
* </pre>
|
784 |
+
*
|
785 |
+
* @param string $value A string
|
786 |
+
* @param string $delimiter The delimiter
|
787 |
+
* @param int $limit The limit
|
788 |
+
*
|
789 |
+
* @return array The split string as an array
|
790 |
+
*/
|
791 |
+
function twig_split_filter($value, $delimiter, $limit = null)
|
792 |
+
{
|
793 |
+
if (empty($delimiter)) {
|
794 |
+
return str_split($value, null === $limit ? 1 : $limit);
|
795 |
+
}
|
796 |
+
|
797 |
+
return null === $limit ? explode($delimiter, $value) : explode($delimiter, $value, $limit);
|
798 |
+
}
|
799 |
+
|
800 |
+
// The '_default' filter is used internally to avoid using the ternary operator
|
801 |
+
// which costs a lot for big contexts (before PHP 5.4). So, on average,
|
802 |
+
// a function call is cheaper.
|
803 |
+
function _twig_default_filter($value, $default = '')
|
804 |
+
{
|
805 |
+
if (twig_test_empty($value)) {
|
806 |
+
return $default;
|
807 |
+
}
|
808 |
+
|
809 |
+
return $value;
|
810 |
+
}
|
811 |
+
|
812 |
+
/**
|
813 |
+
* Returns the keys for the given array.
|
814 |
+
*
|
815 |
+
* It is useful when you want to iterate over the keys of an array:
|
816 |
+
*
|
817 |
+
* <pre>
|
818 |
+
* {% for key in array|keys %}
|
819 |
+
* {# ... #}
|
820 |
+
* {% endfor %}
|
821 |
+
* </pre>
|
822 |
+
*
|
823 |
+
* @param array $array An array
|
824 |
+
*
|
825 |
+
* @return array The keys
|
826 |
+
*/
|
827 |
+
function twig_get_array_keys_filter($array)
|
828 |
+
{
|
829 |
+
if (is_object($array) && $array instanceof Traversable) {
|
830 |
+
return array_keys(iterator_to_array($array));
|
831 |
+
}
|
832 |
+
|
833 |
+
if (!is_array($array)) {
|
834 |
+
return array();
|
835 |
+
}
|
836 |
+
|
837 |
+
return array_keys($array);
|
838 |
+
}
|
839 |
+
|
840 |
+
/**
|
841 |
+
* Reverses a variable.
|
842 |
+
*
|
843 |
+
* @param Twig_Environment $env A Twig_Environment instance
|
844 |
+
* @param array|Traversable|string $item An array, a Traversable instance, or a string
|
845 |
+
* @param bool $preserveKeys Whether to preserve key or not
|
846 |
+
*
|
847 |
+
* @return mixed The reversed input
|
848 |
+
*/
|
849 |
+
function twig_reverse_filter(Twig_Environment $env, $item, $preserveKeys = false)
|
850 |
+
{
|
851 |
+
if (is_object($item) && $item instanceof Traversable) {
|
852 |
+
return array_reverse(iterator_to_array($item), $preserveKeys);
|
853 |
+
}
|
854 |
+
|
855 |
+
if (is_array($item)) {
|
856 |
+
return array_reverse($item, $preserveKeys);
|
857 |
+
}
|
858 |
+
|
859 |
+
if (null !== $charset = $env->getCharset()) {
|
860 |
+
$string = (string) $item;
|
861 |
+
|
862 |
+
if ('UTF-8' != $charset) {
|
863 |
+
$item = twig_convert_encoding($string, 'UTF-8', $charset);
|
864 |
+
}
|
865 |
+
|
866 |
+
preg_match_all('/./us', $item, $matches);
|
867 |
+
|
868 |
+
$string = implode('', array_reverse($matches[0]));
|
869 |
+
|
870 |
+
if ('UTF-8' != $charset) {
|
871 |
+
$string = twig_convert_encoding($string, $charset, 'UTF-8');
|
872 |
+
}
|
873 |
+
|
874 |
+
return $string;
|
875 |
+
}
|
876 |
+
|
877 |
+
return strrev((string) $item);
|
878 |
+
}
|
879 |
+
|
880 |
+
/**
|
881 |
+
* Sorts an array.
|
882 |
+
*
|
883 |
+
* @param array $array An array
|
884 |
+
*/
|
885 |
+
function twig_sort_filter($array)
|
886 |
+
{
|
887 |
+
asort($array);
|
888 |
+
|
889 |
+
return $array;
|
890 |
+
}
|
891 |
+
|
892 |
+
/* used internally */
|
893 |
+
function twig_in_filter($value, $compare)
|
894 |
+
{
|
895 |
+
if (is_array($compare)) {
|
896 |
+
return in_array($value, $compare, is_object($value));
|
897 |
+
} elseif (is_string($compare)) {
|
898 |
+
if (!strlen($value)) {
|
899 |
+
return empty($compare);
|
900 |
+
}
|
901 |
+
|
902 |
+
return false !== strpos($compare, (string) $value);
|
903 |
+
} elseif ($compare instanceof Traversable) {
|
904 |
+
return in_array($value, iterator_to_array($compare, false), is_object($value));
|
905 |
+
}
|
906 |
+
|
907 |
+
return false;
|
908 |
+
}
|
909 |
+
|
910 |
+
/**
|
911 |
+
* Escapes a string.
|
912 |
+
*
|
913 |
+
* @param Twig_Environment $env A Twig_Environment instance
|
914 |
+
* @param string $string The value to be escaped
|
915 |
+
* @param string $strategy The escaping strategy
|
916 |
+
* @param string $charset The charset
|
917 |
+
* @param bool $autoescape Whether the function is called by the auto-escaping feature (true) or by the developer (false)
|
918 |
+
*/
|
919 |
+
function twig_escape_filter(Twig_Environment $env, $string, $strategy = 'html', $charset = null, $autoescape = false)
|
920 |
+
{
|
921 |
+
if ($autoescape && $string instanceof Twig_Markup) {
|
922 |
+
return $string;
|
923 |
+
}
|
924 |
+
|
925 |
+
if (!is_string($string)) {
|
926 |
+
if (is_object($string) && method_exists($string, '__toString')) {
|
927 |
+
$string = (string) $string;
|
928 |
+
} else {
|
929 |
+
return $string;
|
930 |
+
}
|
931 |
+
}
|
932 |
+
|
933 |
+
if (null === $charset) {
|
934 |
+
$charset = $env->getCharset();
|
935 |
+
}
|
936 |
+
|
937 |
+
switch ($strategy) {
|
938 |
+
case 'html':
|
939 |
+
// see http://php.net/htmlspecialchars
|
940 |
+
|
941 |
+
// Using a static variable to avoid initializing the array
|
942 |
+
// each time the function is called. Moving the declaration on the
|
943 |
+
// top of the function slow downs other escaping strategies.
|
944 |
+
static $htmlspecialcharsCharsets;
|
945 |
+
|
946 |
+
if (null === $htmlspecialcharsCharsets) {
|
947 |
+
if ('hiphop' === substr(PHP_VERSION, -6)) {
|
948 |
+
$htmlspecialcharsCharsets = array('utf-8' => true, 'UTF-8' => true);
|
949 |
+
} else {
|
950 |
+
$htmlspecialcharsCharsets = array(
|
951 |
+
'ISO-8859-1' => true, 'ISO8859-1' => true,
|
952 |
+
'ISO-8859-15' => true, 'ISO8859-15' => true,
|
953 |
+
'utf-8' => true, 'UTF-8' => true,
|
954 |
+
'CP866' => true, 'IBM866' => true, '866' => true,
|
955 |
+
'CP1251' => true, 'WINDOWS-1251' => true, 'WIN-1251' => true,
|
956 |
+
'1251' => true,
|
957 |
+
'CP1252' => true, 'WINDOWS-1252' => true, '1252' => true,
|
958 |
+
'KOI8-R' => true, 'KOI8-RU' => true, 'KOI8R' => true,
|
959 |
+
'BIG5' => true, '950' => true,
|
960 |
+
'GB2312' => true, '936' => true,
|
961 |
+
'BIG5-HKSCS' => true,
|
962 |
+
'SHIFT_JIS' => true, 'SJIS' => true, '932' => true,
|
963 |
+
'EUC-JP' => true, 'EUCJP' => true,
|
964 |
+
'ISO8859-5' => true, 'ISO-8859-5' => true, 'MACROMAN' => true,
|
965 |
+
);
|
966 |
+
}
|
967 |
+
}
|
968 |
+
|
969 |
+
if (isset($htmlspecialcharsCharsets[$charset])) {
|
970 |
+
return htmlspecialchars($string, ENT_QUOTES | ENT_SUBSTITUTE, $charset);
|
971 |
+
}
|
972 |
+
|
973 |
+
if (isset($htmlspecialcharsCharsets[strtoupper($charset)])) {
|
974 |
+
// cache the lowercase variant for future iterations
|
975 |
+
$htmlspecialcharsCharsets[$charset] = true;
|
976 |
+
|
977 |
+
return htmlspecialchars($string, ENT_QUOTES | ENT_SUBSTITUTE, $charset);
|
978 |
+
}
|
979 |
+
|
980 |
+
$string = twig_convert_encoding($string, 'UTF-8', $charset);
|
981 |
+
$string = htmlspecialchars($string, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
|
982 |
+
|
983 |
+
return twig_convert_encoding($string, $charset, 'UTF-8');
|
984 |
+
|
985 |
+
case 'js':
|
986 |
+
// escape all non-alphanumeric characters
|
987 |
+
// into their \xHH or \uHHHH representations
|
988 |
+
if ('UTF-8' != $charset) {
|
989 |
+
$string = twig_convert_encoding($string, 'UTF-8', $charset);
|
990 |
+
}
|
991 |
+
|
992 |
+
if (0 == strlen($string) ? false : (1 == preg_match('/^./su', $string) ? false : true)) {
|
993 |
+
throw new Twig_Error_Runtime('The string to escape is not a valid UTF-8 string.');
|
994 |
+
}
|
995 |
+
|
996 |
+
$string = preg_replace_callback('#[^a-zA-Z0-9,\._]#Su', '_twig_escape_js_callback', $string);
|
997 |
+
|
998 |
+
if ('UTF-8' != $charset) {
|
999 |
+
$string = twig_convert_encoding($string, $charset, 'UTF-8');
|
1000 |
+
}
|
1001 |
+
|
1002 |
+
return $string;
|
1003 |
+
|
1004 |
+
case 'css':
|
1005 |
+
if ('UTF-8' != $charset) {
|
1006 |
+
$string = twig_convert_encoding($string, 'UTF-8', $charset);
|
1007 |
+
}
|
1008 |
+
|
1009 |
+
if (0 == strlen($string) ? false : (1 == preg_match('/^./su', $string) ? false : true)) {
|
1010 |
+
throw new Twig_Error_Runtime('The string to escape is not a valid UTF-8 string.');
|
1011 |
+
}
|
1012 |
+
|
1013 |
+
$string = preg_replace_callback('#[^a-zA-Z0-9]#Su', '_twig_escape_css_callback', $string);
|
1014 |
+
|
1015 |
+
if ('UTF-8' != $charset) {
|
1016 |
+
$string = twig_convert_encoding($string, $charset, 'UTF-8');
|
1017 |
+
}
|
1018 |
+
|
1019 |
+
return $string;
|
1020 |
+
|
1021 |
+
case 'html_attr':
|
1022 |
+
if ('UTF-8' != $charset) {
|
1023 |
+
$string = twig_convert_encoding($string, 'UTF-8', $charset);
|
1024 |
+
}
|
1025 |
+
|
1026 |
+
if (0 == strlen($string) ? false : (1 == preg_match('/^./su', $string) ? false : true)) {
|
1027 |
+
throw new Twig_Error_Runtime('The string to escape is not a valid UTF-8 string.');
|
1028 |
+
}
|
1029 |
+
|
1030 |
+
$string = preg_replace_callback('#[^a-zA-Z0-9,\.\-_]#Su', '_twig_escape_html_attr_callback', $string);
|
1031 |
+
|
1032 |
+
if ('UTF-8' != $charset) {
|
1033 |
+
$string = twig_convert_encoding($string, $charset, 'UTF-8');
|
1034 |
+
}
|
1035 |
+
|
1036 |
+
return $string;
|
1037 |
+
|
1038 |
+
case 'url':
|
1039 |
+
// hackish test to avoid version_compare that is much slower, this works unless PHP releases a 5.10.*
|
1040 |
+
// at that point however PHP 5.2.* support can be removed
|
1041 |
+
if (PHP_VERSION < '5.3.0') {
|
1042 |
+
return str_replace('%7E', '~', rawurlencode($string));
|
1043 |
+
}
|
1044 |
+
|
1045 |
+
return rawurlencode($string);
|
1046 |
+
|
1047 |
+
default:
|
1048 |
+
static $escapers;
|
1049 |
+
|
1050 |
+
if (null === $escapers) {
|
1051 |
+
$escapers = $env->getExtension('core')->getEscapers();
|
1052 |
+
}
|
1053 |
+
|
1054 |
+
if (isset($escapers[$strategy])) {
|
1055 |
+
return call_user_func($escapers[$strategy], $env, $string, $charset);
|
1056 |
+
}
|
1057 |
+
|
1058 |
+
$validStrategies = implode(', ', array_merge(array('html', 'js', 'url', 'css', 'html_attr'), array_keys($escapers)));
|
1059 |
+
|
1060 |
+
throw new Twig_Error_Runtime(sprintf('Invalid escaping strategy "%s" (valid ones: %s).', $strategy, $validStrategies));
|
1061 |
+
}
|
1062 |
+
}
|
1063 |
+
|
1064 |
+
/* used internally */
|
1065 |
+
function twig_escape_filter_is_safe(Twig_Node $filterArgs)
|
1066 |
+
{
|
1067 |
+
foreach ($filterArgs as $arg) {
|
1068 |
+
if ($arg instanceof Twig_Node_Expression_Constant) {
|
1069 |
+
return array($arg->getAttribute('value'));
|
1070 |
+
}
|
1071 |
+
|
1072 |
+
return array();
|
1073 |
+
}
|
1074 |
+
|
1075 |
+
return array('html');
|
1076 |
+
}
|
1077 |
+
|
1078 |
+
if (function_exists('mb_convert_encoding')) {
|
1079 |
+
function twig_convert_encoding($string, $to, $from)
|
1080 |
+
{
|
1081 |
+
return mb_convert_encoding($string, $to, $from);
|
1082 |
+
}
|
1083 |
+
} elseif (function_exists('iconv')) {
|
1084 |
+
function twig_convert_encoding($string, $to, $from)
|
1085 |
+
{
|
1086 |
+
return iconv($from, $to, $string);
|
1087 |
+
}
|
1088 |
+
} else {
|
1089 |
+
function twig_convert_encoding($string, $to, $from)
|
1090 |
+
{
|
1091 |
+
throw new Twig_Error_Runtime('No suitable convert encoding function (use UTF-8 as your encoding or install the iconv or mbstring extension).');
|
1092 |
+
}
|
1093 |
+
}
|
1094 |
+
|
1095 |
+
function _twig_escape_js_callback($matches)
|
1096 |
+
{
|
1097 |
+
$char = $matches[0];
|
1098 |
+
|
1099 |
+
// \xHH
|
1100 |
+
if (!isset($char[1])) {
|
1101 |
+
return '\\x'.strtoupper(substr('00'.bin2hex($char), -2));
|
1102 |
+
}
|
1103 |
+
|
1104 |
+
// \uHHHH
|
1105 |
+
$char = twig_convert_encoding($char, 'UTF-16BE', 'UTF-8');
|
1106 |
+
|
1107 |
+
return '\\u'.strtoupper(substr('0000'.bin2hex($char), -4));
|
1108 |
+
}
|
1109 |
+
|
1110 |
+
function _twig_escape_css_callback($matches)
|
1111 |
+
{
|
1112 |
+
$char = $matches[0];
|
1113 |
+
|
1114 |
+
// \xHH
|
1115 |
+
if (!isset($char[1])) {
|
1116 |
+
$hex = ltrim(strtoupper(bin2hex($char)), '0');
|
1117 |
+
if (0 === strlen($hex)) {
|
1118 |
+
$hex = '0';
|
1119 |
+
}
|
1120 |
+
|
1121 |
+
return '\\'.$hex.' ';
|
1122 |
+
}
|
1123 |
+
|
1124 |
+
// \uHHHH
|
1125 |
+
$char = twig_convert_encoding($char, 'UTF-16BE', 'UTF-8');
|
1126 |
+
|
1127 |
+
return '\\'.ltrim(strtoupper(bin2hex($char)), '0').' ';
|
1128 |
+
}
|
1129 |
+
|
1130 |
+
/**
|
1131 |
+
* This function is adapted from code coming from Zend Framework.
|
1132 |
+
*
|
1133 |
+
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
|
1134 |
+
* @license http://framework.zend.com/license/new-bsd New BSD License
|
1135 |
+
*/
|
1136 |
+
function _twig_escape_html_attr_callback($matches)
|
1137 |
+
{
|
1138 |
+
/*
|
1139 |
+
* While HTML supports far more named entities, the lowest common denominator
|
1140 |
+
* has become HTML5's XML Serialisation which is restricted to the those named
|
1141 |
+
* entities that XML supports. Using HTML entities would result in this error:
|
1142 |
+
* XML Parsing Error: undefined entity
|
1143 |
+
*/
|
1144 |
+
static $entityMap = array(
|
1145 |
+
34 => 'quot', /* quotation mark */
|
1146 |
+
38 => 'amp', /* ampersand */
|
1147 |
+
60 => 'lt', /* less-than sign */
|
1148 |
+
62 => 'gt', /* greater-than sign */
|
1149 |
+
);
|
1150 |
+
|
1151 |
+
$chr = $matches[0];
|
1152 |
+
$ord = ord($chr);
|
1153 |
+
|
1154 |
+
/**
|
1155 |
+
* The following replaces characters undefined in HTML with the
|
1156 |
+
* hex entity for the Unicode replacement character.
|
1157 |
+
*/
|
1158 |
+
if (($ord <= 0x1f && $chr != "\t" && $chr != "\n" && $chr != "\r") || ($ord >= 0x7f && $ord <= 0x9f)) {
|
1159 |
+
return '�';
|
1160 |
+
}
|
1161 |
+
|
1162 |
+
/**
|
1163 |
+
* Check if the current character to escape has a name entity we should
|
1164 |
+
* replace it with while grabbing the hex value of the character.
|
1165 |
+
*/
|
1166 |
+
if (strlen($chr) == 1) {
|
1167 |
+
$hex = strtoupper(substr('00'.bin2hex($chr), -2));
|
1168 |
+
} else {
|
1169 |
+
$chr = twig_convert_encoding($chr, 'UTF-16BE', 'UTF-8');
|
1170 |
+
$hex = strtoupper(substr('0000'.bin2hex($chr), -4));
|
1171 |
+
}
|
1172 |
+
|
1173 |
+
$int = hexdec($hex);
|
1174 |
+
if (array_key_exists($int, $entityMap)) {
|
1175 |
+
return sprintf('&%s;', $entityMap[$int]);
|
1176 |
+
}
|
1177 |
+
|
1178 |
+
/**
|
1179 |
+
* Per OWASP recommendations, we'll use hex entities for any other
|
1180 |
+
* characters where a named entity does not exist.
|
1181 |
+
*/
|
1182 |
+
|
1183 |
+
return sprintf('&#x%s;', $hex);
|
1184 |
+
}
|
1185 |
+
|
1186 |
+
// add multibyte extensions if possible
|
1187 |
+
if (function_exists('mb_get_info')) {
|
1188 |
+
/**
|
1189 |
+
* Returns the length of a variable.
|
1190 |
+
*
|
1191 |
+
* @param Twig_Environment $env A Twig_Environment instance
|
1192 |
+
* @param mixed $thing A variable
|
1193 |
+
*
|
1194 |
+
* @return int The length of the value
|
1195 |
+
*/
|
1196 |
+
function twig_length_filter(Twig_Environment $env, $thing)
|
1197 |
+
{
|
1198 |
+
return is_scalar($thing) ? mb_strlen($thing, $env->getCharset()) : count($thing);
|
1199 |
+
}
|
1200 |
+
|
1201 |
+
/**
|
1202 |
+
* Converts a string to uppercase.
|
1203 |
+
*
|
1204 |
+
* @param Twig_Environment $env A Twig_Environment instance
|
1205 |
+
* @param string $string A string
|
1206 |
+
*
|
1207 |
+
* @return string The uppercased string
|
1208 |
+
*/
|
1209 |
+
function twig_upper_filter(Twig_Environment $env, $string)
|
1210 |
+
{
|
1211 |
+
if (null !== ($charset = $env->getCharset())) {
|
1212 |
+
return mb_strtoupper($string, $charset);
|
1213 |
+
}
|
1214 |
+
|
1215 |
+
return strtoupper($string);
|
1216 |
+
}
|
1217 |
+
|
1218 |
+
/**
|
1219 |
+
* Converts a string to lowercase.
|
1220 |
+
*
|
1221 |
+
* @param Twig_Environment $env A Twig_Environment instance
|
1222 |
+
* @param string $string A string
|
1223 |
+
*
|
1224 |
+
* @return string The lowercased string
|
1225 |
+
*/
|
1226 |
+
function twig_lower_filter(Twig_Environment $env, $string)
|
1227 |
+
{
|
1228 |
+
if (null !== ($charset = $env->getCharset())) {
|
1229 |
+
return mb_strtolower($string, $charset);
|
1230 |
+
}
|
1231 |
+
|
1232 |
+
return strtolower($string);
|
1233 |
+
}
|
1234 |
+
|
1235 |
+
/**
|
1236 |
+
* Returns a titlecased string.
|
1237 |
+
*
|
1238 |
+
* @param Twig_Environment $env A Twig_Environment instance
|
1239 |
+
* @param string $string A string
|
1240 |
+
*
|
1241 |
+
* @return string The titlecased string
|
1242 |
+
*/
|
1243 |
+
function twig_title_string_filter(Twig_Environment $env, $string)
|
1244 |
+
{
|
1245 |
+
if (null !== ($charset = $env->getCharset())) {
|
1246 |
+
return mb_convert_case($string, MB_CASE_TITLE, $charset);
|
1247 |
+
}
|
1248 |
+
|
1249 |
+
return ucwords(strtolower($string));
|
1250 |
+
}
|
1251 |
+
|
1252 |
+
/**
|
1253 |
+
* Returns a capitalized string.
|
1254 |
+
*
|
1255 |
+
* @param Twig_Environment $env A Twig_Environment instance
|
1256 |
+
* @param string $string A string
|
1257 |
+
*
|
1258 |
+
* @return string The capitalized string
|
1259 |
+
*/
|
1260 |
+
function twig_capitalize_string_filter(Twig_Environment $env, $string)
|
1261 |
+
{
|
1262 |
+
if (null !== ($charset = $env->getCharset())) {
|
1263 |
+
return mb_strtoupper(mb_substr($string, 0, 1, $charset), $charset).
|
1264 |
+
mb_strtolower(mb_substr($string, 1, mb_strlen($string, $charset), $charset), $charset);
|
1265 |
+
}
|
1266 |
+
|
1267 |
+
return ucfirst(strtolower($string));
|
1268 |
+
}
|
1269 |
+
}
|
1270 |
+
// and byte fallback
|
1271 |
+
else {
|
1272 |
+
/**
|
1273 |
+
* Returns the length of a variable.
|
1274 |
+
*
|
1275 |
+
* @param Twig_Environment $env A Twig_Environment instance
|
1276 |
+
* @param mixed $thing A variable
|
1277 |
+
*
|
1278 |
+
* @return int The length of the value
|
1279 |
+
*/
|
1280 |
+
function twig_length_filter(Twig_Environment $env, $thing)
|
1281 |
+
{
|
1282 |
+
return is_scalar($thing) ? strlen($thing) : count($thing);
|
1283 |
+
}
|
1284 |
+
|
1285 |
+
/**
|
1286 |
+
* Returns a titlecased string.
|
1287 |
+
*
|
1288 |
+
* @param Twig_Environment $env A Twig_Environment instance
|
1289 |
+
* @param string $string A string
|
1290 |
+
*
|
1291 |
+
* @return string The titlecased string
|
1292 |
+
*/
|
1293 |
+
function twig_title_string_filter(Twig_Environment $env, $string)
|
1294 |
+
{
|
1295 |
+
return ucwords(strtolower($string));
|
1296 |
+
}
|
1297 |
+
|
1298 |
+
/**
|
1299 |
+
* Returns a capitalized string.
|
1300 |
+
*
|
1301 |
+
* @param Twig_Environment $env A Twig_Environment instance
|
1302 |
+
* @param string $string A string
|
1303 |
+
*
|
1304 |
+
* @return string The capitalized string
|
1305 |
+
*/
|
1306 |
+
function twig_capitalize_string_filter(Twig_Environment $env, $string)
|
1307 |
+
{
|
1308 |
+
return ucfirst(strtolower($string));
|
1309 |
+
}
|
1310 |
+
}
|
1311 |
+
|
1312 |
+
/* used internally */
|
1313 |
+
function twig_ensure_traversable($seq)
|
1314 |
+
{
|
1315 |
+
if ($seq instanceof Traversable || is_array($seq)) {
|
1316 |
+
return $seq;
|
1317 |
+
}
|
1318 |
+
|
1319 |
+
return array();
|
1320 |
+
}
|
1321 |
+
|
1322 |
+
/**
|
1323 |
+
* Checks if a variable is empty.
|
1324 |
+
*
|
1325 |
+
* <pre>
|
1326 |
+
* {# evaluates to true if the foo variable is null, false, or the empty string #}
|
1327 |
+
* {% if foo is empty %}
|
1328 |
+
* {# ... #}
|
1329 |
+
* {% endif %}
|
1330 |
+
* </pre>
|
1331 |
+
*
|
1332 |
+
* @param mixed $value A variable
|
1333 |
+
*
|
1334 |
+
* @return bool true if the value is empty, false otherwise
|
1335 |
+
*/
|
1336 |
+
function twig_test_empty($value)
|
1337 |
+
{
|
1338 |
+
if ($value instanceof Countable) {
|
1339 |
+
return 0 == count($value);
|
1340 |
+
}
|
1341 |
+
|
1342 |
+
return '' === $value || false === $value || null === $value || array() === $value;
|
1343 |
+
}
|
1344 |
+
|
1345 |
+
/**
|
1346 |
+
* Checks if a variable is traversable.
|
1347 |
+
*
|
1348 |
+
* <pre>
|
1349 |
+
* {# evaluates to true if the foo variable is an array or a traversable object #}
|
1350 |
+
* {% if foo is traversable %}
|
1351 |
+
* {# ... #}
|
1352 |
+
* {% endif %}
|
1353 |
+
* </pre>
|
1354 |
+
*
|
1355 |
+
* @param mixed $value A variable
|
1356 |
+
*
|
1357 |
+
* @return bool true if the value is traversable
|
1358 |
+
*/
|
1359 |
+
function twig_test_iterable($value)
|
1360 |
+
{
|
1361 |
+
return $value instanceof Traversable || is_array($value);
|
1362 |
+
}
|
1363 |
+
|
1364 |
+
/**
|
1365 |
+
* Renders a template.
|
1366 |
+
*
|
1367 |
+
* @param string|array $template The template to render or an array of templates to try consecutively
|
1368 |
+
* @param array $variables The variables to pass to the template
|
1369 |
+
* @param bool $with_context Whether to pass the current context variables or not
|
1370 |
+
* @param bool $ignore_missing Whether to ignore missing templates or not
|
1371 |
+
* @param bool $sandboxed Whether to sandbox the template or not
|
1372 |
+
*
|
1373 |
+
* @return string The rendered template
|
1374 |
+
*/
|
1375 |
+
function twig_include(Twig_Environment $env, $context, $template, $variables = array(), $withContext = true, $ignoreMissing = false, $sandboxed = false)
|
1376 |
+
{
|
1377 |
+
$alreadySandboxed = false;
|
1378 |
+
$sandbox = null;
|
1379 |
+
if ($withContext) {
|
1380 |
+
$variables = array_merge($context, $variables);
|
1381 |
+
}
|
1382 |
+
|
1383 |
+
if ($isSandboxed = $sandboxed && $env->hasExtension('sandbox')) {
|
1384 |
+
$sandbox = $env->getExtension('sandbox');
|
1385 |
+
if (!$alreadySandboxed = $sandbox->isSandboxed()) {
|
1386 |
+
$sandbox->enableSandbox();
|
1387 |
+
}
|
1388 |
+
}
|
1389 |
+
|
1390 |
+
try {
|
1391 |
+
return $env->resolveTemplate($template)->render($variables);
|
1392 |
+
} catch (Twig_Error_Loader $e) {
|
1393 |
+
if (!$ignoreMissing) {
|
1394 |
+
throw $e;
|
1395 |
+
}
|
1396 |
+
}
|
1397 |
+
|
1398 |
+
if ($isSandboxed && !$alreadySandboxed) {
|
1399 |
+
$sandbox->disableSandbox();
|
1400 |
+
}
|
1401 |
+
}
|
1402 |
+
|
1403 |
+
/**
|
1404 |
+
* Returns a template content without rendering it.
|
1405 |
+
*
|
1406 |
+
* @param string $name The template name
|
1407 |
+
*
|
1408 |
+
* @return string The template source
|
1409 |
+
*/
|
1410 |
+
function twig_source(Twig_Environment $env, $name)
|
1411 |
+
{
|
1412 |
+
return $env->getLoader()->getSource($name);
|
1413 |
+
}
|
1414 |
+
|
1415 |
+
/**
|
1416 |
+
* Provides the ability to get constants from instances as well as class/global constants.
|
1417 |
+
*
|
1418 |
+
* @param string $constant The name of the constant
|
1419 |
+
* @param null|object $object The object to get the constant from
|
1420 |
+
*
|
1421 |
+
* @return string
|
1422 |
+
*/
|
1423 |
+
function twig_constant($constant, $object = null)
|
1424 |
+
{
|
1425 |
+
if (null !== $object) {
|
1426 |
+
$constant = get_class($object).'::'.$constant;
|
1427 |
+
}
|
1428 |
+
|
1429 |
+
return constant($constant);
|
1430 |
+
}
|
1431 |
+
|
1432 |
+
/**
|
1433 |
+
* Batches item.
|
1434 |
+
*
|
1435 |
+
* @param array $items An array of items
|
1436 |
+
* @param int $size The size of the batch
|
1437 |
+
* @param mixed $fill A value used to fill missing items
|
1438 |
+
*
|
1439 |
+
* @return array
|
1440 |
+
*/
|
1441 |
+
function twig_array_batch($items, $size, $fill = null)
|
1442 |
+
{
|
1443 |
+
if ($items instanceof Traversable) {
|
1444 |
+
$items = iterator_to_array($items, false);
|
1445 |
+
}
|
1446 |
+
|
1447 |
+
$size = ceil($size);
|
1448 |
+
|
1449 |
+
$result = array_chunk($items, $size, true);
|
1450 |
+
|
1451 |
+
if (null !== $fill) {
|
1452 |
+
$last = count($result) - 1;
|
1453 |
+
if ($fillCount = $size - count($result[$last])) {
|
1454 |
+
$result[$last] = array_merge(
|
1455 |
+
$result[$last],
|
1456 |
+
array_fill(0, $fillCount, $fill)
|
1457 |
+
);
|
1458 |
+
}
|
1459 |
+
}
|
1460 |
+
|
1461 |
+
return $result;
|
1462 |
+
}
|
classes/Twig/Extension/Debug.php
CHANGED
@@ -1,71 +1,71 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2011 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
class Twig_Extension_Debug extends Twig_Extension
|
12 |
-
{
|
13 |
-
/**
|
14 |
-
* Returns a list of global functions to add to the existing list.
|
15 |
-
*
|
16 |
-
* @return array An array of global functions
|
17 |
-
*/
|
18 |
-
public function getFunctions()
|
19 |
-
{
|
20 |
-
// dump is safe if var_dump is overridden by xdebug
|
21 |
-
$isDumpOutputHtmlSafe = extension_loaded('xdebug')
|
22 |
-
// false means that it was not set (and the default is on) or it explicitly enabled
|
23 |
-
&& (false === ini_get('xdebug.overload_var_dump') || ini_get('xdebug.overload_var_dump'))
|
24 |
-
// false means that it was not set (and the default is on) or it explicitly enabled
|
25 |
-
// xdebug.overload_var_dump produces HTML only when html_errors is also enabled
|
26 |
-
&& (false === ini_get('html_errors') || ini_get('html_errors'))
|
27 |
-
|| 'cli' === php_sapi_name()
|
28 |
-
;
|
29 |
-
|
30 |
-
return array(
|
31 |
-
new Twig_SimpleFunction('dump', 'twig_var_dump', array('is_safe' => $isDumpOutputHtmlSafe ? array('html') : array(), 'needs_context' => true, 'needs_environment' => true)),
|
32 |
-
);
|
33 |
-
}
|
34 |
-
|
35 |
-
/**
|
36 |
-
* Returns the name of the extension.
|
37 |
-
*
|
38 |
-
* @return string The extension name
|
39 |
-
*/
|
40 |
-
public function getName()
|
41 |
-
{
|
42 |
-
return 'debug';
|
43 |
-
}
|
44 |
-
}
|
45 |
-
|
46 |
-
function twig_var_dump(Twig_Environment $env, $context)
|
47 |
-
{
|
48 |
-
if (!$env->isDebug()) {
|
49 |
-
return;
|
50 |
-
}
|
51 |
-
|
52 |
-
ob_start();
|
53 |
-
|
54 |
-
$count = func_num_args();
|
55 |
-
if (2 === $count) {
|
56 |
-
$vars = array();
|
57 |
-
foreach ($context as $key => $value) {
|
58 |
-
if (!$value instanceof Twig_Template) {
|
59 |
-
$vars[$key] = $value;
|
60 |
-
}
|
61 |
-
}
|
62 |
-
|
63 |
-
var_dump($vars);
|
64 |
-
} else {
|
65 |
-
for ($i = 2; $i < $count; $i++) {
|
66 |
-
var_dump(func_get_arg($i));
|
67 |
-
}
|
68 |
-
}
|
69 |
-
|
70 |
-
return ob_get_clean();
|
71 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2011 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
class Twig_Extension_Debug extends Twig_Extension
|
12 |
+
{
|
13 |
+
/**
|
14 |
+
* Returns a list of global functions to add to the existing list.
|
15 |
+
*
|
16 |
+
* @return array An array of global functions
|
17 |
+
*/
|
18 |
+
public function getFunctions()
|
19 |
+
{
|
20 |
+
// dump is safe if var_dump is overridden by xdebug
|
21 |
+
$isDumpOutputHtmlSafe = extension_loaded('xdebug')
|
22 |
+
// false means that it was not set (and the default is on) or it explicitly enabled
|
23 |
+
&& (false === ini_get('xdebug.overload_var_dump') || ini_get('xdebug.overload_var_dump'))
|
24 |
+
// false means that it was not set (and the default is on) or it explicitly enabled
|
25 |
+
// xdebug.overload_var_dump produces HTML only when html_errors is also enabled
|
26 |
+
&& (false === ini_get('html_errors') || ini_get('html_errors'))
|
27 |
+
|| 'cli' === php_sapi_name()
|
28 |
+
;
|
29 |
+
|
30 |
+
return array(
|
31 |
+
new Twig_SimpleFunction('dump', 'twig_var_dump', array('is_safe' => $isDumpOutputHtmlSafe ? array('html') : array(), 'needs_context' => true, 'needs_environment' => true)),
|
32 |
+
);
|
33 |
+
}
|
34 |
+
|
35 |
+
/**
|
36 |
+
* Returns the name of the extension.
|
37 |
+
*
|
38 |
+
* @return string The extension name
|
39 |
+
*/
|
40 |
+
public function getName()
|
41 |
+
{
|
42 |
+
return 'debug';
|
43 |
+
}
|
44 |
+
}
|
45 |
+
|
46 |
+
function twig_var_dump(Twig_Environment $env, $context)
|
47 |
+
{
|
48 |
+
if (!$env->isDebug()) {
|
49 |
+
return;
|
50 |
+
}
|
51 |
+
|
52 |
+
ob_start();
|
53 |
+
|
54 |
+
$count = func_num_args();
|
55 |
+
if (2 === $count) {
|
56 |
+
$vars = array();
|
57 |
+
foreach ($context as $key => $value) {
|
58 |
+
if (!$value instanceof Twig_Template) {
|
59 |
+
$vars[$key] = $value;
|
60 |
+
}
|
61 |
+
}
|
62 |
+
|
63 |
+
var_dump($vars);
|
64 |
+
} else {
|
65 |
+
for ($i = 2; $i < $count; $i++) {
|
66 |
+
var_dump(func_get_arg($i));
|
67 |
+
}
|
68 |
+
}
|
69 |
+
|
70 |
+
return ob_get_clean();
|
71 |
+
}
|
classes/Twig/Extension/Escaper.php
CHANGED
@@ -1,107 +1,107 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2009 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
class Twig_Extension_Escaper extends Twig_Extension
|
12 |
-
{
|
13 |
-
protected $defaultStrategy;
|
14 |
-
|
15 |
-
public function __construct($defaultStrategy = 'html')
|
16 |
-
{
|
17 |
-
$this->setDefaultStrategy($defaultStrategy);
|
18 |
-
}
|
19 |
-
|
20 |
-
/**
|
21 |
-
* Returns the token parser instances to add to the existing list.
|
22 |
-
*
|
23 |
-
* @return array An array of Twig_TokenParserInterface or Twig_TokenParserBrokerInterface instances
|
24 |
-
*/
|
25 |
-
public function getTokenParsers()
|
26 |
-
{
|
27 |
-
return array(new Twig_TokenParser_AutoEscape());
|
28 |
-
}
|
29 |
-
|
30 |
-
/**
|
31 |
-
* Returns the node visitor instances to add to the existing list.
|
32 |
-
*
|
33 |
-
* @return Twig_NodeVisitorInterface[] An array of Twig_NodeVisitorInterface instances
|
34 |
-
*/
|
35 |
-
public function getNodeVisitors()
|
36 |
-
{
|
37 |
-
return array(new Twig_NodeVisitor_Escaper());
|
38 |
-
}
|
39 |
-
|
40 |
-
/**
|
41 |
-
* Returns a list of filters to add to the existing list.
|
42 |
-
*
|
43 |
-
* @return array An array of filters
|
44 |
-
*/
|
45 |
-
public function getFilters()
|
46 |
-
{
|
47 |
-
return array(
|
48 |
-
new Twig_SimpleFilter('raw', 'twig_raw_filter', array('is_safe' => array('all'))),
|
49 |
-
);
|
50 |
-
}
|
51 |
-
|
52 |
-
/**
|
53 |
-
* Sets the default strategy to use when not defined by the user.
|
54 |
-
*
|
55 |
-
* The strategy can be a valid PHP callback that takes the template
|
56 |
-
* "filename" as an argument and returns the strategy to use.
|
57 |
-
*
|
58 |
-
* @param mixed $defaultStrategy An escaping strategy
|
59 |
-
*/
|
60 |
-
public function setDefaultStrategy($defaultStrategy)
|
61 |
-
{
|
62 |
-
// for BC
|
63 |
-
if (true === $defaultStrategy) {
|
64 |
-
$defaultStrategy = 'html';
|
65 |
-
}
|
66 |
-
|
67 |
-
$this->defaultStrategy = $defaultStrategy;
|
68 |
-
}
|
69 |
-
|
70 |
-
/**
|
71 |
-
* Gets the default strategy to use when not defined by the user.
|
72 |
-
*
|
73 |
-
* @param string $filename The template "filename"
|
74 |
-
*
|
75 |
-
* @return string The default strategy to use for the template
|
76 |
-
*/
|
77 |
-
public function getDefaultStrategy($filename)
|
78 |
-
{
|
79 |
-
// disable string callables to avoid calling a function named html or js,
|
80 |
-
// or any other upcoming escaping strategy
|
81 |
-
if (!is_string($this->defaultStrategy) && is_callable($this->defaultStrategy)) {
|
82 |
-
return call_user_func($this->defaultStrategy, $filename);
|
83 |
-
}
|
84 |
-
|
85 |
-
return $this->defaultStrategy;
|
86 |
-
}
|
87 |
-
|
88 |
-
/**
|
89 |
-
* Returns the name of the extension.
|
90 |
-
*
|
91 |
-
* @return string The extension name
|
92 |
-
*/
|
93 |
-
public function getName()
|
94 |
-
{
|
95 |
-
return 'escaper';
|
96 |
-
}
|
97 |
-
}
|
98 |
-
|
99 |
-
/**
|
100 |
-
* Marks a variable as being safe.
|
101 |
-
*
|
102 |
-
* @param string $string A PHP variable
|
103 |
-
*/
|
104 |
-
function twig_raw_filter($string)
|
105 |
-
{
|
106 |
-
return $string;
|
107 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2009 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
class Twig_Extension_Escaper extends Twig_Extension
|
12 |
+
{
|
13 |
+
protected $defaultStrategy;
|
14 |
+
|
15 |
+
public function __construct($defaultStrategy = 'html')
|
16 |
+
{
|
17 |
+
$this->setDefaultStrategy($defaultStrategy);
|
18 |
+
}
|
19 |
+
|
20 |
+
/**
|
21 |
+
* Returns the token parser instances to add to the existing list.
|
22 |
+
*
|
23 |
+
* @return array An array of Twig_TokenParserInterface or Twig_TokenParserBrokerInterface instances
|
24 |
+
*/
|
25 |
+
public function getTokenParsers()
|
26 |
+
{
|
27 |
+
return array(new Twig_TokenParser_AutoEscape());
|
28 |
+
}
|
29 |
+
|
30 |
+
/**
|
31 |
+
* Returns the node visitor instances to add to the existing list.
|
32 |
+
*
|
33 |
+
* @return Twig_NodeVisitorInterface[] An array of Twig_NodeVisitorInterface instances
|
34 |
+
*/
|
35 |
+
public function getNodeVisitors()
|
36 |
+
{
|
37 |
+
return array(new Twig_NodeVisitor_Escaper());
|
38 |
+
}
|
39 |
+
|
40 |
+
/**
|
41 |
+
* Returns a list of filters to add to the existing list.
|
42 |
+
*
|
43 |
+
* @return array An array of filters
|
44 |
+
*/
|
45 |
+
public function getFilters()
|
46 |
+
{
|
47 |
+
return array(
|
48 |
+
new Twig_SimpleFilter('raw', 'twig_raw_filter', array('is_safe' => array('all'))),
|
49 |
+
);
|
50 |
+
}
|
51 |
+
|
52 |
+
/**
|
53 |
+
* Sets the default strategy to use when not defined by the user.
|
54 |
+
*
|
55 |
+
* The strategy can be a valid PHP callback that takes the template
|
56 |
+
* "filename" as an argument and returns the strategy to use.
|
57 |
+
*
|
58 |
+
* @param mixed $defaultStrategy An escaping strategy
|
59 |
+
*/
|
60 |
+
public function setDefaultStrategy($defaultStrategy)
|
61 |
+
{
|
62 |
+
// for BC
|
63 |
+
if (true === $defaultStrategy) {
|
64 |
+
$defaultStrategy = 'html';
|
65 |
+
}
|
66 |
+
|
67 |
+
$this->defaultStrategy = $defaultStrategy;
|
68 |
+
}
|
69 |
+
|
70 |
+
/**
|
71 |
+
* Gets the default strategy to use when not defined by the user.
|
72 |
+
*
|
73 |
+
* @param string $filename The template "filename"
|
74 |
+
*
|
75 |
+
* @return string The default strategy to use for the template
|
76 |
+
*/
|
77 |
+
public function getDefaultStrategy($filename)
|
78 |
+
{
|
79 |
+
// disable string callables to avoid calling a function named html or js,
|
80 |
+
// or any other upcoming escaping strategy
|
81 |
+
if (!is_string($this->defaultStrategy) && is_callable($this->defaultStrategy)) {
|
82 |
+
return call_user_func($this->defaultStrategy, $filename);
|
83 |
+
}
|
84 |
+
|
85 |
+
return $this->defaultStrategy;
|
86 |
+
}
|
87 |
+
|
88 |
+
/**
|
89 |
+
* Returns the name of the extension.
|
90 |
+
*
|
91 |
+
* @return string The extension name
|
92 |
+
*/
|
93 |
+
public function getName()
|
94 |
+
{
|
95 |
+
return 'escaper';
|
96 |
+
}
|
97 |
+
}
|
98 |
+
|
99 |
+
/**
|
100 |
+
* Marks a variable as being safe.
|
101 |
+
*
|
102 |
+
* @param string $string A PHP variable
|
103 |
+
*/
|
104 |
+
function twig_raw_filter($string)
|
105 |
+
{
|
106 |
+
return $string;
|
107 |
+
}
|
classes/Twig/Extension/Optimizer.php
CHANGED
@@ -1,35 +1,35 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2010 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
class Twig_Extension_Optimizer extends Twig_Extension
|
12 |
-
{
|
13 |
-
protected $optimizers;
|
14 |
-
|
15 |
-
public function __construct($optimizers = -1)
|
16 |
-
{
|
17 |
-
$this->optimizers = $optimizers;
|
18 |
-
}
|
19 |
-
|
20 |
-
/**
|
21 |
-
* {@inheritdoc}
|
22 |
-
*/
|
23 |
-
public function getNodeVisitors()
|
24 |
-
{
|
25 |
-
return array(new Twig_NodeVisitor_Optimizer($this->optimizers));
|
26 |
-
}
|
27 |
-
|
28 |
-
/**
|
29 |
-
* {@inheritdoc}
|
30 |
-
*/
|
31 |
-
public function getName()
|
32 |
-
{
|
33 |
-
return 'optimizer';
|
34 |
-
}
|
35 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2010 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
class Twig_Extension_Optimizer extends Twig_Extension
|
12 |
+
{
|
13 |
+
protected $optimizers;
|
14 |
+
|
15 |
+
public function __construct($optimizers = -1)
|
16 |
+
{
|
17 |
+
$this->optimizers = $optimizers;
|
18 |
+
}
|
19 |
+
|
20 |
+
/**
|
21 |
+
* {@inheritdoc}
|
22 |
+
*/
|
23 |
+
public function getNodeVisitors()
|
24 |
+
{
|
25 |
+
return array(new Twig_NodeVisitor_Optimizer($this->optimizers));
|
26 |
+
}
|
27 |
+
|
28 |
+
/**
|
29 |
+
* {@inheritdoc}
|
30 |
+
*/
|
31 |
+
public function getName()
|
32 |
+
{
|
33 |
+
return 'optimizer';
|
34 |
+
}
|
35 |
+
}
|
classes/Twig/Extension/Sandbox.php
CHANGED
@@ -1,112 +1,112 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2009 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
class Twig_Extension_Sandbox extends Twig_Extension
|
12 |
-
{
|
13 |
-
protected $sandboxedGlobally;
|
14 |
-
protected $sandboxed;
|
15 |
-
protected $policy;
|
16 |
-
|
17 |
-
public function __construct(Twig_Sandbox_SecurityPolicyInterface $policy, $sandboxed = false)
|
18 |
-
{
|
19 |
-
$this->policy = $policy;
|
20 |
-
$this->sandboxedGlobally = $sandboxed;
|
21 |
-
}
|
22 |
-
|
23 |
-
/**
|
24 |
-
* Returns the token parser instances to add to the existing list.
|
25 |
-
*
|
26 |
-
* @return array An array of Twig_TokenParserInterface or Twig_TokenParserBrokerInterface instances
|
27 |
-
*/
|
28 |
-
public function getTokenParsers()
|
29 |
-
{
|
30 |
-
return array(new Twig_TokenParser_Sandbox());
|
31 |
-
}
|
32 |
-
|
33 |
-
/**
|
34 |
-
* Returns the node visitor instances to add to the existing list.
|
35 |
-
*
|
36 |
-
* @return Twig_NodeVisitorInterface[] An array of Twig_NodeVisitorInterface instances
|
37 |
-
*/
|
38 |
-
public function getNodeVisitors()
|
39 |
-
{
|
40 |
-
return array(new Twig_NodeVisitor_Sandbox());
|
41 |
-
}
|
42 |
-
|
43 |
-
public function enableSandbox()
|
44 |
-
{
|
45 |
-
$this->sandboxed = true;
|
46 |
-
}
|
47 |
-
|
48 |
-
public function disableSandbox()
|
49 |
-
{
|
50 |
-
$this->sandboxed = false;
|
51 |
-
}
|
52 |
-
|
53 |
-
public function isSandboxed()
|
54 |
-
{
|
55 |
-
return $this->sandboxedGlobally || $this->sandboxed;
|
56 |
-
}
|
57 |
-
|
58 |
-
public function isSandboxedGlobally()
|
59 |
-
{
|
60 |
-
return $this->sandboxedGlobally;
|
61 |
-
}
|
62 |
-
|
63 |
-
public function setSecurityPolicy(Twig_Sandbox_SecurityPolicyInterface $policy)
|
64 |
-
{
|
65 |
-
$this->policy = $policy;
|
66 |
-
}
|
67 |
-
|
68 |
-
public function getSecurityPolicy()
|
69 |
-
{
|
70 |
-
return $this->policy;
|
71 |
-
}
|
72 |
-
|
73 |
-
public function checkSecurity($tags, $filters, $functions)
|
74 |
-
{
|
75 |
-
if ($this->isSandboxed()) {
|
76 |
-
$this->policy->checkSecurity($tags, $filters, $functions);
|
77 |
-
}
|
78 |
-
}
|
79 |
-
|
80 |
-
public function checkMethodAllowed($obj, $method)
|
81 |
-
{
|
82 |
-
if ($this->isSandboxed()) {
|
83 |
-
$this->policy->checkMethodAllowed($obj, $method);
|
84 |
-
}
|
85 |
-
}
|
86 |
-
|
87 |
-
public function checkPropertyAllowed($obj, $method)
|
88 |
-
{
|
89 |
-
if ($this->isSandboxed()) {
|
90 |
-
$this->policy->checkPropertyAllowed($obj, $method);
|
91 |
-
}
|
92 |
-
}
|
93 |
-
|
94 |
-
public function ensureToStringAllowed($obj)
|
95 |
-
{
|
96 |
-
if ($this->isSandboxed() && is_object($obj)) {
|
97 |
-
$this->policy->checkMethodAllowed($obj, '__toString');
|
98 |
-
}
|
99 |
-
|
100 |
-
return $obj;
|
101 |
-
}
|
102 |
-
|
103 |
-
/**
|
104 |
-
* Returns the name of the extension.
|
105 |
-
*
|
106 |
-
* @return string The extension name
|
107 |
-
*/
|
108 |
-
public function getName()
|
109 |
-
{
|
110 |
-
return 'sandbox';
|
111 |
-
}
|
112 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2009 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
class Twig_Extension_Sandbox extends Twig_Extension
|
12 |
+
{
|
13 |
+
protected $sandboxedGlobally;
|
14 |
+
protected $sandboxed;
|
15 |
+
protected $policy;
|
16 |
+
|
17 |
+
public function __construct(Twig_Sandbox_SecurityPolicyInterface $policy, $sandboxed = false)
|
18 |
+
{
|
19 |
+
$this->policy = $policy;
|
20 |
+
$this->sandboxedGlobally = $sandboxed;
|
21 |
+
}
|
22 |
+
|
23 |
+
/**
|
24 |
+
* Returns the token parser instances to add to the existing list.
|
25 |
+
*
|
26 |
+
* @return array An array of Twig_TokenParserInterface or Twig_TokenParserBrokerInterface instances
|
27 |
+
*/
|
28 |
+
public function getTokenParsers()
|
29 |
+
{
|
30 |
+
return array(new Twig_TokenParser_Sandbox());
|
31 |
+
}
|
32 |
+
|
33 |
+
/**
|
34 |
+
* Returns the node visitor instances to add to the existing list.
|
35 |
+
*
|
36 |
+
* @return Twig_NodeVisitorInterface[] An array of Twig_NodeVisitorInterface instances
|
37 |
+
*/
|
38 |
+
public function getNodeVisitors()
|
39 |
+
{
|
40 |
+
return array(new Twig_NodeVisitor_Sandbox());
|
41 |
+
}
|
42 |
+
|
43 |
+
public function enableSandbox()
|
44 |
+
{
|
45 |
+
$this->sandboxed = true;
|
46 |
+
}
|
47 |
+
|
48 |
+
public function disableSandbox()
|
49 |
+
{
|
50 |
+
$this->sandboxed = false;
|
51 |
+
}
|
52 |
+
|
53 |
+
public function isSandboxed()
|
54 |
+
{
|
55 |
+
return $this->sandboxedGlobally || $this->sandboxed;
|
56 |
+
}
|
57 |
+
|
58 |
+
public function isSandboxedGlobally()
|
59 |
+
{
|
60 |
+
return $this->sandboxedGlobally;
|
61 |
+
}
|
62 |
+
|
63 |
+
public function setSecurityPolicy(Twig_Sandbox_SecurityPolicyInterface $policy)
|
64 |
+
{
|
65 |
+
$this->policy = $policy;
|
66 |
+
}
|
67 |
+
|
68 |
+
public function getSecurityPolicy()
|
69 |
+
{
|
70 |
+
return $this->policy;
|
71 |
+
}
|
72 |
+
|
73 |
+
public function checkSecurity($tags, $filters, $functions)
|
74 |
+
{
|
75 |
+
if ($this->isSandboxed()) {
|
76 |
+
$this->policy->checkSecurity($tags, $filters, $functions);
|
77 |
+
}
|
78 |
+
}
|
79 |
+
|
80 |
+
public function checkMethodAllowed($obj, $method)
|
81 |
+
{
|
82 |
+
if ($this->isSandboxed()) {
|
83 |
+
$this->policy->checkMethodAllowed($obj, $method);
|
84 |
+
}
|
85 |
+
}
|
86 |
+
|
87 |
+
public function checkPropertyAllowed($obj, $method)
|
88 |
+
{
|
89 |
+
if ($this->isSandboxed()) {
|
90 |
+
$this->policy->checkPropertyAllowed($obj, $method);
|
91 |
+
}
|
92 |
+
}
|
93 |
+
|
94 |
+
public function ensureToStringAllowed($obj)
|
95 |
+
{
|
96 |
+
if ($this->isSandboxed() && is_object($obj)) {
|
97 |
+
$this->policy->checkMethodAllowed($obj, '__toString');
|
98 |
+
}
|
99 |
+
|
100 |
+
return $obj;
|
101 |
+
}
|
102 |
+
|
103 |
+
/**
|
104 |
+
* Returns the name of the extension.
|
105 |
+
*
|
106 |
+
* @return string The extension name
|
107 |
+
*/
|
108 |
+
public function getName()
|
109 |
+
{
|
110 |
+
return 'sandbox';
|
111 |
+
}
|
112 |
+
}
|
classes/Twig/Extension/Staging.php
CHANGED
@@ -1,113 +1,113 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2012 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
/**
|
13 |
-
* Internal class.
|
14 |
-
*
|
15 |
-
* This class is used by Twig_Environment as a staging area and must not be used directly.
|
16 |
-
*
|
17 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
18 |
-
*/
|
19 |
-
class Twig_Extension_Staging extends Twig_Extension
|
20 |
-
{
|
21 |
-
protected $functions = array();
|
22 |
-
protected $filters = array();
|
23 |
-
protected $visitors = array();
|
24 |
-
protected $tokenParsers = array();
|
25 |
-
protected $globals = array();
|
26 |
-
protected $tests = array();
|
27 |
-
|
28 |
-
public function addFunction($name, $function)
|
29 |
-
{
|
30 |
-
$this->functions[$name] = $function;
|
31 |
-
}
|
32 |
-
|
33 |
-
/**
|
34 |
-
* {@inheritdoc}
|
35 |
-
*/
|
36 |
-
public function getFunctions()
|
37 |
-
{
|
38 |
-
return $this->functions;
|
39 |
-
}
|
40 |
-
|
41 |
-
public function addFilter($name, $filter)
|
42 |
-
{
|
43 |
-
$this->filters[$name] = $filter;
|
44 |
-
}
|
45 |
-
|
46 |
-
/**
|
47 |
-
* {@inheritdoc}
|
48 |
-
*/
|
49 |
-
public function getFilters()
|
50 |
-
{
|
51 |
-
return $this->filters;
|
52 |
-
}
|
53 |
-
|
54 |
-
public function addNodeVisitor(Twig_NodeVisitorInterface $visitor)
|
55 |
-
{
|
56 |
-
$this->visitors[] = $visitor;
|
57 |
-
}
|
58 |
-
|
59 |
-
/**
|
60 |
-
* {@inheritdoc}
|
61 |
-
*/
|
62 |
-
public function getNodeVisitors()
|
63 |
-
{
|
64 |
-
return $this->visitors;
|
65 |
-
}
|
66 |
-
|
67 |
-
public function addTokenParser(Twig_TokenParserInterface $parser)
|
68 |
-
{
|
69 |
-
$this->tokenParsers[] = $parser;
|
70 |
-
}
|
71 |
-
|
72 |
-
/**
|
73 |
-
* {@inheritdoc}
|
74 |
-
*/
|
75 |
-
public function getTokenParsers()
|
76 |
-
{
|
77 |
-
return $this->tokenParsers;
|
78 |
-
}
|
79 |
-
|
80 |
-
public function addGlobal($name, $value)
|
81 |
-
{
|
82 |
-
$this->globals[$name] = $value;
|
83 |
-
}
|
84 |
-
|
85 |
-
/**
|
86 |
-
* {@inheritdoc}
|
87 |
-
*/
|
88 |
-
public function getGlobals()
|
89 |
-
{
|
90 |
-
return $this->globals;
|
91 |
-
}
|
92 |
-
|
93 |
-
public function addTest($name, $test)
|
94 |
-
{
|
95 |
-
$this->tests[$name] = $test;
|
96 |
-
}
|
97 |
-
|
98 |
-
/**
|
99 |
-
* {@inheritdoc}
|
100 |
-
*/
|
101 |
-
public function getTests()
|
102 |
-
{
|
103 |
-
return $this->tests;
|
104 |
-
}
|
105 |
-
|
106 |
-
/**
|
107 |
-
* {@inheritdoc}
|
108 |
-
*/
|
109 |
-
public function getName()
|
110 |
-
{
|
111 |
-
return 'staging';
|
112 |
-
}
|
113 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2012 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Internal class.
|
14 |
+
*
|
15 |
+
* This class is used by Twig_Environment as a staging area and must not be used directly.
|
16 |
+
*
|
17 |
+
* @author Fabien Potencier <fabien@symfony.com>
|
18 |
+
*/
|
19 |
+
class Twig_Extension_Staging extends Twig_Extension
|
20 |
+
{
|
21 |
+
protected $functions = array();
|
22 |
+
protected $filters = array();
|
23 |
+
protected $visitors = array();
|
24 |
+
protected $tokenParsers = array();
|
25 |
+
protected $globals = array();
|
26 |
+
protected $tests = array();
|
27 |
+
|
28 |
+
public function addFunction($name, $function)
|
29 |
+
{
|
30 |
+
$this->functions[$name] = $function;
|
31 |
+
}
|
32 |
+
|
33 |
+
/**
|
34 |
+
* {@inheritdoc}
|
35 |
+
*/
|
36 |
+
public function getFunctions()
|
37 |
+
{
|
38 |
+
return $this->functions;
|
39 |
+
}
|
40 |
+
|
41 |
+
public function addFilter($name, $filter)
|
42 |
+
{
|
43 |
+
$this->filters[$name] = $filter;
|
44 |
+
}
|
45 |
+
|
46 |
+
/**
|
47 |
+
* {@inheritdoc}
|
48 |
+
*/
|
49 |
+
public function getFilters()
|
50 |
+
{
|
51 |
+
return $this->filters;
|
52 |
+
}
|
53 |
+
|
54 |
+
public function addNodeVisitor(Twig_NodeVisitorInterface $visitor)
|
55 |
+
{
|
56 |
+
$this->visitors[] = $visitor;
|
57 |
+
}
|
58 |
+
|
59 |
+
/**
|
60 |
+
* {@inheritdoc}
|
61 |
+
*/
|
62 |
+
public function getNodeVisitors()
|
63 |
+
{
|
64 |
+
return $this->visitors;
|
65 |
+
}
|
66 |
+
|
67 |
+
public function addTokenParser(Twig_TokenParserInterface $parser)
|
68 |
+
{
|
69 |
+
$this->tokenParsers[] = $parser;
|
70 |
+
}
|
71 |
+
|
72 |
+
/**
|
73 |
+
* {@inheritdoc}
|
74 |
+
*/
|
75 |
+
public function getTokenParsers()
|
76 |
+
{
|
77 |
+
return $this->tokenParsers;
|
78 |
+
}
|
79 |
+
|
80 |
+
public function addGlobal($name, $value)
|
81 |
+
{
|
82 |
+
$this->globals[$name] = $value;
|
83 |
+
}
|
84 |
+
|
85 |
+
/**
|
86 |
+
* {@inheritdoc}
|
87 |
+
*/
|
88 |
+
public function getGlobals()
|
89 |
+
{
|
90 |
+
return $this->globals;
|
91 |
+
}
|
92 |
+
|
93 |
+
public function addTest($name, $test)
|
94 |
+
{
|
95 |
+
$this->tests[$name] = $test;
|
96 |
+
}
|
97 |
+
|
98 |
+
/**
|
99 |
+
* {@inheritdoc}
|
100 |
+
*/
|
101 |
+
public function getTests()
|
102 |
+
{
|
103 |
+
return $this->tests;
|
104 |
+
}
|
105 |
+
|
106 |
+
/**
|
107 |
+
* {@inheritdoc}
|
108 |
+
*/
|
109 |
+
public function getName()
|
110 |
+
{
|
111 |
+
return 'staging';
|
112 |
+
}
|
113 |
+
}
|
classes/Twig/Extension/StringLoader.php
CHANGED
@@ -1,64 +1,64 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2012 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
class Twig_Extension_StringLoader extends Twig_Extension
|
12 |
-
{
|
13 |
-
/**
|
14 |
-
* {@inheritdoc}
|
15 |
-
*/
|
16 |
-
public function getFunctions()
|
17 |
-
{
|
18 |
-
return array(
|
19 |
-
new Twig_SimpleFunction('template_from_string', 'twig_template_from_string', array('needs_environment' => true)),
|
20 |
-
);
|
21 |
-
}
|
22 |
-
|
23 |
-
/**
|
24 |
-
* {@inheritdoc}
|
25 |
-
*/
|
26 |
-
public function getName()
|
27 |
-
{
|
28 |
-
return 'string_loader';
|
29 |
-
}
|
30 |
-
}
|
31 |
-
|
32 |
-
/**
|
33 |
-
* Loads a template from a string.
|
34 |
-
*
|
35 |
-
* <pre>
|
36 |
-
* {{ include(template_from_string("Hello {{ name }}")) }}
|
37 |
-
* </pre>
|
38 |
-
*
|
39 |
-
* @param Twig_Environment $env A Twig_Environment instance
|
40 |
-
* @param string $template A template as a string
|
41 |
-
*
|
42 |
-
* @return Twig_Template A Twig_Template instance
|
43 |
-
*/
|
44 |
-
function twig_template_from_string(Twig_Environment $env, $template)
|
45 |
-
{
|
46 |
-
$name = sprintf('__string_template__%s', hash('sha256', uniqid(mt_rand(), true), false));
|
47 |
-
|
48 |
-
$loader = new Twig_Loader_Chain(array(
|
49 |
-
new Twig_Loader_Array(array($name => $template)),
|
50 |
-
$current = $env->getLoader(),
|
51 |
-
));
|
52 |
-
|
53 |
-
$env->setLoader($loader);
|
54 |
-
try {
|
55 |
-
$template = $env->loadTemplate($name);
|
56 |
-
} catch (Exception $e) {
|
57 |
-
$env->setLoader($current);
|
58 |
-
|
59 |
-
throw $e;
|
60 |
-
}
|
61 |
-
$env->setLoader($current);
|
62 |
-
|
63 |
-
return $template;
|
64 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2012 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
class Twig_Extension_StringLoader extends Twig_Extension
|
12 |
+
{
|
13 |
+
/**
|
14 |
+
* {@inheritdoc}
|
15 |
+
*/
|
16 |
+
public function getFunctions()
|
17 |
+
{
|
18 |
+
return array(
|
19 |
+
new Twig_SimpleFunction('template_from_string', 'twig_template_from_string', array('needs_environment' => true)),
|
20 |
+
);
|
21 |
+
}
|
22 |
+
|
23 |
+
/**
|
24 |
+
* {@inheritdoc}
|
25 |
+
*/
|
26 |
+
public function getName()
|
27 |
+
{
|
28 |
+
return 'string_loader';
|
29 |
+
}
|
30 |
+
}
|
31 |
+
|
32 |
+
/**
|
33 |
+
* Loads a template from a string.
|
34 |
+
*
|
35 |
+
* <pre>
|
36 |
+
* {{ include(template_from_string("Hello {{ name }}")) }}
|
37 |
+
* </pre>
|
38 |
+
*
|
39 |
+
* @param Twig_Environment $env A Twig_Environment instance
|
40 |
+
* @param string $template A template as a string
|
41 |
+
*
|
42 |
+
* @return Twig_Template A Twig_Template instance
|
43 |
+
*/
|
44 |
+
function twig_template_from_string(Twig_Environment $env, $template)
|
45 |
+
{
|
46 |
+
$name = sprintf('__string_template__%s', hash('sha256', uniqid(mt_rand(), true), false));
|
47 |
+
|
48 |
+
$loader = new Twig_Loader_Chain(array(
|
49 |
+
new Twig_Loader_Array(array($name => $template)),
|
50 |
+
$current = $env->getLoader(),
|
51 |
+
));
|
52 |
+
|
53 |
+
$env->setLoader($loader);
|
54 |
+
try {
|
55 |
+
$template = $env->loadTemplate($name);
|
56 |
+
} catch (Exception $e) {
|
57 |
+
$env->setLoader($current);
|
58 |
+
|
59 |
+
throw $e;
|
60 |
+
}
|
61 |
+
$env->setLoader($current);
|
62 |
+
|
63 |
+
return $template;
|
64 |
+
}
|
classes/Twig/ExtensionInterface.php
CHANGED
@@ -1,83 +1,83 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2009 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
/**
|
13 |
-
* Interface implemented by extension classes.
|
14 |
-
*
|
15 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
16 |
-
*/
|
17 |
-
interface Twig_ExtensionInterface
|
18 |
-
{
|
19 |
-
/**
|
20 |
-
* Initializes the runtime environment.
|
21 |
-
*
|
22 |
-
* This is where you can load some file that contains filter functions for instance.
|
23 |
-
*
|
24 |
-
* @param Twig_Environment $environment The current Twig_Environment instance
|
25 |
-
*/
|
26 |
-
public function initRuntime(Twig_Environment $environment);
|
27 |
-
|
28 |
-
/**
|
29 |
-
* Returns the token parser instances to add to the existing list.
|
30 |
-
*
|
31 |
-
* @return array An array of Twig_TokenParserInterface or Twig_TokenParserBrokerInterface instances
|
32 |
-
*/
|
33 |
-
public function getTokenParsers();
|
34 |
-
|
35 |
-
/**
|
36 |
-
* Returns the node visitor instances to add to the existing list.
|
37 |
-
*
|
38 |
-
* @return Twig_NodeVisitorInterface[] An array of Twig_NodeVisitorInterface instances
|
39 |
-
*/
|
40 |
-
public function getNodeVisitors();
|
41 |
-
|
42 |
-
/**
|
43 |
-
* Returns a list of filters to add to the existing list.
|
44 |
-
*
|
45 |
-
* @return array An array of filters
|
46 |
-
*/
|
47 |
-
public function getFilters();
|
48 |
-
|
49 |
-
/**
|
50 |
-
* Returns a list of tests to add to the existing list.
|
51 |
-
*
|
52 |
-
* @return array An array of tests
|
53 |
-
*/
|
54 |
-
public function getTests();
|
55 |
-
|
56 |
-
/**
|
57 |
-
* Returns a list of functions to add to the existing list.
|
58 |
-
*
|
59 |
-
* @return array An array of functions
|
60 |
-
*/
|
61 |
-
public function getFunctions();
|
62 |
-
|
63 |
-
/**
|
64 |
-
* Returns a list of operators to add to the existing list.
|
65 |
-
*
|
66 |
-
* @return array An array of operators
|
67 |
-
*/
|
68 |
-
public function getOperators();
|
69 |
-
|
70 |
-
/**
|
71 |
-
* Returns a list of global variables to add to the existing list.
|
72 |
-
*
|
73 |
-
* @return array An array of global variables
|
74 |
-
*/
|
75 |
-
public function getGlobals();
|
76 |
-
|
77 |
-
/**
|
78 |
-
* Returns the name of the extension.
|
79 |
-
*
|
80 |
-
* @return string The extension name
|
81 |
-
*/
|
82 |
-
public function getName();
|
83 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2009 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Interface implemented by extension classes.
|
14 |
+
*
|
15 |
+
* @author Fabien Potencier <fabien@symfony.com>
|
16 |
+
*/
|
17 |
+
interface Twig_ExtensionInterface
|
18 |
+
{
|
19 |
+
/**
|
20 |
+
* Initializes the runtime environment.
|
21 |
+
*
|
22 |
+
* This is where you can load some file that contains filter functions for instance.
|
23 |
+
*
|
24 |
+
* @param Twig_Environment $environment The current Twig_Environment instance
|
25 |
+
*/
|
26 |
+
public function initRuntime(Twig_Environment $environment);
|
27 |
+
|
28 |
+
/**
|
29 |
+
* Returns the token parser instances to add to the existing list.
|
30 |
+
*
|
31 |
+
* @return array An array of Twig_TokenParserInterface or Twig_TokenParserBrokerInterface instances
|
32 |
+
*/
|
33 |
+
public function getTokenParsers();
|
34 |
+
|
35 |
+
/**
|
36 |
+
* Returns the node visitor instances to add to the existing list.
|
37 |
+
*
|
38 |
+
* @return Twig_NodeVisitorInterface[] An array of Twig_NodeVisitorInterface instances
|
39 |
+
*/
|
40 |
+
public function getNodeVisitors();
|
41 |
+
|
42 |
+
/**
|
43 |
+
* Returns a list of filters to add to the existing list.
|
44 |
+
*
|
45 |
+
* @return array An array of filters
|
46 |
+
*/
|
47 |
+
public function getFilters();
|
48 |
+
|
49 |
+
/**
|
50 |
+
* Returns a list of tests to add to the existing list.
|
51 |
+
*
|
52 |
+
* @return array An array of tests
|
53 |
+
*/
|
54 |
+
public function getTests();
|
55 |
+
|
56 |
+
/**
|
57 |
+
* Returns a list of functions to add to the existing list.
|
58 |
+
*
|
59 |
+
* @return array An array of functions
|
60 |
+
*/
|
61 |
+
public function getFunctions();
|
62 |
+
|
63 |
+
/**
|
64 |
+
* Returns a list of operators to add to the existing list.
|
65 |
+
*
|
66 |
+
* @return array An array of operators
|
67 |
+
*/
|
68 |
+
public function getOperators();
|
69 |
+
|
70 |
+
/**
|
71 |
+
* Returns a list of global variables to add to the existing list.
|
72 |
+
*
|
73 |
+
* @return array An array of global variables
|
74 |
+
*/
|
75 |
+
public function getGlobals();
|
76 |
+
|
77 |
+
/**
|
78 |
+
* Returns the name of the extension.
|
79 |
+
*
|
80 |
+
* @return string The extension name
|
81 |
+
*/
|
82 |
+
public function getName();
|
83 |
+
}
|
classes/Twig/Filter.php
CHANGED
@@ -1,81 +1,81 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2009 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
/**
|
13 |
-
* Represents a template filter.
|
14 |
-
*
|
15 |
-
* Use Twig_SimpleFilter instead.
|
16 |
-
*
|
17 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
18 |
-
* @deprecated since 1.12 (to be removed in 2.0)
|
19 |
-
*/
|
20 |
-
abstract class Twig_Filter implements Twig_FilterInterface, Twig_FilterCallableInterface
|
21 |
-
{
|
22 |
-
protected $options;
|
23 |
-
protected $arguments = array();
|
24 |
-
|
25 |
-
public function __construct(array $options = array())
|
26 |
-
{
|
27 |
-
$this->options = array_merge(array(
|
28 |
-
'needs_environment' => false,
|
29 |
-
'needs_context' => false,
|
30 |
-
'pre_escape' => null,
|
31 |
-
'preserves_safety' => null,
|
32 |
-
'callable' => null,
|
33 |
-
), $options);
|
34 |
-
}
|
35 |
-
|
36 |
-
public function setArguments($arguments)
|
37 |
-
{
|
38 |
-
$this->arguments = $arguments;
|
39 |
-
}
|
40 |
-
|
41 |
-
public function getArguments()
|
42 |
-
{
|
43 |
-
return $this->arguments;
|
44 |
-
}
|
45 |
-
|
46 |
-
public function needsEnvironment()
|
47 |
-
{
|
48 |
-
return $this->options['needs_environment'];
|
49 |
-
}
|
50 |
-
|
51 |
-
public function needsContext()
|
52 |
-
{
|
53 |
-
return $this->options['needs_context'];
|
54 |
-
}
|
55 |
-
|
56 |
-
public function getSafe(Twig_Node $filterArgs)
|
57 |
-
{
|
58 |
-
if (isset($this->options['is_safe'])) {
|
59 |
-
return $this->options['is_safe'];
|
60 |
-
}
|
61 |
-
|
62 |
-
if (isset($this->options['is_safe_callback'])) {
|
63 |
-
return call_user_func($this->options['is_safe_callback'], $filterArgs);
|
64 |
-
}
|
65 |
-
}
|
66 |
-
|
67 |
-
public function getPreservesSafety()
|
68 |
-
{
|
69 |
-
return $this->options['preserves_safety'];
|
70 |
-
}
|
71 |
-
|
72 |
-
public function getPreEscape()
|
73 |
-
{
|
74 |
-
return $this->options['pre_escape'];
|
75 |
-
}
|
76 |
-
|
77 |
-
public function getCallable()
|
78 |
-
{
|
79 |
-
return $this->options['callable'];
|
80 |
-
}
|
81 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2009 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Represents a template filter.
|
14 |
+
*
|
15 |
+
* Use Twig_SimpleFilter instead.
|
16 |
+
*
|
17 |
+
* @author Fabien Potencier <fabien@symfony.com>
|
18 |
+
* @deprecated since 1.12 (to be removed in 2.0)
|
19 |
+
*/
|
20 |
+
abstract class Twig_Filter implements Twig_FilterInterface, Twig_FilterCallableInterface
|
21 |
+
{
|
22 |
+
protected $options;
|
23 |
+
protected $arguments = array();
|
24 |
+
|
25 |
+
public function __construct(array $options = array())
|
26 |
+
{
|
27 |
+
$this->options = array_merge(array(
|
28 |
+
'needs_environment' => false,
|
29 |
+
'needs_context' => false,
|
30 |
+
'pre_escape' => null,
|
31 |
+
'preserves_safety' => null,
|
32 |
+
'callable' => null,
|
33 |
+
), $options);
|
34 |
+
}
|
35 |
+
|
36 |
+
public function setArguments($arguments)
|
37 |
+
{
|
38 |
+
$this->arguments = $arguments;
|
39 |
+
}
|
40 |
+
|
41 |
+
public function getArguments()
|
42 |
+
{
|
43 |
+
return $this->arguments;
|
44 |
+
}
|
45 |
+
|
46 |
+
public function needsEnvironment()
|
47 |
+
{
|
48 |
+
return $this->options['needs_environment'];
|
49 |
+
}
|
50 |
+
|
51 |
+
public function needsContext()
|
52 |
+
{
|
53 |
+
return $this->options['needs_context'];
|
54 |
+
}
|
55 |
+
|
56 |
+
public function getSafe(Twig_Node $filterArgs)
|
57 |
+
{
|
58 |
+
if (isset($this->options['is_safe'])) {
|
59 |
+
return $this->options['is_safe'];
|
60 |
+
}
|
61 |
+
|
62 |
+
if (isset($this->options['is_safe_callback'])) {
|
63 |
+
return call_user_func($this->options['is_safe_callback'], $filterArgs);
|
64 |
+
}
|
65 |
+
}
|
66 |
+
|
67 |
+
public function getPreservesSafety()
|
68 |
+
{
|
69 |
+
return $this->options['preserves_safety'];
|
70 |
+
}
|
71 |
+
|
72 |
+
public function getPreEscape()
|
73 |
+
{
|
74 |
+
return $this->options['pre_escape'];
|
75 |
+
}
|
76 |
+
|
77 |
+
public function getCallable()
|
78 |
+
{
|
79 |
+
return $this->options['callable'];
|
80 |
+
}
|
81 |
+
}
|
classes/Twig/Filter/Function.php
CHANGED
@@ -1,37 +1,37 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2009 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
/**
|
13 |
-
* Represents a function template filter.
|
14 |
-
*
|
15 |
-
* Use Twig_SimpleFilter instead.
|
16 |
-
*
|
17 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
18 |
-
* @deprecated since 1.12 (to be removed in 2.0)
|
19 |
-
*/
|
20 |
-
class Twig_Filter_Function extends Twig_Filter
|
21 |
-
{
|
22 |
-
protected $function;
|
23 |
-
|
24 |
-
public function __construct($function, array $options = array())
|
25 |
-
{
|
26 |
-
$options['callable'] = $function;
|
27 |
-
|
28 |
-
parent::__construct($options);
|
29 |
-
|
30 |
-
$this->function = $function;
|
31 |
-
}
|
32 |
-
|
33 |
-
public function compile()
|
34 |
-
{
|
35 |
-
return $this->function;
|
36 |
-
}
|
37 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2009 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Represents a function template filter.
|
14 |
+
*
|
15 |
+
* Use Twig_SimpleFilter instead.
|
16 |
+
*
|
17 |
+
* @author Fabien Potencier <fabien@symfony.com>
|
18 |
+
* @deprecated since 1.12 (to be removed in 2.0)
|
19 |
+
*/
|
20 |
+
class Twig_Filter_Function extends Twig_Filter
|
21 |
+
{
|
22 |
+
protected $function;
|
23 |
+
|
24 |
+
public function __construct($function, array $options = array())
|
25 |
+
{
|
26 |
+
$options['callable'] = $function;
|
27 |
+
|
28 |
+
parent::__construct($options);
|
29 |
+
|
30 |
+
$this->function = $function;
|
31 |
+
}
|
32 |
+
|
33 |
+
public function compile()
|
34 |
+
{
|
35 |
+
return $this->function;
|
36 |
+
}
|
37 |
+
}
|
classes/Twig/Filter/Method.php
CHANGED
@@ -1,39 +1,39 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2009 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
/**
|
13 |
-
* Represents a method template filter.
|
14 |
-
*
|
15 |
-
* Use Twig_SimpleFilter instead.
|
16 |
-
*
|
17 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
18 |
-
* @deprecated since 1.12 (to be removed in 2.0)
|
19 |
-
*/
|
20 |
-
class Twig_Filter_Method extends Twig_Filter
|
21 |
-
{
|
22 |
-
protected $extension;
|
23 |
-
protected $method;
|
24 |
-
|
25 |
-
public function __construct(Twig_ExtensionInterface $extension, $method, array $options = array())
|
26 |
-
{
|
27 |
-
$options['callable'] = array($extension, $method);
|
28 |
-
|
29 |
-
parent::__construct($options);
|
30 |
-
|
31 |
-
$this->extension = $extension;
|
32 |
-
$this->method = $method;
|
33 |
-
}
|
34 |
-
|
35 |
-
public function compile()
|
36 |
-
{
|
37 |
-
return sprintf('$this->env->getExtension(\'%s\')->%s', $this->extension->getName(), $this->method);
|
38 |
-
}
|
39 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2009 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Represents a method template filter.
|
14 |
+
*
|
15 |
+
* Use Twig_SimpleFilter instead.
|
16 |
+
*
|
17 |
+
* @author Fabien Potencier <fabien@symfony.com>
|
18 |
+
* @deprecated since 1.12 (to be removed in 2.0)
|
19 |
+
*/
|
20 |
+
class Twig_Filter_Method extends Twig_Filter
|
21 |
+
{
|
22 |
+
protected $extension;
|
23 |
+
protected $method;
|
24 |
+
|
25 |
+
public function __construct(Twig_ExtensionInterface $extension, $method, array $options = array())
|
26 |
+
{
|
27 |
+
$options['callable'] = array($extension, $method);
|
28 |
+
|
29 |
+
parent::__construct($options);
|
30 |
+
|
31 |
+
$this->extension = $extension;
|
32 |
+
$this->method = $method;
|
33 |
+
}
|
34 |
+
|
35 |
+
public function compile()
|
36 |
+
{
|
37 |
+
return sprintf('$this->env->getExtension(\'%s\')->%s', $this->extension->getName(), $this->method);
|
38 |
+
}
|
39 |
+
}
|
classes/Twig/Filter/Node.php
CHANGED
@@ -1,39 +1,39 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2011 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
/**
|
13 |
-
* Represents a template filter as a node.
|
14 |
-
*
|
15 |
-
* Use Twig_SimpleFilter instead.
|
16 |
-
*
|
17 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
18 |
-
* @deprecated since 1.12 (to be removed in 2.0)
|
19 |
-
*/
|
20 |
-
class Twig_Filter_Node extends Twig_Filter
|
21 |
-
{
|
22 |
-
protected $class;
|
23 |
-
|
24 |
-
public function __construct($class, array $options = array())
|
25 |
-
{
|
26 |
-
parent::__construct($options);
|
27 |
-
|
28 |
-
$this->class = $class;
|
29 |
-
}
|
30 |
-
|
31 |
-
public function getClass()
|
32 |
-
{
|
33 |
-
return $this->class;
|
34 |
-
}
|
35 |
-
|
36 |
-
public function compile()
|
37 |
-
{
|
38 |
-
}
|
39 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2011 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Represents a template filter as a node.
|
14 |
+
*
|
15 |
+
* Use Twig_SimpleFilter instead.
|
16 |
+
*
|
17 |
+
* @author Fabien Potencier <fabien@symfony.com>
|
18 |
+
* @deprecated since 1.12 (to be removed in 2.0)
|
19 |
+
*/
|
20 |
+
class Twig_Filter_Node extends Twig_Filter
|
21 |
+
{
|
22 |
+
protected $class;
|
23 |
+
|
24 |
+
public function __construct($class, array $options = array())
|
25 |
+
{
|
26 |
+
parent::__construct($options);
|
27 |
+
|
28 |
+
$this->class = $class;
|
29 |
+
}
|
30 |
+
|
31 |
+
public function getClass()
|
32 |
+
{
|
33 |
+
return $this->class;
|
34 |
+
}
|
35 |
+
|
36 |
+
public function compile()
|
37 |
+
{
|
38 |
+
}
|
39 |
+
}
|
classes/Twig/FilterCallableInterface.php
CHANGED
@@ -1,23 +1,23 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2012 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
/**
|
13 |
-
* Represents a callable template filter.
|
14 |
-
*
|
15 |
-
* Use Twig_SimpleFilter instead.
|
16 |
-
*
|
17 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
18 |
-
* @deprecated since 1.12 (to be removed in 2.0)
|
19 |
-
*/
|
20 |
-
interface Twig_FilterCallableInterface
|
21 |
-
{
|
22 |
-
public function getCallable();
|
23 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2012 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Represents a callable template filter.
|
14 |
+
*
|
15 |
+
* Use Twig_SimpleFilter instead.
|
16 |
+
*
|
17 |
+
* @author Fabien Potencier <fabien@symfony.com>
|
18 |
+
* @deprecated since 1.12 (to be removed in 2.0)
|
19 |
+
*/
|
20 |
+
interface Twig_FilterCallableInterface
|
21 |
+
{
|
22 |
+
public function getCallable();
|
23 |
+
}
|
classes/Twig/FilterInterface.php
CHANGED
@@ -1,42 +1,42 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2010 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
/**
|
13 |
-
* Represents a template filter.
|
14 |
-
*
|
15 |
-
* Use Twig_SimpleFilter instead.
|
16 |
-
*
|
17 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
18 |
-
* @deprecated since 1.12 (to be removed in 2.0)
|
19 |
-
*/
|
20 |
-
interface Twig_FilterInterface
|
21 |
-
{
|
22 |
-
/**
|
23 |
-
* Compiles a filter.
|
24 |
-
*
|
25 |
-
* @return string The PHP code for the filter
|
26 |
-
*/
|
27 |
-
public function compile();
|
28 |
-
|
29 |
-
public function needsEnvironment();
|
30 |
-
|
31 |
-
public function needsContext();
|
32 |
-
|
33 |
-
public function getSafe(Twig_Node $filterArgs);
|
34 |
-
|
35 |
-
public function getPreservesSafety();
|
36 |
-
|
37 |
-
public function getPreEscape();
|
38 |
-
|
39 |
-
public function setArguments($arguments);
|
40 |
-
|
41 |
-
public function getArguments();
|
42 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2010 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Represents a template filter.
|
14 |
+
*
|
15 |
+
* Use Twig_SimpleFilter instead.
|
16 |
+
*
|
17 |
+
* @author Fabien Potencier <fabien@symfony.com>
|
18 |
+
* @deprecated since 1.12 (to be removed in 2.0)
|
19 |
+
*/
|
20 |
+
interface Twig_FilterInterface
|
21 |
+
{
|
22 |
+
/**
|
23 |
+
* Compiles a filter.
|
24 |
+
*
|
25 |
+
* @return string The PHP code for the filter
|
26 |
+
*/
|
27 |
+
public function compile();
|
28 |
+
|
29 |
+
public function needsEnvironment();
|
30 |
+
|
31 |
+
public function needsContext();
|
32 |
+
|
33 |
+
public function getSafe(Twig_Node $filterArgs);
|
34 |
+
|
35 |
+
public function getPreservesSafety();
|
36 |
+
|
37 |
+
public function getPreEscape();
|
38 |
+
|
39 |
+
public function setArguments($arguments);
|
40 |
+
|
41 |
+
public function getArguments();
|
42 |
+
}
|
classes/Twig/Function.php
CHANGED
@@ -1,71 +1,71 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2010 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
/**
|
13 |
-
* Represents a template function.
|
14 |
-
*
|
15 |
-
* Use Twig_SimpleFunction instead.
|
16 |
-
*
|
17 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
18 |
-
* @deprecated since 1.12 (to be removed in 2.0)
|
19 |
-
*/
|
20 |
-
abstract class Twig_Function implements Twig_FunctionInterface, Twig_FunctionCallableInterface
|
21 |
-
{
|
22 |
-
protected $options;
|
23 |
-
protected $arguments = array();
|
24 |
-
|
25 |
-
public function __construct(array $options = array())
|
26 |
-
{
|
27 |
-
$this->options = array_merge(array(
|
28 |
-
'needs_environment' => false,
|
29 |
-
'needs_context' => false,
|
30 |
-
'callable' => null,
|
31 |
-
), $options);
|
32 |
-
}
|
33 |
-
|
34 |
-
public function setArguments($arguments)
|
35 |
-
{
|
36 |
-
$this->arguments = $arguments;
|
37 |
-
}
|
38 |
-
|
39 |
-
public function getArguments()
|
40 |
-
{
|
41 |
-
return $this->arguments;
|
42 |
-
}
|
43 |
-
|
44 |
-
public function needsEnvironment()
|
45 |
-
{
|
46 |
-
return $this->options['needs_environment'];
|
47 |
-
}
|
48 |
-
|
49 |
-
public function needsContext()
|
50 |
-
{
|
51 |
-
return $this->options['needs_context'];
|
52 |
-
}
|
53 |
-
|
54 |
-
public function getSafe(Twig_Node $functionArgs)
|
55 |
-
{
|
56 |
-
if (isset($this->options['is_safe'])) {
|
57 |
-
return $this->options['is_safe'];
|
58 |
-
}
|
59 |
-
|
60 |
-
if (isset($this->options['is_safe_callback'])) {
|
61 |
-
return call_user_func($this->options['is_safe_callback'], $functionArgs);
|
62 |
-
}
|
63 |
-
|
64 |
-
return array();
|
65 |
-
}
|
66 |
-
|
67 |
-
public function getCallable()
|
68 |
-
{
|
69 |
-
return $this->options['callable'];
|
70 |
-
}
|
71 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2010 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Represents a template function.
|
14 |
+
*
|
15 |
+
* Use Twig_SimpleFunction instead.
|
16 |
+
*
|
17 |
+
* @author Fabien Potencier <fabien@symfony.com>
|
18 |
+
* @deprecated since 1.12 (to be removed in 2.0)
|
19 |
+
*/
|
20 |
+
abstract class Twig_Function implements Twig_FunctionInterface, Twig_FunctionCallableInterface
|
21 |
+
{
|
22 |
+
protected $options;
|
23 |
+
protected $arguments = array();
|
24 |
+
|
25 |
+
public function __construct(array $options = array())
|
26 |
+
{
|
27 |
+
$this->options = array_merge(array(
|
28 |
+
'needs_environment' => false,
|
29 |
+
'needs_context' => false,
|
30 |
+
'callable' => null,
|
31 |
+
), $options);
|
32 |
+
}
|
33 |
+
|
34 |
+
public function setArguments($arguments)
|
35 |
+
{
|
36 |
+
$this->arguments = $arguments;
|
37 |
+
}
|
38 |
+
|
39 |
+
public function getArguments()
|
40 |
+
{
|
41 |
+
return $this->arguments;
|
42 |
+
}
|
43 |
+
|
44 |
+
public function needsEnvironment()
|
45 |
+
{
|
46 |
+
return $this->options['needs_environment'];
|
47 |
+
}
|
48 |
+
|
49 |
+
public function needsContext()
|
50 |
+
{
|
51 |
+
return $this->options['needs_context'];
|
52 |
+
}
|
53 |
+
|
54 |
+
public function getSafe(Twig_Node $functionArgs)
|
55 |
+
{
|
56 |
+
if (isset($this->options['is_safe'])) {
|
57 |
+
return $this->options['is_safe'];
|
58 |
+
}
|
59 |
+
|
60 |
+
if (isset($this->options['is_safe_callback'])) {
|
61 |
+
return call_user_func($this->options['is_safe_callback'], $functionArgs);
|
62 |
+
}
|
63 |
+
|
64 |
+
return array();
|
65 |
+
}
|
66 |
+
|
67 |
+
public function getCallable()
|
68 |
+
{
|
69 |
+
return $this->options['callable'];
|
70 |
+
}
|
71 |
+
}
|
classes/Twig/Function/Function.php
CHANGED
@@ -1,38 +1,38 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2009 Fabien Potencier
|
7 |
-
* (c) 2010 Arnaud Le Blanc
|
8 |
-
*
|
9 |
-
* For the full copyright and license information, please view the LICENSE
|
10 |
-
* file that was distributed with this source code.
|
11 |
-
*/
|
12 |
-
|
13 |
-
/**
|
14 |
-
* Represents a function template function.
|
15 |
-
*
|
16 |
-
* Use Twig_SimpleFunction instead.
|
17 |
-
*
|
18 |
-
* @author Arnaud Le Blanc <arnaud.lb@gmail.com>
|
19 |
-
* @deprecated since 1.12 (to be removed in 2.0)
|
20 |
-
*/
|
21 |
-
class Twig_Function_Function extends Twig_Function
|
22 |
-
{
|
23 |
-
protected $function;
|
24 |
-
|
25 |
-
public function __construct($function, array $options = array())
|
26 |
-
{
|
27 |
-
$options['callable'] = $function;
|
28 |
-
|
29 |
-
parent::__construct($options);
|
30 |
-
|
31 |
-
$this->function = $function;
|
32 |
-
}
|
33 |
-
|
34 |
-
public function compile()
|
35 |
-
{
|
36 |
-
return $this->function;
|
37 |
-
}
|
38 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2009 Fabien Potencier
|
7 |
+
* (c) 2010 Arnaud Le Blanc
|
8 |
+
*
|
9 |
+
* For the full copyright and license information, please view the LICENSE
|
10 |
+
* file that was distributed with this source code.
|
11 |
+
*/
|
12 |
+
|
13 |
+
/**
|
14 |
+
* Represents a function template function.
|
15 |
+
*
|
16 |
+
* Use Twig_SimpleFunction instead.
|
17 |
+
*
|
18 |
+
* @author Arnaud Le Blanc <arnaud.lb@gmail.com>
|
19 |
+
* @deprecated since 1.12 (to be removed in 2.0)
|
20 |
+
*/
|
21 |
+
class Twig_Function_Function extends Twig_Function
|
22 |
+
{
|
23 |
+
protected $function;
|
24 |
+
|
25 |
+
public function __construct($function, array $options = array())
|
26 |
+
{
|
27 |
+
$options['callable'] = $function;
|
28 |
+
|
29 |
+
parent::__construct($options);
|
30 |
+
|
31 |
+
$this->function = $function;
|
32 |
+
}
|
33 |
+
|
34 |
+
public function compile()
|
35 |
+
{
|
36 |
+
return $this->function;
|
37 |
+
}
|
38 |
+
}
|
classes/Twig/Function/Method.php
CHANGED
@@ -1,40 +1,40 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2009 Fabien Potencier
|
7 |
-
* (c) 2010 Arnaud Le Blanc
|
8 |
-
*
|
9 |
-
* For the full copyright and license information, please view the LICENSE
|
10 |
-
* file that was distributed with this source code.
|
11 |
-
*/
|
12 |
-
|
13 |
-
/**
|
14 |
-
* Represents a method template function.
|
15 |
-
*
|
16 |
-
* Use Twig_SimpleFunction instead.
|
17 |
-
*
|
18 |
-
* @author Arnaud Le Blanc <arnaud.lb@gmail.com>
|
19 |
-
* @deprecated since 1.12 (to be removed in 2.0)
|
20 |
-
*/
|
21 |
-
class Twig_Function_Method extends Twig_Function
|
22 |
-
{
|
23 |
-
protected $extension;
|
24 |
-
protected $method;
|
25 |
-
|
26 |
-
public function __construct(Twig_ExtensionInterface $extension, $method, array $options = array())
|
27 |
-
{
|
28 |
-
$options['callable'] = array($extension, $method);
|
29 |
-
|
30 |
-
parent::__construct($options);
|
31 |
-
|
32 |
-
$this->extension = $extension;
|
33 |
-
$this->method = $method;
|
34 |
-
}
|
35 |
-
|
36 |
-
public function compile()
|
37 |
-
{
|
38 |
-
return sprintf('$this->env->getExtension(\'%s\')->%s', $this->extension->getName(), $this->method);
|
39 |
-
}
|
40 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2009 Fabien Potencier
|
7 |
+
* (c) 2010 Arnaud Le Blanc
|
8 |
+
*
|
9 |
+
* For the full copyright and license information, please view the LICENSE
|
10 |
+
* file that was distributed with this source code.
|
11 |
+
*/
|
12 |
+
|
13 |
+
/**
|
14 |
+
* Represents a method template function.
|
15 |
+
*
|
16 |
+
* Use Twig_SimpleFunction instead.
|
17 |
+
*
|
18 |
+
* @author Arnaud Le Blanc <arnaud.lb@gmail.com>
|
19 |
+
* @deprecated since 1.12 (to be removed in 2.0)
|
20 |
+
*/
|
21 |
+
class Twig_Function_Method extends Twig_Function
|
22 |
+
{
|
23 |
+
protected $extension;
|
24 |
+
protected $method;
|
25 |
+
|
26 |
+
public function __construct(Twig_ExtensionInterface $extension, $method, array $options = array())
|
27 |
+
{
|
28 |
+
$options['callable'] = array($extension, $method);
|
29 |
+
|
30 |
+
parent::__construct($options);
|
31 |
+
|
32 |
+
$this->extension = $extension;
|
33 |
+
$this->method = $method;
|
34 |
+
}
|
35 |
+
|
36 |
+
public function compile()
|
37 |
+
{
|
38 |
+
return sprintf('$this->env->getExtension(\'%s\')->%s', $this->extension->getName(), $this->method);
|
39 |
+
}
|
40 |
+
}
|
classes/Twig/Function/Node.php
CHANGED
@@ -1,39 +1,39 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2011 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
/**
|
13 |
-
* Represents a template function as a node.
|
14 |
-
*
|
15 |
-
* Use Twig_SimpleFunction instead.
|
16 |
-
*
|
17 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
18 |
-
* @deprecated since 1.12 (to be removed in 2.0)
|
19 |
-
*/
|
20 |
-
class Twig_Function_Node extends Twig_Function
|
21 |
-
{
|
22 |
-
protected $class;
|
23 |
-
|
24 |
-
public function __construct($class, array $options = array())
|
25 |
-
{
|
26 |
-
parent::__construct($options);
|
27 |
-
|
28 |
-
$this->class = $class;
|
29 |
-
}
|
30 |
-
|
31 |
-
public function getClass()
|
32 |
-
{
|
33 |
-
return $this->class;
|
34 |
-
}
|
35 |
-
|
36 |
-
public function compile()
|
37 |
-
{
|
38 |
-
}
|
39 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2011 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Represents a template function as a node.
|
14 |
+
*
|
15 |
+
* Use Twig_SimpleFunction instead.
|
16 |
+
*
|
17 |
+
* @author Fabien Potencier <fabien@symfony.com>
|
18 |
+
* @deprecated since 1.12 (to be removed in 2.0)
|
19 |
+
*/
|
20 |
+
class Twig_Function_Node extends Twig_Function
|
21 |
+
{
|
22 |
+
protected $class;
|
23 |
+
|
24 |
+
public function __construct($class, array $options = array())
|
25 |
+
{
|
26 |
+
parent::__construct($options);
|
27 |
+
|
28 |
+
$this->class = $class;
|
29 |
+
}
|
30 |
+
|
31 |
+
public function getClass()
|
32 |
+
{
|
33 |
+
return $this->class;
|
34 |
+
}
|
35 |
+
|
36 |
+
public function compile()
|
37 |
+
{
|
38 |
+
}
|
39 |
+
}
|
classes/Twig/FunctionCallableInterface.php
CHANGED
@@ -1,23 +1,23 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2012 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
/**
|
13 |
-
* Represents a callable template function.
|
14 |
-
*
|
15 |
-
* Use Twig_SimpleFunction instead.
|
16 |
-
*
|
17 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
18 |
-
* @deprecated since 1.12 (to be removed in 2.0)
|
19 |
-
*/
|
20 |
-
interface Twig_FunctionCallableInterface
|
21 |
-
{
|
22 |
-
public function getCallable();
|
23 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2012 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Represents a callable template function.
|
14 |
+
*
|
15 |
+
* Use Twig_SimpleFunction instead.
|
16 |
+
*
|
17 |
+
* @author Fabien Potencier <fabien@symfony.com>
|
18 |
+
* @deprecated since 1.12 (to be removed in 2.0)
|
19 |
+
*/
|
20 |
+
interface Twig_FunctionCallableInterface
|
21 |
+
{
|
22 |
+
public function getCallable();
|
23 |
+
}
|
classes/Twig/FunctionInterface.php
CHANGED
@@ -1,39 +1,39 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2010 Fabien Potencier
|
7 |
-
* (c) 2010 Arnaud Le Blanc
|
8 |
-
*
|
9 |
-
* For the full copyright and license information, please view the LICENSE
|
10 |
-
* file that was distributed with this source code.
|
11 |
-
*/
|
12 |
-
|
13 |
-
/**
|
14 |
-
* Represents a template function.
|
15 |
-
*
|
16 |
-
* Use Twig_SimpleFunction instead.
|
17 |
-
*
|
18 |
-
* @author Arnaud Le Blanc <arnaud.lb@gmail.com>
|
19 |
-
* @deprecated since 1.12 (to be removed in 2.0)
|
20 |
-
*/
|
21 |
-
interface Twig_FunctionInterface
|
22 |
-
{
|
23 |
-
/**
|
24 |
-
* Compiles a function.
|
25 |
-
*
|
26 |
-
* @return string The PHP code for the function
|
27 |
-
*/
|
28 |
-
public function compile();
|
29 |
-
|
30 |
-
public function needsEnvironment();
|
31 |
-
|
32 |
-
public function needsContext();
|
33 |
-
|
34 |
-
public function getSafe(Twig_Node $filterArgs);
|
35 |
-
|
36 |
-
public function setArguments($arguments);
|
37 |
-
|
38 |
-
public function getArguments();
|
39 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2010 Fabien Potencier
|
7 |
+
* (c) 2010 Arnaud Le Blanc
|
8 |
+
*
|
9 |
+
* For the full copyright and license information, please view the LICENSE
|
10 |
+
* file that was distributed with this source code.
|
11 |
+
*/
|
12 |
+
|
13 |
+
/**
|
14 |
+
* Represents a template function.
|
15 |
+
*
|
16 |
+
* Use Twig_SimpleFunction instead.
|
17 |
+
*
|
18 |
+
* @author Arnaud Le Blanc <arnaud.lb@gmail.com>
|
19 |
+
* @deprecated since 1.12 (to be removed in 2.0)
|
20 |
+
*/
|
21 |
+
interface Twig_FunctionInterface
|
22 |
+
{
|
23 |
+
/**
|
24 |
+
* Compiles a function.
|
25 |
+
*
|
26 |
+
* @return string The PHP code for the function
|
27 |
+
*/
|
28 |
+
public function compile();
|
29 |
+
|
30 |
+
public function needsEnvironment();
|
31 |
+
|
32 |
+
public function needsContext();
|
33 |
+
|
34 |
+
public function getSafe(Twig_Node $filterArgs);
|
35 |
+
|
36 |
+
public function setArguments($arguments);
|
37 |
+
|
38 |
+
public function getArguments();
|
39 |
+
}
|
classes/Twig/Lexer.php
CHANGED
@@ -1,409 +1,409 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2009 Fabien Potencier
|
7 |
-
* (c) 2009 Armin Ronacher
|
8 |
-
*
|
9 |
-
* For the full copyright and license information, please view the LICENSE
|
10 |
-
* file that was distributed with this source code.
|
11 |
-
*/
|
12 |
-
|
13 |
-
/**
|
14 |
-
* Lexes a template string.
|
15 |
-
*
|
16 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
17 |
-
*/
|
18 |
-
class Twig_Lexer implements Twig_LexerInterface
|
19 |
-
{
|
20 |
-
protected $tokens;
|
21 |
-
protected $code;
|
22 |
-
protected $cursor;
|
23 |
-
protected $lineno;
|
24 |
-
protected $end;
|
25 |
-
protected $state;
|
26 |
-
protected $states;
|
27 |
-
protected $brackets;
|
28 |
-
protected $env;
|
29 |
-
protected $filename;
|
30 |
-
protected $options;
|
31 |
-
protected $regexes;
|
32 |
-
protected $position;
|
33 |
-
protected $positions;
|
34 |
-
protected $currentVarBlockLine;
|
35 |
-
|
36 |
-
const STATE_DATA = 0;
|
37 |
-
const STATE_BLOCK = 1;
|
38 |
-
const STATE_VAR = 2;
|
39 |
-
const STATE_STRING = 3;
|
40 |
-
const STATE_INTERPOLATION = 4;
|
41 |
-
|
42 |
-
const REGEX_NAME = '/[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/A';
|
43 |
-
const REGEX_NUMBER = '/[0-9]+(?:\.[0-9]+)?/A';
|
44 |
-
const REGEX_STRING = '/"([^#"\\\\]*(?:\\\\.[^#"\\\\]*)*)"|\'([^\'\\\\]*(?:\\\\.[^\'\\\\]*)*)\'/As';
|
45 |
-
const REGEX_DQ_STRING_DELIM = '/"/A';
|
46 |
-
const REGEX_DQ_STRING_PART = '/[^#"\\\\]*(?:(?:\\\\.|#(?!\{))[^#"\\\\]*)*/As';
|
47 |
-
const PUNCTUATION = '()[]{}?:.,|';
|
48 |
-
|
49 |
-
public function __construct(Twig_Environment $env, array $options = array())
|
50 |
-
{
|
51 |
-
$this->env = $env;
|
52 |
-
|
53 |
-
$this->options = array_merge(array(
|
54 |
-
'tag_comment' => array('{#', '#}'),
|
55 |
-
'tag_block' => array('{%', '%}'),
|
56 |
-
'tag_variable' => array('{{', '}}'),
|
57 |
-
'whitespace_trim' => '-',
|
58 |
-
'interpolation' => array('#{', '}'),
|
59 |
-
), $options);
|
60 |
-
|
61 |
-
$this->regexes = array(
|
62 |
-
'lex_var' => '/\s*'.preg_quote($this->options['whitespace_trim'].$this->options['tag_variable'][1], '/').'\s*|\s*'.preg_quote($this->options['tag_variable'][1], '/').'/A',
|
63 |
-
'lex_block' => '/\s*(?:'.preg_quote($this->options['whitespace_trim'].$this->options['tag_block'][1], '/').'\s*|\s*'.preg_quote($this->options['tag_block'][1], '/').')\n?/A',
|
64 |
-
'lex_raw_data' => '/('.preg_quote($this->options['tag_block'][0].$this->options['whitespace_trim'], '/').'|'.preg_quote($this->options['tag_block'][0], '/').')\s*(?:end%s)\s*(?:'.preg_quote($this->options['whitespace_trim'].$this->options['tag_block'][1], '/').'\s*|\s*'.preg_quote($this->options['tag_block'][1], '/').')/s',
|
65 |
-
'operator' => $this->getOperatorRegex(),
|
66 |
-
'lex_comment' => '/(?:'.preg_quote($this->options['whitespace_trim'], '/').preg_quote($this->options['tag_comment'][1], '/').'\s*|'.preg_quote($this->options['tag_comment'][1], '/').')\n?/s',
|
67 |
-
'lex_block_raw' => '/\s*(raw|verbatim)\s*(?:'.preg_quote($this->options['whitespace_trim'].$this->options['tag_block'][1], '/').'\s*|\s*'.preg_quote($this->options['tag_block'][1], '/').')/As',
|
68 |
-
'lex_block_line' => '/\s*line\s+(\d+)\s*'.preg_quote($this->options['tag_block'][1], '/').'/As',
|
69 |
-
'lex_tokens_start' => '/('.preg_quote($this->options['tag_variable'][0], '/').'|'.preg_quote($this->options['tag_block'][0], '/').'|'.preg_quote($this->options['tag_comment'][0], '/').')('.preg_quote($this->options['whitespace_trim'], '/').')?/s',
|
70 |
-
'interpolation_start' => '/'.preg_quote($this->options['interpolation'][0], '/').'\s*/A',
|
71 |
-
'interpolation_end' => '/\s*'.preg_quote($this->options['interpolation'][1], '/').'/A',
|
72 |
-
);
|
73 |
-
}
|
74 |
-
|
75 |
-
/**
|
76 |
-
* {@inheritdoc}
|
77 |
-
*/
|
78 |
-
public function tokenize($code, $filename = null)
|
79 |
-
{
|
80 |
-
if (function_exists('mb_internal_encoding') && ((int) ini_get('mbstring.func_overload')) & 2) {
|
81 |
-
$mbEncoding = mb_internal_encoding();
|
82 |
-
mb_internal_encoding('ASCII');
|
83 |
-
} else {
|
84 |
-
$mbEncoding = null;
|
85 |
-
}
|
86 |
-
|
87 |
-
$this->code = str_replace(array("\r\n", "\r"), "\n", $code);
|
88 |
-
$this->filename = $filename;
|
89 |
-
$this->cursor = 0;
|
90 |
-
$this->lineno = 1;
|
91 |
-
$this->end = strlen($this->code);
|
92 |
-
$this->tokens = array();
|
93 |
-
$this->state = self::STATE_DATA;
|
94 |
-
$this->states = array();
|
95 |
-
$this->brackets = array();
|
96 |
-
$this->position = -1;
|
97 |
-
|
98 |
-
// find all token starts in one go
|
99 |
-
preg_match_all($this->regexes['lex_tokens_start'], $this->code, $matches, PREG_OFFSET_CAPTURE);
|
100 |
-
$this->positions = $matches;
|
101 |
-
|
102 |
-
while ($this->cursor < $this->end) {
|
103 |
-
// dispatch to the lexing functions depending
|
104 |
-
// on the current state
|
105 |
-
switch ($this->state) {
|
106 |
-
case self::STATE_DATA:
|
107 |
-
$this->lexData();
|
108 |
-
break;
|
109 |
-
|
110 |
-
case self::STATE_BLOCK:
|
111 |
-
$this->lexBlock();
|
112 |
-
break;
|
113 |
-
|
114 |
-
case self::STATE_VAR:
|
115 |
-
$this->lexVar();
|
116 |
-
break;
|
117 |
-
|
118 |
-
case self::STATE_STRING:
|
119 |
-
$this->lexString();
|
120 |
-
break;
|
121 |
-
|
122 |
-
case self::STATE_INTERPOLATION:
|
123 |
-
$this->lexInterpolation();
|
124 |
-
break;
|
125 |
-
}
|
126 |
-
}
|
127 |
-
|
128 |
-
$this->pushToken(Twig_Token::EOF_TYPE);
|
129 |
-
|
130 |
-
if (!empty($this->brackets)) {
|
131 |
-
list($expect, $lineno) = array_pop($this->brackets);
|
132 |
-
throw new Twig_Error_Syntax(sprintf('Unclosed "%s"', $expect), $lineno, $this->filename);
|
133 |
-
}
|
134 |
-
|
135 |
-
if ($mbEncoding) {
|
136 |
-
mb_internal_encoding($mbEncoding);
|
137 |
-
}
|
138 |
-
|
139 |
-
return new Twig_TokenStream($this->tokens, $this->filename);
|
140 |
-
}
|
141 |
-
|
142 |
-
protected function lexData()
|
143 |
-
{
|
144 |
-
// if no matches are left we return the rest of the template as simple text token
|
145 |
-
if ($this->position == count($this->positions[0]) - 1) {
|
146 |
-
$this->pushToken(Twig_Token::TEXT_TYPE, substr($this->code, $this->cursor));
|
147 |
-
$this->cursor = $this->end;
|
148 |
-
|
149 |
-
return;
|
150 |
-
}
|
151 |
-
|
152 |
-
// Find the first token after the current cursor
|
153 |
-
$position = $this->positions[0][++$this->position];
|
154 |
-
while ($position[1] < $this->cursor) {
|
155 |
-
if ($this->position == count($this->positions[0]) - 1) {
|
156 |
-
return;
|
157 |
-
}
|
158 |
-
$position = $this->positions[0][++$this->position];
|
159 |
-
}
|
160 |
-
|
161 |
-
// push the template text first
|
162 |
-
$text = $textContent = substr($this->code, $this->cursor, $position[1] - $this->cursor);
|
163 |
-
if (isset($this->positions[2][$this->position][0])) {
|
164 |
-
$text = rtrim($text);
|
165 |
-
}
|
166 |
-
$this->pushToken(Twig_Token::TEXT_TYPE, $text);
|
167 |
-
$this->moveCursor($textContent.$position[0]);
|
168 |
-
|
169 |
-
switch ($this->positions[1][$this->position][0]) {
|
170 |
-
case $this->options['tag_comment'][0]:
|
171 |
-
$this->lexComment();
|
172 |
-
break;
|
173 |
-
|
174 |
-
case $this->options['tag_block'][0]:
|
175 |
-
// raw data?
|
176 |
-
if (preg_match($this->regexes['lex_block_raw'], $this->code, $match, null, $this->cursor)) {
|
177 |
-
$this->moveCursor($match[0]);
|
178 |
-
$this->lexRawData($match[1]);
|
179 |
-
// {% line \d+ %}
|
180 |
-
} elseif (preg_match($this->regexes['lex_block_line'], $this->code, $match, null, $this->cursor)) {
|
181 |
-
$this->moveCursor($match[0]);
|
182 |
-
$this->lineno = (int) $match[1];
|
183 |
-
} else {
|
184 |
-
$this->pushToken(Twig_Token::BLOCK_START_TYPE);
|
185 |
-
$this->pushState(self::STATE_BLOCK);
|
186 |
-
$this->currentVarBlockLine = $this->lineno;
|
187 |
-
}
|
188 |
-
break;
|
189 |
-
|
190 |
-
case $this->options['tag_variable'][0]:
|
191 |
-
$this->pushToken(Twig_Token::VAR_START_TYPE);
|
192 |
-
$this->pushState(self::STATE_VAR);
|
193 |
-
$this->currentVarBlockLine = $this->lineno;
|
194 |
-
break;
|
195 |
-
}
|
196 |
-
}
|
197 |
-
|
198 |
-
protected function lexBlock()
|
199 |
-
{
|
200 |
-
if (empty($this->brackets) && preg_match($this->regexes['lex_block'], $this->code, $match, null, $this->cursor)) {
|
201 |
-
$this->pushToken(Twig_Token::BLOCK_END_TYPE);
|
202 |
-
$this->moveCursor($match[0]);
|
203 |
-
$this->popState();
|
204 |
-
} else {
|
205 |
-
$this->lexExpression();
|
206 |
-
}
|
207 |
-
}
|
208 |
-
|
209 |
-
protected function lexVar()
|
210 |
-
{
|
211 |
-
if (empty($this->brackets) && preg_match($this->regexes['lex_var'], $this->code, $match, null, $this->cursor)) {
|
212 |
-
$this->pushToken(Twig_Token::VAR_END_TYPE);
|
213 |
-
$this->moveCursor($match[0]);
|
214 |
-
$this->popState();
|
215 |
-
} else {
|
216 |
-
$this->lexExpression();
|
217 |
-
}
|
218 |
-
}
|
219 |
-
|
220 |
-
protected function lexExpression()
|
221 |
-
{
|
222 |
-
// whitespace
|
223 |
-
if (preg_match('/\s+/A', $this->code, $match, null, $this->cursor)) {
|
224 |
-
$this->moveCursor($match[0]);
|
225 |
-
|
226 |
-
if ($this->cursor >= $this->end) {
|
227 |
-
throw new Twig_Error_Syntax(sprintf('Unclosed "%s"', $this->state === self::STATE_BLOCK ? 'block' : 'variable'), $this->currentVarBlockLine, $this->filename);
|
228 |
-
}
|
229 |
-
}
|
230 |
-
|
231 |
-
// operators
|
232 |
-
if (preg_match($this->regexes['operator'], $this->code, $match, null, $this->cursor)) {
|
233 |
-
$this->pushToken(Twig_Token::OPERATOR_TYPE, preg_replace('/\s+/', ' ', $match[0]));
|
234 |
-
$this->moveCursor($match[0]);
|
235 |
-
}
|
236 |
-
// names
|
237 |
-
elseif (preg_match(self::REGEX_NAME, $this->code, $match, null, $this->cursor)) {
|
238 |
-
$this->pushToken(Twig_Token::NAME_TYPE, $match[0]);
|
239 |
-
$this->moveCursor($match[0]);
|
240 |
-
}
|
241 |
-
// numbers
|
242 |
-
elseif (preg_match(self::REGEX_NUMBER, $this->code, $match, null, $this->cursor)) {
|
243 |
-
$number = (float) $match[0]; // floats
|
244 |
-
if (ctype_digit($match[0]) && $number <= PHP_INT_MAX) {
|
245 |
-
$number = (int) $match[0]; // integers lower than the maximum
|
246 |
-
}
|
247 |
-
$this->pushToken(Twig_Token::NUMBER_TYPE, $number);
|
248 |
-
$this->moveCursor($match[0]);
|
249 |
-
}
|
250 |
-
// punctuation
|
251 |
-
elseif (false !== strpos(self::PUNCTUATION, $this->code[$this->cursor])) {
|
252 |
-
// opening bracket
|
253 |
-
if (false !== strpos('([{', $this->code[$this->cursor])) {
|
254 |
-
$this->brackets[] = array($this->code[$this->cursor], $this->lineno);
|
255 |
-
}
|
256 |
-
// closing bracket
|
257 |
-
elseif (false !== strpos(')]}', $this->code[$this->cursor])) {
|
258 |
-
if (empty($this->brackets)) {
|
259 |
-
throw new Twig_Error_Syntax(sprintf('Unexpected "%s"', $this->code[$this->cursor]), $this->lineno, $this->filename);
|
260 |
-
}
|
261 |
-
|
262 |
-
list($expect, $lineno) = array_pop($this->brackets);
|
263 |
-
if ($this->code[$this->cursor] != strtr($expect, '([{', ')]}')) {
|
264 |
-
throw new Twig_Error_Syntax(sprintf('Unclosed "%s"', $expect), $lineno, $this->filename);
|
265 |
-
}
|
266 |
-
}
|
267 |
-
|
268 |
-
$this->pushToken(Twig_Token::PUNCTUATION_TYPE, $this->code[$this->cursor]);
|
269 |
-
++$this->cursor;
|
270 |
-
}
|
271 |
-
// strings
|
272 |
-
elseif (preg_match(self::REGEX_STRING, $this->code, $match, null, $this->cursor)) {
|
273 |
-
$this->pushToken(Twig_Token::STRING_TYPE, stripcslashes(substr($match[0], 1, -1)));
|
274 |
-
$this->moveCursor($match[0]);
|
275 |
-
}
|
276 |
-
// opening double quoted string
|
277 |
-
elseif (preg_match(self::REGEX_DQ_STRING_DELIM, $this->code, $match, null, $this->cursor)) {
|
278 |
-
$this->brackets[] = array('"', $this->lineno);
|
279 |
-
$this->pushState(self::STATE_STRING);
|
280 |
-
$this->moveCursor($match[0]);
|
281 |
-
}
|
282 |
-
// unlexable
|
283 |
-
else {
|
284 |
-
throw new Twig_Error_Syntax(sprintf('Unexpected character "%s"', $this->code[$this->cursor]), $this->lineno, $this->filename);
|
285 |
-
}
|
286 |
-
}
|
287 |
-
|
288 |
-
protected function lexRawData($tag)
|
289 |
-
{
|
290 |
-
if (!preg_match(str_replace('%s', $tag, $this->regexes['lex_raw_data']), $this->code, $match, PREG_OFFSET_CAPTURE, $this->cursor)) {
|
291 |
-
throw new Twig_Error_Syntax(sprintf('Unexpected end of file: Unclosed "%s" block', $tag), $this->lineno, $this->filename);
|
292 |
-
}
|
293 |
-
|
294 |
-
$text = substr($this->code, $this->cursor, $match[0][1] - $this->cursor);
|
295 |
-
$this->moveCursor($text.$match[0][0]);
|
296 |
-
|
297 |
-
if (false !== strpos($match[1][0], $this->options['whitespace_trim'])) {
|
298 |
-
$text = rtrim($text);
|
299 |
-
}
|
300 |
-
|
301 |
-
$this->pushToken(Twig_Token::TEXT_TYPE, $text);
|
302 |
-
}
|
303 |
-
|
304 |
-
protected function lexComment()
|
305 |
-
{
|
306 |
-
if (!preg_match($this->regexes['lex_comment'], $this->code, $match, PREG_OFFSET_CAPTURE, $this->cursor)) {
|
307 |
-
throw new Twig_Error_Syntax('Unclosed comment', $this->lineno, $this->filename);
|
308 |
-
}
|
309 |
-
|
310 |
-
$this->moveCursor(substr($this->code, $this->cursor, $match[0][1] - $this->cursor).$match[0][0]);
|
311 |
-
}
|
312 |
-
|
313 |
-
protected function lexString()
|
314 |
-
{
|
315 |
-
if (preg_match($this->regexes['interpolation_start'], $this->code, $match, null, $this->cursor)) {
|
316 |
-
$this->brackets[] = array($this->options['interpolation'][0], $this->lineno);
|
317 |
-
$this->pushToken(Twig_Token::INTERPOLATION_START_TYPE);
|
318 |
-
$this->moveCursor($match[0]);
|
319 |
-
$this->pushState(self::STATE_INTERPOLATION);
|
320 |
-
|
321 |
-
} elseif (preg_match(self::REGEX_DQ_STRING_PART, $this->code, $match, null, $this->cursor) && strlen($match[0]) > 0) {
|
322 |
-
$this->pushToken(Twig_Token::STRING_TYPE, stripcslashes($match[0]));
|
323 |
-
$this->moveCursor($match[0]);
|
324 |
-
|
325 |
-
} elseif (preg_match(self::REGEX_DQ_STRING_DELIM, $this->code, $match, null, $this->cursor)) {
|
326 |
-
list($expect, $lineno) = array_pop($this->brackets);
|
327 |
-
if ($this->code[$this->cursor] != '"') {
|
328 |
-
throw new Twig_Error_Syntax(sprintf('Unclosed "%s"', $expect), $lineno, $this->filename);
|
329 |
-
}
|
330 |
-
|
331 |
-
$this->popState();
|
332 |
-
++$this->cursor;
|
333 |
-
}
|
334 |
-
}
|
335 |
-
|
336 |
-
protected function lexInterpolation()
|
337 |
-
{
|
338 |
-
$bracket = end($this->brackets);
|
339 |
-
if ($this->options['interpolation'][0] === $bracket[0] && preg_match($this->regexes['interpolation_end'], $this->code, $match, null, $this->cursor)) {
|
340 |
-
array_pop($this->brackets);
|
341 |
-
$this->pushToken(Twig_Token::INTERPOLATION_END_TYPE);
|
342 |
-
$this->moveCursor($match[0]);
|
343 |
-
$this->popState();
|
344 |
-
} else {
|
345 |
-
$this->lexExpression();
|
346 |
-
}
|
347 |
-
}
|
348 |
-
|
349 |
-
protected function pushToken($type, $value = '')
|
350 |
-
{
|
351 |
-
// do not push empty text tokens
|
352 |
-
if (Twig_Token::TEXT_TYPE === $type && '' === $value) {
|
353 |
-
return;
|
354 |
-
}
|
355 |
-
|
356 |
-
$this->tokens[] = new Twig_Token($type, $value, $this->lineno);
|
357 |
-
}
|
358 |
-
|
359 |
-
protected function moveCursor($text)
|
360 |
-
{
|
361 |
-
$this->cursor += strlen($text);
|
362 |
-
$this->lineno += substr_count($text, "\n");
|
363 |
-
}
|
364 |
-
|
365 |
-
protected function getOperatorRegex()
|
366 |
-
{
|
367 |
-
$operators = array_merge(
|
368 |
-
array('='),
|
369 |
-
array_keys($this->env->getUnaryOperators()),
|
370 |
-
array_keys($this->env->getBinaryOperators())
|
371 |
-
);
|
372 |
-
|
373 |
-
$operators = array_combine($operators, array_map('strlen', $operators));
|
374 |
-
arsort($operators);
|
375 |
-
|
376 |
-
$regex = array();
|
377 |
-
foreach ($operators as $operator => $length) {
|
378 |
-
// an operator that ends with a character must be followed by
|
379 |
-
// a whitespace or a parenthesis
|
380 |
-
if (ctype_alpha($operator[$length - 1])) {
|
381 |
-
$r = preg_quote($operator, '/').'(?=[\s()])';
|
382 |
-
} else {
|
383 |
-
$r = preg_quote($operator, '/');
|
384 |
-
}
|
385 |
-
|
386 |
-
// an operator with a space can be any amount of whitespaces
|
387 |
-
$r = preg_replace('/\s+/', '\s+', $r);
|
388 |
-
|
389 |
-
$regex[] = $r;
|
390 |
-
}
|
391 |
-
|
392 |
-
return '/'.implode('|', $regex).'/A';
|
393 |
-
}
|
394 |
-
|
395 |
-
protected function pushState($state)
|
396 |
-
{
|
397 |
-
$this->states[] = $this->state;
|
398 |
-
$this->state = $state;
|
399 |
-
}
|
400 |
-
|
401 |
-
protected function popState()
|
402 |
-
{
|
403 |
-
if (0 === count($this->states)) {
|
404 |
-
throw new Exception('Cannot pop state without a previous state');
|
405 |
-
}
|
406 |
-
|
407 |
-
$this->state = array_pop($this->states);
|
408 |
-
}
|
409 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2009 Fabien Potencier
|
7 |
+
* (c) 2009 Armin Ronacher
|
8 |
+
*
|
9 |
+
* For the full copyright and license information, please view the LICENSE
|
10 |
+
* file that was distributed with this source code.
|
11 |
+
*/
|
12 |
+
|
13 |
+
/**
|
14 |
+
* Lexes a template string.
|
15 |
+
*
|
16 |
+
* @author Fabien Potencier <fabien@symfony.com>
|
17 |
+
*/
|
18 |
+
class Twig_Lexer implements Twig_LexerInterface
|
19 |
+
{
|
20 |
+
protected $tokens;
|
21 |
+
protected $code;
|
22 |
+
protected $cursor;
|
23 |
+
protected $lineno;
|
24 |
+
protected $end;
|
25 |
+
protected $state;
|
26 |
+
protected $states;
|
27 |
+
protected $brackets;
|
28 |
+
protected $env;
|
29 |
+
protected $filename;
|
30 |
+
protected $options;
|
31 |
+
protected $regexes;
|
32 |
+
protected $position;
|
33 |
+
protected $positions;
|
34 |
+
protected $currentVarBlockLine;
|
35 |
+
|
36 |
+
const STATE_DATA = 0;
|
37 |
+
const STATE_BLOCK = 1;
|
38 |
+
const STATE_VAR = 2;
|
39 |
+
const STATE_STRING = 3;
|
40 |
+
const STATE_INTERPOLATION = 4;
|
41 |
+
|
42 |
+
const REGEX_NAME = '/[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/A';
|
43 |
+
const REGEX_NUMBER = '/[0-9]+(?:\.[0-9]+)?/A';
|
44 |
+
const REGEX_STRING = '/"([^#"\\\\]*(?:\\\\.[^#"\\\\]*)*)"|\'([^\'\\\\]*(?:\\\\.[^\'\\\\]*)*)\'/As';
|
45 |
+
const REGEX_DQ_STRING_DELIM = '/"/A';
|
46 |
+
const REGEX_DQ_STRING_PART = '/[^#"\\\\]*(?:(?:\\\\.|#(?!\{))[^#"\\\\]*)*/As';
|
47 |
+
const PUNCTUATION = '()[]{}?:.,|';
|
48 |
+
|
49 |
+
public function __construct(Twig_Environment $env, array $options = array())
|
50 |
+
{
|
51 |
+
$this->env = $env;
|
52 |
+
|
53 |
+
$this->options = array_merge(array(
|
54 |
+
'tag_comment' => array('{#', '#}'),
|
55 |
+
'tag_block' => array('{%', '%}'),
|
56 |
+
'tag_variable' => array('{{', '}}'),
|
57 |
+
'whitespace_trim' => '-',
|
58 |
+
'interpolation' => array('#{', '}'),
|
59 |
+
), $options);
|
60 |
+
|
61 |
+
$this->regexes = array(
|
62 |
+
'lex_var' => '/\s*'.preg_quote($this->options['whitespace_trim'].$this->options['tag_variable'][1], '/').'\s*|\s*'.preg_quote($this->options['tag_variable'][1], '/').'/A',
|
63 |
+
'lex_block' => '/\s*(?:'.preg_quote($this->options['whitespace_trim'].$this->options['tag_block'][1], '/').'\s*|\s*'.preg_quote($this->options['tag_block'][1], '/').')\n?/A',
|
64 |
+
'lex_raw_data' => '/('.preg_quote($this->options['tag_block'][0].$this->options['whitespace_trim'], '/').'|'.preg_quote($this->options['tag_block'][0], '/').')\s*(?:end%s)\s*(?:'.preg_quote($this->options['whitespace_trim'].$this->options['tag_block'][1], '/').'\s*|\s*'.preg_quote($this->options['tag_block'][1], '/').')/s',
|
65 |
+
'operator' => $this->getOperatorRegex(),
|
66 |
+
'lex_comment' => '/(?:'.preg_quote($this->options['whitespace_trim'], '/').preg_quote($this->options['tag_comment'][1], '/').'\s*|'.preg_quote($this->options['tag_comment'][1], '/').')\n?/s',
|
67 |
+
'lex_block_raw' => '/\s*(raw|verbatim)\s*(?:'.preg_quote($this->options['whitespace_trim'].$this->options['tag_block'][1], '/').'\s*|\s*'.preg_quote($this->options['tag_block'][1], '/').')/As',
|
68 |
+
'lex_block_line' => '/\s*line\s+(\d+)\s*'.preg_quote($this->options['tag_block'][1], '/').'/As',
|
69 |
+
'lex_tokens_start' => '/('.preg_quote($this->options['tag_variable'][0], '/').'|'.preg_quote($this->options['tag_block'][0], '/').'|'.preg_quote($this->options['tag_comment'][0], '/').')('.preg_quote($this->options['whitespace_trim'], '/').')?/s',
|
70 |
+
'interpolation_start' => '/'.preg_quote($this->options['interpolation'][0], '/').'\s*/A',
|
71 |
+
'interpolation_end' => '/\s*'.preg_quote($this->options['interpolation'][1], '/').'/A',
|
72 |
+
);
|
73 |
+
}
|
74 |
+
|
75 |
+
/**
|
76 |
+
* {@inheritdoc}
|
77 |
+
*/
|
78 |
+
public function tokenize($code, $filename = null)
|
79 |
+
{
|
80 |
+
if (function_exists('mb_internal_encoding') && ((int) ini_get('mbstring.func_overload')) & 2) {
|
81 |
+
$mbEncoding = mb_internal_encoding();
|
82 |
+
mb_internal_encoding('ASCII');
|
83 |
+
} else {
|
84 |
+
$mbEncoding = null;
|
85 |
+
}
|
86 |
+
|
87 |
+
$this->code = str_replace(array("\r\n", "\r"), "\n", $code);
|
88 |
+
$this->filename = $filename;
|
89 |
+
$this->cursor = 0;
|
90 |
+
$this->lineno = 1;
|
91 |
+
$this->end = strlen($this->code);
|
92 |
+
$this->tokens = array();
|
93 |
+
$this->state = self::STATE_DATA;
|
94 |
+
$this->states = array();
|
95 |
+
$this->brackets = array();
|
96 |
+
$this->position = -1;
|
97 |
+
|
98 |
+
// find all token starts in one go
|
99 |
+
preg_match_all($this->regexes['lex_tokens_start'], $this->code, $matches, PREG_OFFSET_CAPTURE);
|
100 |
+
$this->positions = $matches;
|
101 |
+
|
102 |
+
while ($this->cursor < $this->end) {
|
103 |
+
// dispatch to the lexing functions depending
|
104 |
+
// on the current state
|
105 |
+
switch ($this->state) {
|
106 |
+
case self::STATE_DATA:
|
107 |
+
$this->lexData();
|
108 |
+
break;
|
109 |
+
|
110 |
+
case self::STATE_BLOCK:
|
111 |
+
$this->lexBlock();
|
112 |
+
break;
|
113 |
+
|
114 |
+
case self::STATE_VAR:
|
115 |
+
$this->lexVar();
|
116 |
+
break;
|
117 |
+
|
118 |
+
case self::STATE_STRING:
|
119 |
+
$this->lexString();
|
120 |
+
break;
|
121 |
+
|
122 |
+
case self::STATE_INTERPOLATION:
|
123 |
+
$this->lexInterpolation();
|
124 |
+
break;
|
125 |
+
}
|
126 |
+
}
|
127 |
+
|
128 |
+
$this->pushToken(Twig_Token::EOF_TYPE);
|
129 |
+
|
130 |
+
if (!empty($this->brackets)) {
|
131 |
+
list($expect, $lineno) = array_pop($this->brackets);
|
132 |
+
throw new Twig_Error_Syntax(sprintf('Unclosed "%s"', $expect), $lineno, $this->filename);
|
133 |
+
}
|
134 |
+
|
135 |
+
if ($mbEncoding) {
|
136 |
+
mb_internal_encoding($mbEncoding);
|
137 |
+
}
|
138 |
+
|
139 |
+
return new Twig_TokenStream($this->tokens, $this->filename);
|
140 |
+
}
|
141 |
+
|
142 |
+
protected function lexData()
|
143 |
+
{
|
144 |
+
// if no matches are left we return the rest of the template as simple text token
|
145 |
+
if ($this->position == count($this->positions[0]) - 1) {
|
146 |
+
$this->pushToken(Twig_Token::TEXT_TYPE, substr($this->code, $this->cursor));
|
147 |
+
$this->cursor = $this->end;
|
148 |
+
|
149 |
+
return;
|
150 |
+
}
|
151 |
+
|
152 |
+
// Find the first token after the current cursor
|
153 |
+
$position = $this->positions[0][++$this->position];
|
154 |
+
while ($position[1] < $this->cursor) {
|
155 |
+
if ($this->position == count($this->positions[0]) - 1) {
|
156 |
+
return;
|
157 |
+
}
|
158 |
+
$position = $this->positions[0][++$this->position];
|
159 |
+
}
|
160 |
+
|
161 |
+
// push the template text first
|
162 |
+
$text = $textContent = substr($this->code, $this->cursor, $position[1] - $this->cursor);
|
163 |
+
if (isset($this->positions[2][$this->position][0])) {
|
164 |
+
$text = rtrim($text);
|
165 |
+
}
|
166 |
+
$this->pushToken(Twig_Token::TEXT_TYPE, $text);
|
167 |
+
$this->moveCursor($textContent.$position[0]);
|
168 |
+
|
169 |
+
switch ($this->positions[1][$this->position][0]) {
|
170 |
+
case $this->options['tag_comment'][0]:
|
171 |
+
$this->lexComment();
|
172 |
+
break;
|
173 |
+
|
174 |
+
case $this->options['tag_block'][0]:
|
175 |
+
// raw data?
|
176 |
+
if (preg_match($this->regexes['lex_block_raw'], $this->code, $match, null, $this->cursor)) {
|
177 |
+
$this->moveCursor($match[0]);
|
178 |
+
$this->lexRawData($match[1]);
|
179 |
+
// {% line \d+ %}
|
180 |
+
} elseif (preg_match($this->regexes['lex_block_line'], $this->code, $match, null, $this->cursor)) {
|
181 |
+
$this->moveCursor($match[0]);
|
182 |
+
$this->lineno = (int) $match[1];
|
183 |
+
} else {
|
184 |
+
$this->pushToken(Twig_Token::BLOCK_START_TYPE);
|
185 |
+
$this->pushState(self::STATE_BLOCK);
|
186 |
+
$this->currentVarBlockLine = $this->lineno;
|
187 |
+
}
|
188 |
+
break;
|
189 |
+
|
190 |
+
case $this->options['tag_variable'][0]:
|
191 |
+
$this->pushToken(Twig_Token::VAR_START_TYPE);
|
192 |
+
$this->pushState(self::STATE_VAR);
|
193 |
+
$this->currentVarBlockLine = $this->lineno;
|
194 |
+
break;
|
195 |
+
}
|
196 |
+
}
|
197 |
+
|
198 |
+
protected function lexBlock()
|
199 |
+
{
|
200 |
+
if (empty($this->brackets) && preg_match($this->regexes['lex_block'], $this->code, $match, null, $this->cursor)) {
|
201 |
+
$this->pushToken(Twig_Token::BLOCK_END_TYPE);
|
202 |
+
$this->moveCursor($match[0]);
|
203 |
+
$this->popState();
|
204 |
+
} else {
|
205 |
+
$this->lexExpression();
|
206 |
+
}
|
207 |
+
}
|
208 |
+
|
209 |
+
protected function lexVar()
|
210 |
+
{
|
211 |
+
if (empty($this->brackets) && preg_match($this->regexes['lex_var'], $this->code, $match, null, $this->cursor)) {
|
212 |
+
$this->pushToken(Twig_Token::VAR_END_TYPE);
|
213 |
+
$this->moveCursor($match[0]);
|
214 |
+
$this->popState();
|
215 |
+
} else {
|
216 |
+
$this->lexExpression();
|
217 |
+
}
|
218 |
+
}
|
219 |
+
|
220 |
+
protected function lexExpression()
|
221 |
+
{
|
222 |
+
// whitespace
|
223 |
+
if (preg_match('/\s+/A', $this->code, $match, null, $this->cursor)) {
|
224 |
+
$this->moveCursor($match[0]);
|
225 |
+
|
226 |
+
if ($this->cursor >= $this->end) {
|
227 |
+
throw new Twig_Error_Syntax(sprintf('Unclosed "%s"', $this->state === self::STATE_BLOCK ? 'block' : 'variable'), $this->currentVarBlockLine, $this->filename);
|
228 |
+
}
|
229 |
+
}
|
230 |
+
|
231 |
+
// operators
|
232 |
+
if (preg_match($this->regexes['operator'], $this->code, $match, null, $this->cursor)) {
|
233 |
+
$this->pushToken(Twig_Token::OPERATOR_TYPE, preg_replace('/\s+/', ' ', $match[0]));
|
234 |
+
$this->moveCursor($match[0]);
|
235 |
+
}
|
236 |
+
// names
|
237 |
+
elseif (preg_match(self::REGEX_NAME, $this->code, $match, null, $this->cursor)) {
|
238 |
+
$this->pushToken(Twig_Token::NAME_TYPE, $match[0]);
|
239 |
+
$this->moveCursor($match[0]);
|
240 |
+
}
|
241 |
+
// numbers
|
242 |
+
elseif (preg_match(self::REGEX_NUMBER, $this->code, $match, null, $this->cursor)) {
|
243 |
+
$number = (float) $match[0]; // floats
|
244 |
+
if (ctype_digit($match[0]) && $number <= PHP_INT_MAX) {
|
245 |
+
$number = (int) $match[0]; // integers lower than the maximum
|
246 |
+
}
|
247 |
+
$this->pushToken(Twig_Token::NUMBER_TYPE, $number);
|
248 |
+
$this->moveCursor($match[0]);
|
249 |
+
}
|
250 |
+
// punctuation
|
251 |
+
elseif (false !== strpos(self::PUNCTUATION, $this->code[$this->cursor])) {
|
252 |
+
// opening bracket
|
253 |
+
if (false !== strpos('([{', $this->code[$this->cursor])) {
|
254 |
+
$this->brackets[] = array($this->code[$this->cursor], $this->lineno);
|
255 |
+
}
|
256 |
+
// closing bracket
|
257 |
+
elseif (false !== strpos(')]}', $this->code[$this->cursor])) {
|
258 |
+
if (empty($this->brackets)) {
|
259 |
+
throw new Twig_Error_Syntax(sprintf('Unexpected "%s"', $this->code[$this->cursor]), $this->lineno, $this->filename);
|
260 |
+
}
|
261 |
+
|
262 |
+
list($expect, $lineno) = array_pop($this->brackets);
|
263 |
+
if ($this->code[$this->cursor] != strtr($expect, '([{', ')]}')) {
|
264 |
+
throw new Twig_Error_Syntax(sprintf('Unclosed "%s"', $expect), $lineno, $this->filename);
|
265 |
+
}
|
266 |
+
}
|
267 |
+
|
268 |
+
$this->pushToken(Twig_Token::PUNCTUATION_TYPE, $this->code[$this->cursor]);
|
269 |
+
++$this->cursor;
|
270 |
+
}
|
271 |
+
// strings
|
272 |
+
elseif (preg_match(self::REGEX_STRING, $this->code, $match, null, $this->cursor)) {
|
273 |
+
$this->pushToken(Twig_Token::STRING_TYPE, stripcslashes(substr($match[0], 1, -1)));
|
274 |
+
$this->moveCursor($match[0]);
|
275 |
+
}
|
276 |
+
// opening double quoted string
|
277 |
+
elseif (preg_match(self::REGEX_DQ_STRING_DELIM, $this->code, $match, null, $this->cursor)) {
|
278 |
+
$this->brackets[] = array('"', $this->lineno);
|
279 |
+
$this->pushState(self::STATE_STRING);
|
280 |
+
$this->moveCursor($match[0]);
|
281 |
+
}
|
282 |
+
// unlexable
|
283 |
+
else {
|
284 |
+
throw new Twig_Error_Syntax(sprintf('Unexpected character "%s"', $this->code[$this->cursor]), $this->lineno, $this->filename);
|
285 |
+
}
|
286 |
+
}
|
287 |
+
|
288 |
+
protected function lexRawData($tag)
|
289 |
+
{
|
290 |
+
if (!preg_match(str_replace('%s', $tag, $this->regexes['lex_raw_data']), $this->code, $match, PREG_OFFSET_CAPTURE, $this->cursor)) {
|
291 |
+
throw new Twig_Error_Syntax(sprintf('Unexpected end of file: Unclosed "%s" block', $tag), $this->lineno, $this->filename);
|
292 |
+
}
|
293 |
+
|
294 |
+
$text = substr($this->code, $this->cursor, $match[0][1] - $this->cursor);
|
295 |
+
$this->moveCursor($text.$match[0][0]);
|
296 |
+
|
297 |
+
if (false !== strpos($match[1][0], $this->options['whitespace_trim'])) {
|
298 |
+
$text = rtrim($text);
|
299 |
+
}
|
300 |
+
|
301 |
+
$this->pushToken(Twig_Token::TEXT_TYPE, $text);
|
302 |
+
}
|
303 |
+
|
304 |
+
protected function lexComment()
|
305 |
+
{
|
306 |
+
if (!preg_match($this->regexes['lex_comment'], $this->code, $match, PREG_OFFSET_CAPTURE, $this->cursor)) {
|
307 |
+
throw new Twig_Error_Syntax('Unclosed comment', $this->lineno, $this->filename);
|
308 |
+
}
|
309 |
+
|
310 |
+
$this->moveCursor(substr($this->code, $this->cursor, $match[0][1] - $this->cursor).$match[0][0]);
|
311 |
+
}
|
312 |
+
|
313 |
+
protected function lexString()
|
314 |
+
{
|
315 |
+
if (preg_match($this->regexes['interpolation_start'], $this->code, $match, null, $this->cursor)) {
|
316 |
+
$this->brackets[] = array($this->options['interpolation'][0], $this->lineno);
|
317 |
+
$this->pushToken(Twig_Token::INTERPOLATION_START_TYPE);
|
318 |
+
$this->moveCursor($match[0]);
|
319 |
+
$this->pushState(self::STATE_INTERPOLATION);
|
320 |
+
|
321 |
+
} elseif (preg_match(self::REGEX_DQ_STRING_PART, $this->code, $match, null, $this->cursor) && strlen($match[0]) > 0) {
|
322 |
+
$this->pushToken(Twig_Token::STRING_TYPE, stripcslashes($match[0]));
|
323 |
+
$this->moveCursor($match[0]);
|
324 |
+
|
325 |
+
} elseif (preg_match(self::REGEX_DQ_STRING_DELIM, $this->code, $match, null, $this->cursor)) {
|
326 |
+
list($expect, $lineno) = array_pop($this->brackets);
|
327 |
+
if ($this->code[$this->cursor] != '"') {
|
328 |
+
throw new Twig_Error_Syntax(sprintf('Unclosed "%s"', $expect), $lineno, $this->filename);
|
329 |
+
}
|
330 |
+
|
331 |
+
$this->popState();
|
332 |
+
++$this->cursor;
|
333 |
+
}
|
334 |
+
}
|
335 |
+
|
336 |
+
protected function lexInterpolation()
|
337 |
+
{
|
338 |
+
$bracket = end($this->brackets);
|
339 |
+
if ($this->options['interpolation'][0] === $bracket[0] && preg_match($this->regexes['interpolation_end'], $this->code, $match, null, $this->cursor)) {
|
340 |
+
array_pop($this->brackets);
|
341 |
+
$this->pushToken(Twig_Token::INTERPOLATION_END_TYPE);
|
342 |
+
$this->moveCursor($match[0]);
|
343 |
+
$this->popState();
|
344 |
+
} else {
|
345 |
+
$this->lexExpression();
|
346 |
+
}
|
347 |
+
}
|
348 |
+
|
349 |
+
protected function pushToken($type, $value = '')
|
350 |
+
{
|
351 |
+
// do not push empty text tokens
|
352 |
+
if (Twig_Token::TEXT_TYPE === $type && '' === $value) {
|
353 |
+
return;
|
354 |
+
}
|
355 |
+
|
356 |
+
$this->tokens[] = new Twig_Token($type, $value, $this->lineno);
|
357 |
+
}
|
358 |
+
|
359 |
+
protected function moveCursor($text)
|
360 |
+
{
|
361 |
+
$this->cursor += strlen($text);
|
362 |
+
$this->lineno += substr_count($text, "\n");
|
363 |
+
}
|
364 |
+
|
365 |
+
protected function getOperatorRegex()
|
366 |
+
{
|
367 |
+
$operators = array_merge(
|
368 |
+
array('='),
|
369 |
+
array_keys($this->env->getUnaryOperators()),
|
370 |
+
array_keys($this->env->getBinaryOperators())
|
371 |
+
);
|
372 |
+
|
373 |
+
$operators = array_combine($operators, array_map('strlen', $operators));
|
374 |
+
arsort($operators);
|
375 |
+
|
376 |
+
$regex = array();
|
377 |
+
foreach ($operators as $operator => $length) {
|
378 |
+
// an operator that ends with a character must be followed by
|
379 |
+
// a whitespace or a parenthesis
|
380 |
+
if (ctype_alpha($operator[$length - 1])) {
|
381 |
+
$r = preg_quote($operator, '/').'(?=[\s()])';
|
382 |
+
} else {
|
383 |
+
$r = preg_quote($operator, '/');
|
384 |
+
}
|
385 |
+
|
386 |
+
// an operator with a space can be any amount of whitespaces
|
387 |
+
$r = preg_replace('/\s+/', '\s+', $r);
|
388 |
+
|
389 |
+
$regex[] = $r;
|
390 |
+
}
|
391 |
+
|
392 |
+
return '/'.implode('|', $regex).'/A';
|
393 |
+
}
|
394 |
+
|
395 |
+
protected function pushState($state)
|
396 |
+
{
|
397 |
+
$this->states[] = $this->state;
|
398 |
+
$this->state = $state;
|
399 |
+
}
|
400 |
+
|
401 |
+
protected function popState()
|
402 |
+
{
|
403 |
+
if (0 === count($this->states)) {
|
404 |
+
throw new Exception('Cannot pop state without a previous state');
|
405 |
+
}
|
406 |
+
|
407 |
+
$this->state = array_pop($this->states);
|
408 |
+
}
|
409 |
+
}
|
classes/Twig/LexerInterface.php
CHANGED
@@ -1,32 +1,32 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2009 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
/**
|
13 |
-
* Interface implemented by lexer classes.
|
14 |
-
*
|
15 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
16 |
-
*
|
17 |
-
* @deprecated since 1.12 (to be removed in 3.0)
|
18 |
-
*/
|
19 |
-
interface Twig_LexerInterface
|
20 |
-
{
|
21 |
-
/**
|
22 |
-
* Tokenizes a source code.
|
23 |
-
*
|
24 |
-
* @param string $code The source code
|
25 |
-
* @param string $filename A unique identifier for the source code
|
26 |
-
*
|
27 |
-
* @return Twig_TokenStream A token stream instance
|
28 |
-
*
|
29 |
-
* @throws Twig_Error_Syntax When the code is syntactically wrong
|
30 |
-
*/
|
31 |
-
public function tokenize($code, $filename = null);
|
32 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2009 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Interface implemented by lexer classes.
|
14 |
+
*
|
15 |
+
* @author Fabien Potencier <fabien@symfony.com>
|
16 |
+
*
|
17 |
+
* @deprecated since 1.12 (to be removed in 3.0)
|
18 |
+
*/
|
19 |
+
interface Twig_LexerInterface
|
20 |
+
{
|
21 |
+
/**
|
22 |
+
* Tokenizes a source code.
|
23 |
+
*
|
24 |
+
* @param string $code The source code
|
25 |
+
* @param string $filename A unique identifier for the source code
|
26 |
+
*
|
27 |
+
* @return Twig_TokenStream A token stream instance
|
28 |
+
*
|
29 |
+
* @throws Twig_Error_Syntax When the code is syntactically wrong
|
30 |
+
*/
|
31 |
+
public function tokenize($code, $filename = null);
|
32 |
+
}
|
classes/Twig/Loader/Array.php
CHANGED
@@ -1,95 +1,95 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2009 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
/**
|
13 |
-
* Loads a template from an array.
|
14 |
-
*
|
15 |
-
* When using this loader with a cache mechanism, you should know that a new cache
|
16 |
-
* key is generated each time a template content "changes" (the cache key being the
|
17 |
-
* source code of the template). If you don't want to see your cache grows out of
|
18 |
-
* control, you need to take care of clearing the old cache file by yourself.
|
19 |
-
*
|
20 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
21 |
-
*/
|
22 |
-
class Twig_Loader_Array implements Twig_LoaderInterface, Twig_ExistsLoaderInterface
|
23 |
-
{
|
24 |
-
protected $templates = array();
|
25 |
-
|
26 |
-
/**
|
27 |
-
* Constructor.
|
28 |
-
*
|
29 |
-
* @param array $templates An array of templates (keys are the names, and values are the source code)
|
30 |
-
*
|
31 |
-
* @see Twig_Loader
|
32 |
-
*/
|
33 |
-
public function __construct(array $templates)
|
34 |
-
{
|
35 |
-
$this->templates = $templates;
|
36 |
-
}
|
37 |
-
|
38 |
-
/**
|
39 |
-
* Adds or overrides a template.
|
40 |
-
*
|
41 |
-
* @param string $name The template name
|
42 |
-
* @param string $template The template source
|
43 |
-
*/
|
44 |
-
public function setTemplate($name, $template)
|
45 |
-
{
|
46 |
-
$this->templates[(string) $name] = $template;
|
47 |
-
}
|
48 |
-
|
49 |
-
/**
|
50 |
-
* {@inheritdoc}
|
51 |
-
*/
|
52 |
-
public function getSource($name)
|
53 |
-
{
|
54 |
-
$name = (string) $name;
|
55 |
-
if (!isset($this->templates[$name])) {
|
56 |
-
throw new Twig_Error_Loader(sprintf('Template "%s" is not defined.', $name));
|
57 |
-
}
|
58 |
-
|
59 |
-
return $this->templates[$name];
|
60 |
-
}
|
61 |
-
|
62 |
-
/**
|
63 |
-
* {@inheritdoc}
|
64 |
-
*/
|
65 |
-
public function exists($name)
|
66 |
-
{
|
67 |
-
return isset($this->templates[(string) $name]);
|
68 |
-
}
|
69 |
-
|
70 |
-
/**
|
71 |
-
* {@inheritdoc}
|
72 |
-
*/
|
73 |
-
public function getCacheKey($name)
|
74 |
-
{
|
75 |
-
$name = (string) $name;
|
76 |
-
if (!isset($this->templates[$name])) {
|
77 |
-
throw new Twig_Error_Loader(sprintf('Template "%s" is not defined.', $name));
|
78 |
-
}
|
79 |
-
|
80 |
-
return $this->templates[$name];
|
81 |
-
}
|
82 |
-
|
83 |
-
/**
|
84 |
-
* {@inheritdoc}
|
85 |
-
*/
|
86 |
-
public function isFresh($name, $time)
|
87 |
-
{
|
88 |
-
$name = (string) $name;
|
89 |
-
if (!isset($this->templates[$name])) {
|
90 |
-
throw new Twig_Error_Loader(sprintf('Template "%s" is not defined.', $name));
|
91 |
-
}
|
92 |
-
|
93 |
-
return true;
|
94 |
-
}
|
95 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2009 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Loads a template from an array.
|
14 |
+
*
|
15 |
+
* When using this loader with a cache mechanism, you should know that a new cache
|
16 |
+
* key is generated each time a template content "changes" (the cache key being the
|
17 |
+
* source code of the template). If you don't want to see your cache grows out of
|
18 |
+
* control, you need to take care of clearing the old cache file by yourself.
|
19 |
+
*
|
20 |
+
* @author Fabien Potencier <fabien@symfony.com>
|
21 |
+
*/
|
22 |
+
class Twig_Loader_Array implements Twig_LoaderInterface, Twig_ExistsLoaderInterface
|
23 |
+
{
|
24 |
+
protected $templates = array();
|
25 |
+
|
26 |
+
/**
|
27 |
+
* Constructor.
|
28 |
+
*
|
29 |
+
* @param array $templates An array of templates (keys are the names, and values are the source code)
|
30 |
+
*
|
31 |
+
* @see Twig_Loader
|
32 |
+
*/
|
33 |
+
public function __construct(array $templates)
|
34 |
+
{
|
35 |
+
$this->templates = $templates;
|
36 |
+
}
|
37 |
+
|
38 |
+
/**
|
39 |
+
* Adds or overrides a template.
|
40 |
+
*
|
41 |
+
* @param string $name The template name
|
42 |
+
* @param string $template The template source
|
43 |
+
*/
|
44 |
+
public function setTemplate($name, $template)
|
45 |
+
{
|
46 |
+
$this->templates[(string) $name] = $template;
|
47 |
+
}
|
48 |
+
|
49 |
+
/**
|
50 |
+
* {@inheritdoc}
|
51 |
+
*/
|
52 |
+
public function getSource($name)
|
53 |
+
{
|
54 |
+
$name = (string) $name;
|
55 |
+
if (!isset($this->templates[$name])) {
|
56 |
+
throw new Twig_Error_Loader(sprintf('Template "%s" is not defined.', $name));
|
57 |
+
}
|
58 |
+
|
59 |
+
return $this->templates[$name];
|
60 |
+
}
|
61 |
+
|
62 |
+
/**
|
63 |
+
* {@inheritdoc}
|
64 |
+
*/
|
65 |
+
public function exists($name)
|
66 |
+
{
|
67 |
+
return isset($this->templates[(string) $name]);
|
68 |
+
}
|
69 |
+
|
70 |
+
/**
|
71 |
+
* {@inheritdoc}
|
72 |
+
*/
|
73 |
+
public function getCacheKey($name)
|
74 |
+
{
|
75 |
+
$name = (string) $name;
|
76 |
+
if (!isset($this->templates[$name])) {
|
77 |
+
throw new Twig_Error_Loader(sprintf('Template "%s" is not defined.', $name));
|
78 |
+
}
|
79 |
+
|
80 |
+
return $this->templates[$name];
|
81 |
+
}
|
82 |
+
|
83 |
+
/**
|
84 |
+
* {@inheritdoc}
|
85 |
+
*/
|
86 |
+
public function isFresh($name, $time)
|
87 |
+
{
|
88 |
+
$name = (string) $name;
|
89 |
+
if (!isset($this->templates[$name])) {
|
90 |
+
throw new Twig_Error_Loader(sprintf('Template "%s" is not defined.', $name));
|
91 |
+
}
|
92 |
+
|
93 |
+
return true;
|
94 |
+
}
|
95 |
+
}
|
classes/Twig/Loader/Chain.php
CHANGED
@@ -1,138 +1,138 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2011 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
/**
|
13 |
-
* Loads templates from other loaders.
|
14 |
-
*
|
15 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
16 |
-
*/
|
17 |
-
class Twig_Loader_Chain implements Twig_LoaderInterface, Twig_ExistsLoaderInterface
|
18 |
-
{
|
19 |
-
private $hasSourceCache = array();
|
20 |
-
protected $loaders = array();
|
21 |
-
|
22 |
-
/**
|
23 |
-
* Constructor.
|
24 |
-
*
|
25 |
-
* @param Twig_LoaderInterface[] $loaders An array of loader instances
|
26 |
-
*/
|
27 |
-
public function __construct(array $loaders = array())
|
28 |
-
{
|
29 |
-
foreach ($loaders as $loader) {
|
30 |
-
$this->addLoader($loader);
|
31 |
-
}
|
32 |
-
}
|
33 |
-
|
34 |
-
/**
|
35 |
-
* Adds a loader instance.
|
36 |
-
*
|
37 |
-
* @param Twig_LoaderInterface $loader A Loader instance
|
38 |
-
*/
|
39 |
-
public function addLoader(Twig_LoaderInterface $loader)
|
40 |
-
{
|
41 |
-
$this->loaders[] = $loader;
|
42 |
-
$this->hasSourceCache = array();
|
43 |
-
}
|
44 |
-
|
45 |
-
/**
|
46 |
-
* {@inheritdoc}
|
47 |
-
*/
|
48 |
-
public function getSource($name)
|
49 |
-
{
|
50 |
-
$exceptions = array();
|
51 |
-
foreach ($this->loaders as $loader) {
|
52 |
-
if ($loader instanceof Twig_ExistsLoaderInterface && !$loader->exists($name)) {
|
53 |
-
continue;
|
54 |
-
}
|
55 |
-
|
56 |
-
try {
|
57 |
-
return $loader->getSource($name);
|
58 |
-
} catch (Twig_Error_Loader $e) {
|
59 |
-
$exceptions[] = $e->getMessage();
|
60 |
-
}
|
61 |
-
}
|
62 |
-
|
63 |
-
throw new Twig_Error_Loader(sprintf('Template "%s" is not defined (%s).', $name, implode(', ', $exceptions)));
|
64 |
-
}
|
65 |
-
|
66 |
-
/**
|
67 |
-
* {@inheritdoc}
|
68 |
-
*/
|
69 |
-
public function exists($name)
|
70 |
-
{
|
71 |
-
$name = (string) $name;
|
72 |
-
|
73 |
-
if (isset($this->hasSourceCache[$name])) {
|
74 |
-
return $this->hasSourceCache[$name];
|
75 |
-
}
|
76 |
-
|
77 |
-
foreach ($this->loaders as $loader) {
|
78 |
-
if ($loader instanceof Twig_ExistsLoaderInterface) {
|
79 |
-
if ($loader->exists($name)) {
|
80 |
-
return $this->hasSourceCache[$name] = true;
|
81 |
-
}
|
82 |
-
|
83 |
-
continue;
|
84 |
-
}
|
85 |
-
|
86 |
-
try {
|
87 |
-
$loader->getSource($name);
|
88 |
-
|
89 |
-
return $this->hasSourceCache[$name] = true;
|
90 |
-
} catch (Twig_Error_Loader $e) {
|
91 |
-
}
|
92 |
-
}
|
93 |
-
|
94 |
-
return $this->hasSourceCache[$name] = false;
|
95 |
-
}
|
96 |
-
|
97 |
-
/**
|
98 |
-
* {@inheritdoc}
|
99 |
-
*/
|
100 |
-
public function getCacheKey($name)
|
101 |
-
{
|
102 |
-
$exceptions = array();
|
103 |
-
foreach ($this->loaders as $loader) {
|
104 |
-
if ($loader instanceof Twig_ExistsLoaderInterface && !$loader->exists($name)) {
|
105 |
-
continue;
|
106 |
-
}
|
107 |
-
|
108 |
-
try {
|
109 |
-
return $loader->getCacheKey($name);
|
110 |
-
} catch (Twig_Error_Loader $e) {
|
111 |
-
$exceptions[] = get_class($loader).': '.$e->getMessage();
|
112 |
-
}
|
113 |
-
}
|
114 |
-
|
115 |
-
throw new Twig_Error_Loader(sprintf('Template "%s" is not defined (%s).', $name, implode(' ', $exceptions)));
|
116 |
-
}
|
117 |
-
|
118 |
-
/**
|
119 |
-
* {@inheritdoc}
|
120 |
-
*/
|
121 |
-
public function isFresh($name, $time)
|
122 |
-
{
|
123 |
-
$exceptions = array();
|
124 |
-
foreach ($this->loaders as $loader) {
|
125 |
-
if ($loader instanceof Twig_ExistsLoaderInterface && !$loader->exists($name)) {
|
126 |
-
continue;
|
127 |
-
}
|
128 |
-
|
129 |
-
try {
|
130 |
-
return $loader->isFresh($name, $time);
|
131 |
-
} catch (Twig_Error_Loader $e) {
|
132 |
-
$exceptions[] = get_class($loader).': '.$e->getMessage();
|
133 |
-
}
|
134 |
-
}
|
135 |
-
|
136 |
-
throw new Twig_Error_Loader(sprintf('Template "%s" is not defined (%s).', $name, implode(' ', $exceptions)));
|
137 |
-
}
|
138 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2011 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Loads templates from other loaders.
|
14 |
+
*
|
15 |
+
* @author Fabien Potencier <fabien@symfony.com>
|
16 |
+
*/
|
17 |
+
class Twig_Loader_Chain implements Twig_LoaderInterface, Twig_ExistsLoaderInterface
|
18 |
+
{
|
19 |
+
private $hasSourceCache = array();
|
20 |
+
protected $loaders = array();
|
21 |
+
|
22 |
+
/**
|
23 |
+
* Constructor.
|
24 |
+
*
|
25 |
+
* @param Twig_LoaderInterface[] $loaders An array of loader instances
|
26 |
+
*/
|
27 |
+
public function __construct(array $loaders = array())
|
28 |
+
{
|
29 |
+
foreach ($loaders as $loader) {
|
30 |
+
$this->addLoader($loader);
|
31 |
+
}
|
32 |
+
}
|
33 |
+
|
34 |
+
/**
|
35 |
+
* Adds a loader instance.
|
36 |
+
*
|
37 |
+
* @param Twig_LoaderInterface $loader A Loader instance
|
38 |
+
*/
|
39 |
+
public function addLoader(Twig_LoaderInterface $loader)
|
40 |
+
{
|
41 |
+
$this->loaders[] = $loader;
|
42 |
+
$this->hasSourceCache = array();
|
43 |
+
}
|
44 |
+
|
45 |
+
/**
|
46 |
+
* {@inheritdoc}
|
47 |
+
*/
|
48 |
+
public function getSource($name)
|
49 |
+
{
|
50 |
+
$exceptions = array();
|
51 |
+
foreach ($this->loaders as $loader) {
|
52 |
+
if ($loader instanceof Twig_ExistsLoaderInterface && !$loader->exists($name)) {
|
53 |
+
continue;
|
54 |
+
}
|
55 |
+
|
56 |
+
try {
|
57 |
+
return $loader->getSource($name);
|
58 |
+
} catch (Twig_Error_Loader $e) {
|
59 |
+
$exceptions[] = $e->getMessage();
|
60 |
+
}
|
61 |
+
}
|
62 |
+
|
63 |
+
throw new Twig_Error_Loader(sprintf('Template "%s" is not defined (%s).', $name, implode(', ', $exceptions)));
|
64 |
+
}
|
65 |
+
|
66 |
+
/**
|
67 |
+
* {@inheritdoc}
|
68 |
+
*/
|
69 |
+
public function exists($name)
|
70 |
+
{
|
71 |
+
$name = (string) $name;
|
72 |
+
|
73 |
+
if (isset($this->hasSourceCache[$name])) {
|
74 |
+
return $this->hasSourceCache[$name];
|
75 |
+
}
|
76 |
+
|
77 |
+
foreach ($this->loaders as $loader) {
|
78 |
+
if ($loader instanceof Twig_ExistsLoaderInterface) {
|
79 |
+
if ($loader->exists($name)) {
|
80 |
+
return $this->hasSourceCache[$name] = true;
|
81 |
+
}
|
82 |
+
|
83 |
+
continue;
|
84 |
+
}
|
85 |
+
|
86 |
+
try {
|
87 |
+
$loader->getSource($name);
|
88 |
+
|
89 |
+
return $this->hasSourceCache[$name] = true;
|
90 |
+
} catch (Twig_Error_Loader $e) {
|
91 |
+
}
|
92 |
+
}
|
93 |
+
|
94 |
+
return $this->hasSourceCache[$name] = false;
|
95 |
+
}
|
96 |
+
|
97 |
+
/**
|
98 |
+
* {@inheritdoc}
|
99 |
+
*/
|
100 |
+
public function getCacheKey($name)
|
101 |
+
{
|
102 |
+
$exceptions = array();
|
103 |
+
foreach ($this->loaders as $loader) {
|
104 |
+
if ($loader instanceof Twig_ExistsLoaderInterface && !$loader->exists($name)) {
|
105 |
+
continue;
|
106 |
+
}
|
107 |
+
|
108 |
+
try {
|
109 |
+
return $loader->getCacheKey($name);
|
110 |
+
} catch (Twig_Error_Loader $e) {
|
111 |
+
$exceptions[] = get_class($loader).': '.$e->getMessage();
|
112 |
+
}
|
113 |
+
}
|
114 |
+
|
115 |
+
throw new Twig_Error_Loader(sprintf('Template "%s" is not defined (%s).', $name, implode(' ', $exceptions)));
|
116 |
+
}
|
117 |
+
|
118 |
+
/**
|
119 |
+
* {@inheritdoc}
|
120 |
+
*/
|
121 |
+
public function isFresh($name, $time)
|
122 |
+
{
|
123 |
+
$exceptions = array();
|
124 |
+
foreach ($this->loaders as $loader) {
|
125 |
+
if ($loader instanceof Twig_ExistsLoaderInterface && !$loader->exists($name)) {
|
126 |
+
continue;
|
127 |
+
}
|
128 |
+
|
129 |
+
try {
|
130 |
+
return $loader->isFresh($name, $time);
|
131 |
+
} catch (Twig_Error_Loader $e) {
|
132 |
+
$exceptions[] = get_class($loader).': '.$e->getMessage();
|
133 |
+
}
|
134 |
+
}
|
135 |
+
|
136 |
+
throw new Twig_Error_Loader(sprintf('Template "%s" is not defined (%s).', $name, implode(' ', $exceptions)));
|
137 |
+
}
|
138 |
+
}
|
classes/Twig/Loader/Filesystem.php
CHANGED
@@ -1,236 +1,236 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2009 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
/**
|
13 |
-
* Loads template from the filesystem.
|
14 |
-
*
|
15 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
16 |
-
*/
|
17 |
-
class Twig_Loader_Filesystem implements Twig_LoaderInterface, Twig_ExistsLoaderInterface
|
18 |
-
{
|
19 |
-
/** Identifier of the main namespace. */
|
20 |
-
const MAIN_NAMESPACE = '__main__';
|
21 |
-
|
22 |
-
protected $paths = array();
|
23 |
-
protected $cache = array();
|
24 |
-
|
25 |
-
/**
|
26 |
-
* Constructor.
|
27 |
-
*
|
28 |
-
* @param string|array $paths A path or an array of paths where to look for templates
|
29 |
-
*/
|
30 |
-
public function __construct($paths = array())
|
31 |
-
{
|
32 |
-
if ($paths) {
|
33 |
-
$this->setPaths($paths);
|
34 |
-
}
|
35 |
-
}
|
36 |
-
|
37 |
-
/**
|
38 |
-
* Returns the paths to the templates.
|
39 |
-
*
|
40 |
-
* @param string $namespace A path namespace
|
41 |
-
*
|
42 |
-
* @return array The array of paths where to look for templates
|
43 |
-
*/
|
44 |
-
public function getPaths($namespace = self::MAIN_NAMESPACE)
|
45 |
-
{
|
46 |
-
return isset($this->paths[$namespace]) ? $this->paths[$namespace] : array();
|
47 |
-
}
|
48 |
-
|
49 |
-
/**
|
50 |
-
* Returns the path namespaces.
|
51 |
-
*
|
52 |
-
* The main namespace is always defined.
|
53 |
-
*
|
54 |
-
* @return array The array of defined namespaces
|
55 |
-
*/
|
56 |
-
public function getNamespaces()
|
57 |
-
{
|
58 |
-
return array_keys($this->paths);
|
59 |
-
}
|
60 |
-
|
61 |
-
/**
|
62 |
-
* Sets the paths where templates are stored.
|
63 |
-
*
|
64 |
-
* @param string|array $paths A path or an array of paths where to look for templates
|
65 |
-
* @param string $namespace A path namespace
|
66 |
-
*/
|
67 |
-
public function setPaths($paths, $namespace = self::MAIN_NAMESPACE)
|
68 |
-
{
|
69 |
-
if (!is_array($paths)) {
|
70 |
-
$paths = array($paths);
|
71 |
-
}
|
72 |
-
|
73 |
-
$this->paths[$namespace] = array();
|
74 |
-
foreach ($paths as $path) {
|
75 |
-
$this->addPath($path, $namespace);
|
76 |
-
}
|
77 |
-
}
|
78 |
-
|
79 |
-
/**
|
80 |
-
* Adds a path where templates are stored.
|
81 |
-
*
|
82 |
-
* @param string $path A path where to look for templates
|
83 |
-
* @param string $namespace A path name
|
84 |
-
*
|
85 |
-
* @throws Twig_Error_Loader
|
86 |
-
*/
|
87 |
-
public function addPath($path, $namespace = self::MAIN_NAMESPACE)
|
88 |
-
{
|
89 |
-
// invalidate the cache
|
90 |
-
$this->cache = array();
|
91 |
-
|
92 |
-
if (!is_dir($path)) {
|
93 |
-
throw new Twig_Error_Loader(sprintf('The "%s" directory does not exist.', $path));
|
94 |
-
}
|
95 |
-
|
96 |
-
$this->paths[$namespace][] = rtrim($path, '/\\');
|
97 |
-
}
|
98 |
-
|
99 |
-
/**
|
100 |
-
* Prepends a path where templates are stored.
|
101 |
-
*
|
102 |
-
* @param string $path A path where to look for templates
|
103 |
-
* @param string $namespace A path name
|
104 |
-
*
|
105 |
-
* @throws Twig_Error_Loader
|
106 |
-
*/
|
107 |
-
public function prependPath($path, $namespace = self::MAIN_NAMESPACE)
|
108 |
-
{
|
109 |
-
// invalidate the cache
|
110 |
-
$this->cache = array();
|
111 |
-
|
112 |
-
if (!is_dir($path)) {
|
113 |
-
throw new Twig_Error_Loader(sprintf('The "%s" directory does not exist.', $path));
|
114 |
-
}
|
115 |
-
|
116 |
-
$path = rtrim($path, '/\\');
|
117 |
-
|
118 |
-
if (!isset($this->paths[$namespace])) {
|
119 |
-
$this->paths[$namespace][] = $path;
|
120 |
-
} else {
|
121 |
-
array_unshift($this->paths[$namespace], $path);
|
122 |
-
}
|
123 |
-
}
|
124 |
-
|
125 |
-
/**
|
126 |
-
* {@inheritdoc}
|
127 |
-
*/
|
128 |
-
public function getSource($name)
|
129 |
-
{
|
130 |
-
return file_get_contents($this->findTemplate($name));
|
131 |
-
}
|
132 |
-
|
133 |
-
/**
|
134 |
-
* {@inheritdoc}
|
135 |
-
*/
|
136 |
-
public function getCacheKey($name)
|
137 |
-
{
|
138 |
-
return $this->findTemplate($name);
|
139 |
-
}
|
140 |
-
|
141 |
-
/**
|
142 |
-
* {@inheritdoc}
|
143 |
-
*/
|
144 |
-
public function exists($name)
|
145 |
-
{
|
146 |
-
$name = $this->normalizeName($name);
|
147 |
-
|
148 |
-
if (isset($this->cache[$name])) {
|
149 |
-
return true;
|
150 |
-
}
|
151 |
-
|
152 |
-
try {
|
153 |
-
$this->findTemplate($name);
|
154 |
-
|
155 |
-
return true;
|
156 |
-
} catch (Twig_Error_Loader $exception) {
|
157 |
-
return false;
|
158 |
-
}
|
159 |
-
}
|
160 |
-
|
161 |
-
/**
|
162 |
-
* {@inheritdoc}
|
163 |
-
*/
|
164 |
-
public function isFresh($name, $time)
|
165 |
-
{
|
166 |
-
return filemtime($this->findTemplate($name)) <= $time;
|
167 |
-
}
|
168 |
-
|
169 |
-
protected function findTemplate($name)
|
170 |
-
{
|
171 |
-
$name = $this->normalizeName($name);
|
172 |
-
|
173 |
-
if (isset($this->cache[$name])) {
|
174 |
-
return $this->cache[$name];
|
175 |
-
}
|
176 |
-
|
177 |
-
$this->validateName($name);
|
178 |
-
|
179 |
-
list($namespace, $shortname) = $this->parseName($name);
|
180 |
-
|
181 |
-
if (!isset($this->paths[$namespace])) {
|
182 |
-
throw new Twig_Error_Loader(sprintf('There are no registered paths for namespace "%s".', $namespace));
|
183 |
-
}
|
184 |
-
|
185 |
-
foreach ($this->paths[$namespace] as $path) {
|
186 |
-
if (is_file($path.'/'.$shortname)) {
|
187 |
-
return $this->cache[$name] = $path.'/'.$shortname;
|
188 |
-
}
|
189 |
-
}
|
190 |
-
|
191 |
-
throw new Twig_Error_Loader(sprintf('Unable to find template "%s" (looked into: %s).', $name, implode(', ', $this->paths[$namespace])));
|
192 |
-
}
|
193 |
-
|
194 |
-
protected function parseName($name, $default = self::MAIN_NAMESPACE)
|
195 |
-
{
|
196 |
-
if (isset($name[0]) && '@' == $name[0]) {
|
197 |
-
if (false === $pos = strpos($name, '/')) {
|
198 |
-
throw new Twig_Error_Loader(sprintf('Malformed namespaced template name "%s" (expecting "@namespace/template_name").', $name));
|
199 |
-
}
|
200 |
-
|
201 |
-
$namespace = substr($name, 1, $pos - 1);
|
202 |
-
$shortname = substr($name, $pos + 1);
|
203 |
-
|
204 |
-
return array($namespace, $shortname);
|
205 |
-
}
|
206 |
-
|
207 |
-
return array($default, $name);
|
208 |
-
}
|
209 |
-
|
210 |
-
protected function normalizeName($name)
|
211 |
-
{
|
212 |
-
return preg_replace('#/{2,}#', '/', strtr((string) $name, '\\', '/'));
|
213 |
-
}
|
214 |
-
|
215 |
-
protected function validateName($name)
|
216 |
-
{
|
217 |
-
if (false !== strpos($name, "\0")) {
|
218 |
-
throw new Twig_Error_Loader('A template name cannot contain NUL bytes.');
|
219 |
-
}
|
220 |
-
|
221 |
-
$name = ltrim($name, '/');
|
222 |
-
$parts = explode('/', $name);
|
223 |
-
$level = 0;
|
224 |
-
foreach ($parts as $part) {
|
225 |
-
if ('..' === $part) {
|
226 |
-
--$level;
|
227 |
-
} elseif ('.' !== $part) {
|
228 |
-
++$level;
|
229 |
-
}
|
230 |
-
|
231 |
-
if ($level < 0) {
|
232 |
-
throw new Twig_Error_Loader(sprintf('Looks like you try to load a template outside configured directories (%s).', $name));
|
233 |
-
}
|
234 |
-
}
|
235 |
-
}
|
236 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2009 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Loads template from the filesystem.
|
14 |
+
*
|
15 |
+
* @author Fabien Potencier <fabien@symfony.com>
|
16 |
+
*/
|
17 |
+
class Twig_Loader_Filesystem implements Twig_LoaderInterface, Twig_ExistsLoaderInterface
|
18 |
+
{
|
19 |
+
/** Identifier of the main namespace. */
|
20 |
+
const MAIN_NAMESPACE = '__main__';
|
21 |
+
|
22 |
+
protected $paths = array();
|
23 |
+
protected $cache = array();
|
24 |
+
|
25 |
+
/**
|
26 |
+
* Constructor.
|
27 |
+
*
|
28 |
+
* @param string|array $paths A path or an array of paths where to look for templates
|
29 |
+
*/
|
30 |
+
public function __construct($paths = array())
|
31 |
+
{
|
32 |
+
if ($paths) {
|
33 |
+
$this->setPaths($paths);
|
34 |
+
}
|
35 |
+
}
|
36 |
+
|
37 |
+
/**
|
38 |
+
* Returns the paths to the templates.
|
39 |
+
*
|
40 |
+
* @param string $namespace A path namespace
|
41 |
+
*
|
42 |
+
* @return array The array of paths where to look for templates
|
43 |
+
*/
|
44 |
+
public function getPaths($namespace = self::MAIN_NAMESPACE)
|
45 |
+
{
|
46 |
+
return isset($this->paths[$namespace]) ? $this->paths[$namespace] : array();
|
47 |
+
}
|
48 |
+
|
49 |
+
/**
|
50 |
+
* Returns the path namespaces.
|
51 |
+
*
|
52 |
+
* The main namespace is always defined.
|
53 |
+
*
|
54 |
+
* @return array The array of defined namespaces
|
55 |
+
*/
|
56 |
+
public function getNamespaces()
|
57 |
+
{
|
58 |
+
return array_keys($this->paths);
|
59 |
+
}
|
60 |
+
|
61 |
+
/**
|
62 |
+
* Sets the paths where templates are stored.
|
63 |
+
*
|
64 |
+
* @param string|array $paths A path or an array of paths where to look for templates
|
65 |
+
* @param string $namespace A path namespace
|
66 |
+
*/
|
67 |
+
public function setPaths($paths, $namespace = self::MAIN_NAMESPACE)
|
68 |
+
{
|
69 |
+
if (!is_array($paths)) {
|
70 |
+
$paths = array($paths);
|
71 |
+
}
|
72 |
+
|
73 |
+
$this->paths[$namespace] = array();
|
74 |
+
foreach ($paths as $path) {
|
75 |
+
$this->addPath($path, $namespace);
|
76 |
+
}
|
77 |
+
}
|
78 |
+
|
79 |
+
/**
|
80 |
+
* Adds a path where templates are stored.
|
81 |
+
*
|
82 |
+
* @param string $path A path where to look for templates
|
83 |
+
* @param string $namespace A path name
|
84 |
+
*
|
85 |
+
* @throws Twig_Error_Loader
|
86 |
+
*/
|
87 |
+
public function addPath($path, $namespace = self::MAIN_NAMESPACE)
|
88 |
+
{
|
89 |
+
// invalidate the cache
|
90 |
+
$this->cache = array();
|
91 |
+
|
92 |
+
if (!is_dir($path)) {
|
93 |
+
throw new Twig_Error_Loader(sprintf('The "%s" directory does not exist.', $path));
|
94 |
+
}
|
95 |
+
|
96 |
+
$this->paths[$namespace][] = rtrim($path, '/\\');
|
97 |
+
}
|
98 |
+
|
99 |
+
/**
|
100 |
+
* Prepends a path where templates are stored.
|
101 |
+
*
|
102 |
+
* @param string $path A path where to look for templates
|
103 |
+
* @param string $namespace A path name
|
104 |
+
*
|
105 |
+
* @throws Twig_Error_Loader
|
106 |
+
*/
|
107 |
+
public function prependPath($path, $namespace = self::MAIN_NAMESPACE)
|
108 |
+
{
|
109 |
+
// invalidate the cache
|
110 |
+
$this->cache = array();
|
111 |
+
|
112 |
+
if (!is_dir($path)) {
|
113 |
+
throw new Twig_Error_Loader(sprintf('The "%s" directory does not exist.', $path));
|
114 |
+
}
|
115 |
+
|
116 |
+
$path = rtrim($path, '/\\');
|
117 |
+
|
118 |
+
if (!isset($this->paths[$namespace])) {
|
119 |
+
$this->paths[$namespace][] = $path;
|
120 |
+
} else {
|
121 |
+
array_unshift($this->paths[$namespace], $path);
|
122 |
+
}
|
123 |
+
}
|
124 |
+
|
125 |
+
/**
|
126 |
+
* {@inheritdoc}
|
127 |
+
*/
|
128 |
+
public function getSource($name)
|
129 |
+
{
|
130 |
+
return file_get_contents($this->findTemplate($name));
|
131 |
+
}
|
132 |
+
|
133 |
+
/**
|
134 |
+
* {@inheritdoc}
|
135 |
+
*/
|
136 |
+
public function getCacheKey($name)
|
137 |
+
{
|
138 |
+
return $this->findTemplate($name);
|
139 |
+
}
|
140 |
+
|
141 |
+
/**
|
142 |
+
* {@inheritdoc}
|
143 |
+
*/
|
144 |
+
public function exists($name)
|
145 |
+
{
|
146 |
+
$name = $this->normalizeName($name);
|
147 |
+
|
148 |
+
if (isset($this->cache[$name])) {
|
149 |
+
return true;
|
150 |
+
}
|
151 |
+
|
152 |
+
try {
|
153 |
+
$this->findTemplate($name);
|
154 |
+
|
155 |
+
return true;
|
156 |
+
} catch (Twig_Error_Loader $exception) {
|
157 |
+
return false;
|
158 |
+
}
|
159 |
+
}
|
160 |
+
|
161 |
+
/**
|
162 |
+
* {@inheritdoc}
|
163 |
+
*/
|
164 |
+
public function isFresh($name, $time)
|
165 |
+
{
|
166 |
+
return filemtime($this->findTemplate($name)) <= $time;
|
167 |
+
}
|
168 |
+
|
169 |
+
protected function findTemplate($name)
|
170 |
+
{
|
171 |
+
$name = $this->normalizeName($name);
|
172 |
+
|
173 |
+
if (isset($this->cache[$name])) {
|
174 |
+
return $this->cache[$name];
|
175 |
+
}
|
176 |
+
|
177 |
+
$this->validateName($name);
|
178 |
+
|
179 |
+
list($namespace, $shortname) = $this->parseName($name);
|
180 |
+
|
181 |
+
if (!isset($this->paths[$namespace])) {
|
182 |
+
throw new Twig_Error_Loader(sprintf('There are no registered paths for namespace "%s".', $namespace));
|
183 |
+
}
|
184 |
+
|
185 |
+
foreach ($this->paths[$namespace] as $path) {
|
186 |
+
if (is_file($path.'/'.$shortname)) {
|
187 |
+
return $this->cache[$name] = $path.'/'.$shortname;
|
188 |
+
}
|
189 |
+
}
|
190 |
+
|
191 |
+
throw new Twig_Error_Loader(sprintf('Unable to find template "%s" (looked into: %s).', $name, implode(', ', $this->paths[$namespace])));
|
192 |
+
}
|
193 |
+
|
194 |
+
protected function parseName($name, $default = self::MAIN_NAMESPACE)
|
195 |
+
{
|
196 |
+
if (isset($name[0]) && '@' == $name[0]) {
|
197 |
+
if (false === $pos = strpos($name, '/')) {
|
198 |
+
throw new Twig_Error_Loader(sprintf('Malformed namespaced template name "%s" (expecting "@namespace/template_name").', $name));
|
199 |
+
}
|
200 |
+
|
201 |
+
$namespace = substr($name, 1, $pos - 1);
|
202 |
+
$shortname = substr($name, $pos + 1);
|
203 |
+
|
204 |
+
return array($namespace, $shortname);
|
205 |
+
}
|
206 |
+
|
207 |
+
return array($default, $name);
|
208 |
+
}
|
209 |
+
|
210 |
+
protected function normalizeName($name)
|
211 |
+
{
|
212 |
+
return preg_replace('#/{2,}#', '/', strtr((string) $name, '\\', '/'));
|
213 |
+
}
|
214 |
+
|
215 |
+
protected function validateName($name)
|
216 |
+
{
|
217 |
+
if (false !== strpos($name, "\0")) {
|
218 |
+
throw new Twig_Error_Loader('A template name cannot contain NUL bytes.');
|
219 |
+
}
|
220 |
+
|
221 |
+
$name = ltrim($name, '/');
|
222 |
+
$parts = explode('/', $name);
|
223 |
+
$level = 0;
|
224 |
+
foreach ($parts as $part) {
|
225 |
+
if ('..' === $part) {
|
226 |
+
--$level;
|
227 |
+
} elseif ('.' !== $part) {
|
228 |
+
++$level;
|
229 |
+
}
|
230 |
+
|
231 |
+
if ($level < 0) {
|
232 |
+
throw new Twig_Error_Loader(sprintf('Looks like you try to load a template outside configured directories (%s).', $name));
|
233 |
+
}
|
234 |
+
}
|
235 |
+
}
|
236 |
+
}
|
classes/Twig/Loader/String.php
CHANGED
@@ -1,59 +1,59 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2009 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
/**
|
13 |
-
* Loads a template from a string.
|
14 |
-
*
|
15 |
-
* This loader should only be used for unit testing as it has many limitations
|
16 |
-
* (for instance, the include or extends tag does not make any sense for a string
|
17 |
-
* loader).
|
18 |
-
*
|
19 |
-
* When using this loader with a cache mechanism, you should know that a new cache
|
20 |
-
* key is generated each time a template content "changes" (the cache key being the
|
21 |
-
* source code of the template). If you don't want to see your cache grows out of
|
22 |
-
* control, you need to take care of clearing the old cache file by yourself.
|
23 |
-
*
|
24 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
25 |
-
*/
|
26 |
-
class Twig_Loader_String implements Twig_LoaderInterface, Twig_ExistsLoaderInterface
|
27 |
-
{
|
28 |
-
/**
|
29 |
-
* {@inheritdoc}
|
30 |
-
*/
|
31 |
-
public function getSource($name)
|
32 |
-
{
|
33 |
-
return $name;
|
34 |
-
}
|
35 |
-
|
36 |
-
/**
|
37 |
-
* {@inheritdoc}
|
38 |
-
*/
|
39 |
-
public function exists($name)
|
40 |
-
{
|
41 |
-
return true;
|
42 |
-
}
|
43 |
-
|
44 |
-
/**
|
45 |
-
* {@inheritdoc}
|
46 |
-
*/
|
47 |
-
public function getCacheKey($name)
|
48 |
-
{
|
49 |
-
return $name;
|
50 |
-
}
|
51 |
-
|
52 |
-
/**
|
53 |
-
* {@inheritdoc}
|
54 |
-
*/
|
55 |
-
public function isFresh($name, $time)
|
56 |
-
{
|
57 |
-
return true;
|
58 |
-
}
|
59 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2009 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Loads a template from a string.
|
14 |
+
*
|
15 |
+
* This loader should only be used for unit testing as it has many limitations
|
16 |
+
* (for instance, the include or extends tag does not make any sense for a string
|
17 |
+
* loader).
|
18 |
+
*
|
19 |
+
* When using this loader with a cache mechanism, you should know that a new cache
|
20 |
+
* key is generated each time a template content "changes" (the cache key being the
|
21 |
+
* source code of the template). If you don't want to see your cache grows out of
|
22 |
+
* control, you need to take care of clearing the old cache file by yourself.
|
23 |
+
*
|
24 |
+
* @author Fabien Potencier <fabien@symfony.com>
|
25 |
+
*/
|
26 |
+
class Twig_Loader_String implements Twig_LoaderInterface, Twig_ExistsLoaderInterface
|
27 |
+
{
|
28 |
+
/**
|
29 |
+
* {@inheritdoc}
|
30 |
+
*/
|
31 |
+
public function getSource($name)
|
32 |
+
{
|
33 |
+
return $name;
|
34 |
+
}
|
35 |
+
|
36 |
+
/**
|
37 |
+
* {@inheritdoc}
|
38 |
+
*/
|
39 |
+
public function exists($name)
|
40 |
+
{
|
41 |
+
return true;
|
42 |
+
}
|
43 |
+
|
44 |
+
/**
|
45 |
+
* {@inheritdoc}
|
46 |
+
*/
|
47 |
+
public function getCacheKey($name)
|
48 |
+
{
|
49 |
+
return $name;
|
50 |
+
}
|
51 |
+
|
52 |
+
/**
|
53 |
+
* {@inheritdoc}
|
54 |
+
*/
|
55 |
+
public function isFresh($name, $time)
|
56 |
+
{
|
57 |
+
return true;
|
58 |
+
}
|
59 |
+
}
|
classes/Twig/LoaderInterface.php
CHANGED
@@ -1,52 +1,52 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2009 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
/**
|
13 |
-
* Interface all loaders must implement.
|
14 |
-
*
|
15 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
16 |
-
*/
|
17 |
-
interface Twig_LoaderInterface
|
18 |
-
{
|
19 |
-
/**
|
20 |
-
* Gets the source code of a template, given its name.
|
21 |
-
*
|
22 |
-
* @param string $name The name of the template to load
|
23 |
-
*
|
24 |
-
* @return string The template source code
|
25 |
-
*
|
26 |
-
* @throws Twig_Error_Loader When $name is not found
|
27 |
-
*/
|
28 |
-
public function getSource($name);
|
29 |
-
|
30 |
-
/**
|
31 |
-
* Gets the cache key to use for the cache for a given template name.
|
32 |
-
*
|
33 |
-
* @param string $name The name of the template to load
|
34 |
-
*
|
35 |
-
* @return string The cache key
|
36 |
-
*
|
37 |
-
* @throws Twig_Error_Loader When $name is not found
|
38 |
-
*/
|
39 |
-
public function getCacheKey($name);
|
40 |
-
|
41 |
-
/**
|
42 |
-
* Returns true if the template is still fresh.
|
43 |
-
*
|
44 |
-
* @param string $name The template name
|
45 |
-
* @param timestamp $time The last modification time of the cached template
|
46 |
-
*
|
47 |
-
* @return bool true if the template is fresh, false otherwise
|
48 |
-
*
|
49 |
-
* @throws Twig_Error_Loader When $name is not found
|
50 |
-
*/
|
51 |
-
public function isFresh($name, $time);
|
52 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2009 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Interface all loaders must implement.
|
14 |
+
*
|
15 |
+
* @author Fabien Potencier <fabien@symfony.com>
|
16 |
+
*/
|
17 |
+
interface Twig_LoaderInterface
|
18 |
+
{
|
19 |
+
/**
|
20 |
+
* Gets the source code of a template, given its name.
|
21 |
+
*
|
22 |
+
* @param string $name The name of the template to load
|
23 |
+
*
|
24 |
+
* @return string The template source code
|
25 |
+
*
|
26 |
+
* @throws Twig_Error_Loader When $name is not found
|
27 |
+
*/
|
28 |
+
public function getSource($name);
|
29 |
+
|
30 |
+
/**
|
31 |
+
* Gets the cache key to use for the cache for a given template name.
|
32 |
+
*
|
33 |
+
* @param string $name The name of the template to load
|
34 |
+
*
|
35 |
+
* @return string The cache key
|
36 |
+
*
|
37 |
+
* @throws Twig_Error_Loader When $name is not found
|
38 |
+
*/
|
39 |
+
public function getCacheKey($name);
|
40 |
+
|
41 |
+
/**
|
42 |
+
* Returns true if the template is still fresh.
|
43 |
+
*
|
44 |
+
* @param string $name The template name
|
45 |
+
* @param timestamp $time The last modification time of the cached template
|
46 |
+
*
|
47 |
+
* @return bool true if the template is fresh, false otherwise
|
48 |
+
*
|
49 |
+
* @throws Twig_Error_Loader When $name is not found
|
50 |
+
*/
|
51 |
+
public function isFresh($name, $time);
|
52 |
+
}
|
classes/Twig/Markup.php
CHANGED
@@ -1,37 +1,37 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2010 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
/**
|
13 |
-
* Marks a content as safe.
|
14 |
-
*
|
15 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
16 |
-
*/
|
17 |
-
class Twig_Markup implements Countable
|
18 |
-
{
|
19 |
-
protected $content;
|
20 |
-
protected $charset;
|
21 |
-
|
22 |
-
public function __construct($content, $charset)
|
23 |
-
{
|
24 |
-
$this->content = (string) $content;
|
25 |
-
$this->charset = $charset;
|
26 |
-
}
|
27 |
-
|
28 |
-
public function __toString()
|
29 |
-
{
|
30 |
-
return $this->content;
|
31 |
-
}
|
32 |
-
|
33 |
-
public function count()
|
34 |
-
{
|
35 |
-
return function_exists('mb_get_info') ? mb_strlen($this->content, $this->charset) : strlen($this->content);
|
36 |
-
}
|
37 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2010 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Marks a content as safe.
|
14 |
+
*
|
15 |
+
* @author Fabien Potencier <fabien@symfony.com>
|
16 |
+
*/
|
17 |
+
class Twig_Markup implements Countable
|
18 |
+
{
|
19 |
+
protected $content;
|
20 |
+
protected $charset;
|
21 |
+
|
22 |
+
public function __construct($content, $charset)
|
23 |
+
{
|
24 |
+
$this->content = (string) $content;
|
25 |
+
$this->charset = $charset;
|
26 |
+
}
|
27 |
+
|
28 |
+
public function __toString()
|
29 |
+
{
|
30 |
+
return $this->content;
|
31 |
+
}
|
32 |
+
|
33 |
+
public function count()
|
34 |
+
{
|
35 |
+
return function_exists('mb_get_info') ? mb_strlen($this->content, $this->charset) : strlen($this->content);
|
36 |
+
}
|
37 |
+
}
|
classes/Twig/Node.php
CHANGED
@@ -1,226 +1,226 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2009 Fabien Potencier
|
7 |
-
* (c) 2009 Armin Ronacher
|
8 |
-
*
|
9 |
-
* For the full copyright and license information, please view the LICENSE
|
10 |
-
* file that was distributed with this source code.
|
11 |
-
*/
|
12 |
-
|
13 |
-
/**
|
14 |
-
* Represents a node in the AST.
|
15 |
-
*
|
16 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
17 |
-
*/
|
18 |
-
class Twig_Node implements Twig_NodeInterface
|
19 |
-
{
|
20 |
-
protected $nodes;
|
21 |
-
protected $attributes;
|
22 |
-
protected $lineno;
|
23 |
-
protected $tag;
|
24 |
-
|
25 |
-
/**
|
26 |
-
* Constructor.
|
27 |
-
*
|
28 |
-
* The nodes are automatically made available as properties ($this->node).
|
29 |
-
* The attributes are automatically made available as array items ($this['name']).
|
30 |
-
*
|
31 |
-
* @param array $nodes An array of named nodes
|
32 |
-
* @param array $attributes An array of attributes (should not be nodes)
|
33 |
-
* @param int $lineno The line number
|
34 |
-
* @param string $tag The tag name associated with the Node
|
35 |
-
*/
|
36 |
-
public function __construct(array $nodes = array(), array $attributes = array(), $lineno = 0, $tag = null)
|
37 |
-
{
|
38 |
-
$this->nodes = $nodes;
|
39 |
-
$this->attributes = $attributes;
|
40 |
-
$this->lineno = $lineno;
|
41 |
-
$this->tag = $tag;
|
42 |
-
}
|
43 |
-
|
44 |
-
public function __toString()
|
45 |
-
{
|
46 |
-
$attributes = array();
|
47 |
-
foreach ($this->attributes as $name => $value) {
|
48 |
-
$attributes[] = sprintf('%s: %s', $name, str_replace("\n", '', var_export($value, true)));
|
49 |
-
}
|
50 |
-
|
51 |
-
$repr = array(get_class($this).'('.implode(', ', $attributes));
|
52 |
-
|
53 |
-
if (count($this->nodes)) {
|
54 |
-
foreach ($this->nodes as $name => $node) {
|
55 |
-
$len = strlen($name) + 4;
|
56 |
-
$noderepr = array();
|
57 |
-
foreach (explode("\n", (string) $node) as $line) {
|
58 |
-
$noderepr[] = str_repeat(' ', $len).$line;
|
59 |
-
}
|
60 |
-
|
61 |
-
$repr[] = sprintf(' %s: %s', $name, ltrim(implode("\n", $noderepr)));
|
62 |
-
}
|
63 |
-
|
64 |
-
$repr[] = ')';
|
65 |
-
} else {
|
66 |
-
$repr[0] .= ')';
|
67 |
-
}
|
68 |
-
|
69 |
-
return implode("\n", $repr);
|
70 |
-
}
|
71 |
-
|
72 |
-
public function toXml($asDom = false)
|
73 |
-
{
|
74 |
-
$dom = new DOMDocument('1.0', 'UTF-8');
|
75 |
-
$dom->formatOutput = true;
|
76 |
-
$dom->appendChild($xml = $dom->createElement('twig'));
|
77 |
-
|
78 |
-
$xml->appendChild($node = $dom->createElement('node'));
|
79 |
-
$node->setAttribute('class', get_class($this));
|
80 |
-
|
81 |
-
foreach ($this->attributes as $name => $value) {
|
82 |
-
$node->appendChild($attribute = $dom->createElement('attribute'));
|
83 |
-
$attribute->setAttribute('name', $name);
|
84 |
-
$attribute->appendChild($dom->createTextNode($value));
|
85 |
-
}
|
86 |
-
|
87 |
-
foreach ($this->nodes as $name => $n) {
|
88 |
-
if (null === $n) {
|
89 |
-
continue;
|
90 |
-
}
|
91 |
-
|
92 |
-
$child = $n->toXml(true)->getElementsByTagName('node')->item(0);
|
93 |
-
$child = $dom->importNode($child, true);
|
94 |
-
$child->setAttribute('name', $name);
|
95 |
-
|
96 |
-
$node->appendChild($child);
|
97 |
-
}
|
98 |
-
|
99 |
-
return $asDom ? $dom : $dom->saveXml();
|
100 |
-
}
|
101 |
-
|
102 |
-
public function compile(Twig_Compiler $compiler)
|
103 |
-
{
|
104 |
-
foreach ($this->nodes as $node) {
|
105 |
-
$node->compile($compiler);
|
106 |
-
}
|
107 |
-
}
|
108 |
-
|
109 |
-
public function getLine()
|
110 |
-
{
|
111 |
-
return $this->lineno;
|
112 |
-
}
|
113 |
-
|
114 |
-
public function getNodeTag()
|
115 |
-
{
|
116 |
-
return $this->tag;
|
117 |
-
}
|
118 |
-
|
119 |
-
/**
|
120 |
-
* Returns true if the attribute is defined.
|
121 |
-
*
|
122 |
-
* @param string The attribute name
|
123 |
-
*
|
124 |
-
* @return bool true if the attribute is defined, false otherwise
|
125 |
-
*/
|
126 |
-
public function hasAttribute($name)
|
127 |
-
{
|
128 |
-
return array_key_exists($name, $this->attributes);
|
129 |
-
}
|
130 |
-
|
131 |
-
/**
|
132 |
-
* Gets an attribute.
|
133 |
-
*
|
134 |
-
* @param string The attribute name
|
135 |
-
*
|
136 |
-
* @return mixed The attribute value
|
137 |
-
*/
|
138 |
-
public function getAttribute($name)
|
139 |
-
{
|
140 |
-
if (!array_key_exists($name, $this->attributes)) {
|
141 |
-
throw new LogicException(sprintf('Attribute "%s" does not exist for Node "%s".', $name, get_class($this)));
|
142 |
-
}
|
143 |
-
|
144 |
-
return $this->attributes[$name];
|
145 |
-
}
|
146 |
-
|
147 |
-
/**
|
148 |
-
* Sets an attribute.
|
149 |
-
*
|
150 |
-
* @param string The attribute name
|
151 |
-
* @param mixed The attribute value
|
152 |
-
*/
|
153 |
-
public function setAttribute($name, $value)
|
154 |
-
{
|
155 |
-
$this->attributes[$name] = $value;
|
156 |
-
}
|
157 |
-
|
158 |
-
/**
|
159 |
-
* Removes an attribute.
|
160 |
-
*
|
161 |
-
* @param string The attribute name
|
162 |
-
*/
|
163 |
-
public function removeAttribute($name)
|
164 |
-
{
|
165 |
-
unset($this->attributes[$name]);
|
166 |
-
}
|
167 |
-
|
168 |
-
/**
|
169 |
-
* Returns true if the node with the given identifier exists.
|
170 |
-
*
|
171 |
-
* @param string The node name
|
172 |
-
*
|
173 |
-
* @return bool true if the node with the given name exists, false otherwise
|
174 |
-
*/
|
175 |
-
public function hasNode($name)
|
176 |
-
{
|
177 |
-
return array_key_exists($name, $this->nodes);
|
178 |
-
}
|
179 |
-
|
180 |
-
/**
|
181 |
-
* Gets a node by name.
|
182 |
-
*
|
183 |
-
* @param string The node name
|
184 |
-
*
|
185 |
-
* @return Twig_Node A Twig_Node instance
|
186 |
-
*/
|
187 |
-
public function getNode($name)
|
188 |
-
{
|
189 |
-
if (!array_key_exists($name, $this->nodes)) {
|
190 |
-
throw new LogicException(sprintf('Node "%s" does not exist for Node "%s".', $name, get_class($this)));
|
191 |
-
}
|
192 |
-
|
193 |
-
return $this->nodes[$name];
|
194 |
-
}
|
195 |
-
|
196 |
-
/**
|
197 |
-
* Sets a node.
|
198 |
-
*
|
199 |
-
* @param string The node name
|
200 |
-
* @param Twig_Node A Twig_Node instance
|
201 |
-
*/
|
202 |
-
public function setNode($name, $node = null)
|
203 |
-
{
|
204 |
-
$this->nodes[$name] = $node;
|
205 |
-
}
|
206 |
-
|
207 |
-
/**
|
208 |
-
* Removes a node by name.
|
209 |
-
*
|
210 |
-
* @param string The node name
|
211 |
-
*/
|
212 |
-
public function removeNode($name)
|
213 |
-
{
|
214 |
-
unset($this->nodes[$name]);
|
215 |
-
}
|
216 |
-
|
217 |
-
public function count()
|
218 |
-
{
|
219 |
-
return count($this->nodes);
|
220 |
-
}
|
221 |
-
|
222 |
-
public function getIterator()
|
223 |
-
{
|
224 |
-
return new ArrayIterator($this->nodes);
|
225 |
-
}
|
226 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2009 Fabien Potencier
|
7 |
+
* (c) 2009 Armin Ronacher
|
8 |
+
*
|
9 |
+
* For the full copyright and license information, please view the LICENSE
|
10 |
+
* file that was distributed with this source code.
|
11 |
+
*/
|
12 |
+
|
13 |
+
/**
|
14 |
+
* Represents a node in the AST.
|
15 |
+
*
|
16 |
+
* @author Fabien Potencier <fabien@symfony.com>
|
17 |
+
*/
|
18 |
+
class Twig_Node implements Twig_NodeInterface
|
19 |
+
{
|
20 |
+
protected $nodes;
|
21 |
+
protected $attributes;
|
22 |
+
protected $lineno;
|
23 |
+
protected $tag;
|
24 |
+
|
25 |
+
/**
|
26 |
+
* Constructor.
|
27 |
+
*
|
28 |
+
* The nodes are automatically made available as properties ($this->node).
|
29 |
+
* The attributes are automatically made available as array items ($this['name']).
|
30 |
+
*
|
31 |
+
* @param array $nodes An array of named nodes
|
32 |
+
* @param array $attributes An array of attributes (should not be nodes)
|
33 |
+
* @param int $lineno The line number
|
34 |
+
* @param string $tag The tag name associated with the Node
|
35 |
+
*/
|
36 |
+
public function __construct(array $nodes = array(), array $attributes = array(), $lineno = 0, $tag = null)
|
37 |
+
{
|
38 |
+
$this->nodes = $nodes;
|
39 |
+
$this->attributes = $attributes;
|
40 |
+
$this->lineno = $lineno;
|
41 |
+
$this->tag = $tag;
|
42 |
+
}
|
43 |
+
|
44 |
+
public function __toString()
|
45 |
+
{
|
46 |
+
$attributes = array();
|
47 |
+
foreach ($this->attributes as $name => $value) {
|
48 |
+
$attributes[] = sprintf('%s: %s', $name, str_replace("\n", '', var_export($value, true)));
|
49 |
+
}
|
50 |
+
|
51 |
+
$repr = array(get_class($this).'('.implode(', ', $attributes));
|
52 |
+
|
53 |
+
if (count($this->nodes)) {
|
54 |
+
foreach ($this->nodes as $name => $node) {
|
55 |
+
$len = strlen($name) + 4;
|
56 |
+
$noderepr = array();
|
57 |
+
foreach (explode("\n", (string) $node) as $line) {
|
58 |
+
$noderepr[] = str_repeat(' ', $len).$line;
|
59 |
+
}
|
60 |
+
|
61 |
+
$repr[] = sprintf(' %s: %s', $name, ltrim(implode("\n", $noderepr)));
|
62 |
+
}
|
63 |
+
|
64 |
+
$repr[] = ')';
|
65 |
+
} else {
|
66 |
+
$repr[0] .= ')';
|
67 |
+
}
|
68 |
+
|
69 |
+
return implode("\n", $repr);
|
70 |
+
}
|
71 |
+
|
72 |
+
public function toXml($asDom = false)
|
73 |
+
{
|
74 |
+
$dom = new DOMDocument('1.0', 'UTF-8');
|
75 |
+
$dom->formatOutput = true;
|
76 |
+
$dom->appendChild($xml = $dom->createElement('twig'));
|
77 |
+
|
78 |
+
$xml->appendChild($node = $dom->createElement('node'));
|
79 |
+
$node->setAttribute('class', get_class($this));
|
80 |
+
|
81 |
+
foreach ($this->attributes as $name => $value) {
|
82 |
+
$node->appendChild($attribute = $dom->createElement('attribute'));
|
83 |
+
$attribute->setAttribute('name', $name);
|
84 |
+
$attribute->appendChild($dom->createTextNode($value));
|
85 |
+
}
|
86 |
+
|
87 |
+
foreach ($this->nodes as $name => $n) {
|
88 |
+
if (null === $n) {
|
89 |
+
continue;
|
90 |
+
}
|
91 |
+
|
92 |
+
$child = $n->toXml(true)->getElementsByTagName('node')->item(0);
|
93 |
+
$child = $dom->importNode($child, true);
|
94 |
+
$child->setAttribute('name', $name);
|
95 |
+
|
96 |
+
$node->appendChild($child);
|
97 |
+
}
|
98 |
+
|
99 |
+
return $asDom ? $dom : $dom->saveXml();
|
100 |
+
}
|
101 |
+
|
102 |
+
public function compile(Twig_Compiler $compiler)
|
103 |
+
{
|
104 |
+
foreach ($this->nodes as $node) {
|
105 |
+
$node->compile($compiler);
|
106 |
+
}
|
107 |
+
}
|
108 |
+
|
109 |
+
public function getLine()
|
110 |
+
{
|
111 |
+
return $this->lineno;
|
112 |
+
}
|
113 |
+
|
114 |
+
public function getNodeTag()
|
115 |
+
{
|
116 |
+
return $this->tag;
|
117 |
+
}
|
118 |
+
|
119 |
+
/**
|
120 |
+
* Returns true if the attribute is defined.
|
121 |
+
*
|
122 |
+
* @param string The attribute name
|
123 |
+
*
|
124 |
+
* @return bool true if the attribute is defined, false otherwise
|
125 |
+
*/
|
126 |
+
public function hasAttribute($name)
|
127 |
+
{
|
128 |
+
return array_key_exists($name, $this->attributes);
|
129 |
+
}
|
130 |
+
|
131 |
+
/**
|
132 |
+
* Gets an attribute.
|
133 |
+
*
|
134 |
+
* @param string The attribute name
|
135 |
+
*
|
136 |
+
* @return mixed The attribute value
|
137 |
+
*/
|
138 |
+
public function getAttribute($name)
|
139 |
+
{
|
140 |
+
if (!array_key_exists($name, $this->attributes)) {
|
141 |
+
throw new LogicException(sprintf('Attribute "%s" does not exist for Node "%s".', $name, get_class($this)));
|
142 |
+
}
|
143 |
+
|
144 |
+
return $this->attributes[$name];
|
145 |
+
}
|
146 |
+
|
147 |
+
/**
|
148 |
+
* Sets an attribute.
|
149 |
+
*
|
150 |
+
* @param string The attribute name
|
151 |
+
* @param mixed The attribute value
|
152 |
+
*/
|
153 |
+
public function setAttribute($name, $value)
|
154 |
+
{
|
155 |
+
$this->attributes[$name] = $value;
|
156 |
+
}
|
157 |
+
|
158 |
+
/**
|
159 |
+
* Removes an attribute.
|
160 |
+
*
|
161 |
+
* @param string The attribute name
|
162 |
+
*/
|
163 |
+
public function removeAttribute($name)
|
164 |
+
{
|
165 |
+
unset($this->attributes[$name]);
|
166 |
+
}
|
167 |
+
|
168 |
+
/**
|
169 |
+
* Returns true if the node with the given identifier exists.
|
170 |
+
*
|
171 |
+
* @param string The node name
|
172 |
+
*
|
173 |
+
* @return bool true if the node with the given name exists, false otherwise
|
174 |
+
*/
|
175 |
+
public function hasNode($name)
|
176 |
+
{
|
177 |
+
return array_key_exists($name, $this->nodes);
|
178 |
+
}
|
179 |
+
|
180 |
+
/**
|
181 |
+
* Gets a node by name.
|
182 |
+
*
|
183 |
+
* @param string The node name
|
184 |
+
*
|
185 |
+
* @return Twig_Node A Twig_Node instance
|
186 |
+
*/
|
187 |
+
public function getNode($name)
|
188 |
+
{
|
189 |
+
if (!array_key_exists($name, $this->nodes)) {
|
190 |
+
throw new LogicException(sprintf('Node "%s" does not exist for Node "%s".', $name, get_class($this)));
|
191 |
+
}
|
192 |
+
|
193 |
+
return $this->nodes[$name];
|
194 |
+
}
|
195 |
+
|
196 |
+
/**
|
197 |
+
* Sets a node.
|
198 |
+
*
|
199 |
+
* @param string The node name
|
200 |
+
* @param Twig_Node A Twig_Node instance
|
201 |
+
*/
|
202 |
+
public function setNode($name, $node = null)
|
203 |
+
{
|
204 |
+
$this->nodes[$name] = $node;
|
205 |
+
}
|
206 |
+
|
207 |
+
/**
|
208 |
+
* Removes a node by name.
|
209 |
+
*
|
210 |
+
* @param string The node name
|
211 |
+
*/
|
212 |
+
public function removeNode($name)
|
213 |
+
{
|
214 |
+
unset($this->nodes[$name]);
|
215 |
+
}
|
216 |
+
|
217 |
+
public function count()
|
218 |
+
{
|
219 |
+
return count($this->nodes);
|
220 |
+
}
|
221 |
+
|
222 |
+
public function getIterator()
|
223 |
+
{
|
224 |
+
return new ArrayIterator($this->nodes);
|
225 |
+
}
|
226 |
+
}
|
classes/Twig/Node/AutoEscape.php
CHANGED
@@ -1,39 +1,39 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2009 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
/**
|
13 |
-
* Represents an autoescape node.
|
14 |
-
*
|
15 |
-
* The value is the escaping strategy (can be html, js, ...)
|
16 |
-
*
|
17 |
-
* The true value is equivalent to html.
|
18 |
-
*
|
19 |
-
* If autoescaping is disabled, then the value is false.
|
20 |
-
*
|
21 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
22 |
-
*/
|
23 |
-
class Twig_Node_AutoEscape extends Twig_Node
|
24 |
-
{
|
25 |
-
public function __construct($value, Twig_NodeInterface $body, $lineno, $tag = 'autoescape')
|
26 |
-
{
|
27 |
-
parent::__construct(array('body' => $body), array('value' => $value), $lineno, $tag);
|
28 |
-
}
|
29 |
-
|
30 |
-
/**
|
31 |
-
* Compiles the node to PHP.
|
32 |
-
*
|
33 |
-
* @param Twig_Compiler A Twig_Compiler instance
|
34 |
-
*/
|
35 |
-
public function compile(Twig_Compiler $compiler)
|
36 |
-
{
|
37 |
-
$compiler->subcompile($this->getNode('body'));
|
38 |
-
}
|
39 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2009 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Represents an autoescape node.
|
14 |
+
*
|
15 |
+
* The value is the escaping strategy (can be html, js, ...)
|
16 |
+
*
|
17 |
+
* The true value is equivalent to html.
|
18 |
+
*
|
19 |
+
* If autoescaping is disabled, then the value is false.
|
20 |
+
*
|
21 |
+
* @author Fabien Potencier <fabien@symfony.com>
|
22 |
+
*/
|
23 |
+
class Twig_Node_AutoEscape extends Twig_Node
|
24 |
+
{
|
25 |
+
public function __construct($value, Twig_NodeInterface $body, $lineno, $tag = 'autoescape')
|
26 |
+
{
|
27 |
+
parent::__construct(array('body' => $body), array('value' => $value), $lineno, $tag);
|
28 |
+
}
|
29 |
+
|
30 |
+
/**
|
31 |
+
* Compiles the node to PHP.
|
32 |
+
*
|
33 |
+
* @param Twig_Compiler A Twig_Compiler instance
|
34 |
+
*/
|
35 |
+
public function compile(Twig_Compiler $compiler)
|
36 |
+
{
|
37 |
+
$compiler->subcompile($this->getNode('body'));
|
38 |
+
}
|
39 |
+
}
|
classes/Twig/Node/Block.php
CHANGED
@@ -1,44 +1,44 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2009 Fabien Potencier
|
7 |
-
* (c) 2009 Armin Ronacher
|
8 |
-
*
|
9 |
-
* For the full copyright and license information, please view the LICENSE
|
10 |
-
* file that was distributed with this source code.
|
11 |
-
*/
|
12 |
-
|
13 |
-
/**
|
14 |
-
* Represents a block node.
|
15 |
-
*
|
16 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
17 |
-
*/
|
18 |
-
class Twig_Node_Block extends Twig_Node
|
19 |
-
{
|
20 |
-
public function __construct($name, Twig_NodeInterface $body, $lineno, $tag = null)
|
21 |
-
{
|
22 |
-
parent::__construct(array('body' => $body), array('name' => $name), $lineno, $tag);
|
23 |
-
}
|
24 |
-
|
25 |
-
/**
|
26 |
-
* Compiles the node to PHP.
|
27 |
-
*
|
28 |
-
* @param Twig_Compiler A Twig_Compiler instance
|
29 |
-
*/
|
30 |
-
public function compile(Twig_Compiler $compiler)
|
31 |
-
{
|
32 |
-
$compiler
|
33 |
-
->addDebugInfo($this)
|
34 |
-
->write(sprintf("public function block_%s(\$context, array \$blocks = array())\n", $this->getAttribute('name')), "{\n")
|
35 |
-
->indent()
|
36 |
-
;
|
37 |
-
|
38 |
-
$compiler
|
39 |
-
->subcompile($this->getNode('body'))
|
40 |
-
->outdent()
|
41 |
-
->write("}\n\n")
|
42 |
-
;
|
43 |
-
}
|
44 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2009 Fabien Potencier
|
7 |
+
* (c) 2009 Armin Ronacher
|
8 |
+
*
|
9 |
+
* For the full copyright and license information, please view the LICENSE
|
10 |
+
* file that was distributed with this source code.
|
11 |
+
*/
|
12 |
+
|
13 |
+
/**
|
14 |
+
* Represents a block node.
|
15 |
+
*
|
16 |
+
* @author Fabien Potencier <fabien@symfony.com>
|
17 |
+
*/
|
18 |
+
class Twig_Node_Block extends Twig_Node
|
19 |
+
{
|
20 |
+
public function __construct($name, Twig_NodeInterface $body, $lineno, $tag = null)
|
21 |
+
{
|
22 |
+
parent::__construct(array('body' => $body), array('name' => $name), $lineno, $tag);
|
23 |
+
}
|
24 |
+
|
25 |
+
/**
|
26 |
+
* Compiles the node to PHP.
|
27 |
+
*
|
28 |
+
* @param Twig_Compiler A Twig_Compiler instance
|
29 |
+
*/
|
30 |
+
public function compile(Twig_Compiler $compiler)
|
31 |
+
{
|
32 |
+
$compiler
|
33 |
+
->addDebugInfo($this)
|
34 |
+
->write(sprintf("public function block_%s(\$context, array \$blocks = array())\n", $this->getAttribute('name')), "{\n")
|
35 |
+
->indent()
|
36 |
+
;
|
37 |
+
|
38 |
+
$compiler
|
39 |
+
->subcompile($this->getNode('body'))
|
40 |
+
->outdent()
|
41 |
+
->write("}\n\n")
|
42 |
+
;
|
43 |
+
}
|
44 |
+
}
|
classes/Twig/Node/BlockReference.php
CHANGED
@@ -1,37 +1,37 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2009 Fabien Potencier
|
7 |
-
* (c) 2009 Armin Ronacher
|
8 |
-
*
|
9 |
-
* For the full copyright and license information, please view the LICENSE
|
10 |
-
* file that was distributed with this source code.
|
11 |
-
*/
|
12 |
-
|
13 |
-
/**
|
14 |
-
* Represents a block call node.
|
15 |
-
*
|
16 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
17 |
-
*/
|
18 |
-
class Twig_Node_BlockReference extends Twig_Node implements Twig_NodeOutputInterface
|
19 |
-
{
|
20 |
-
public function __construct($name, $lineno, $tag = null)
|
21 |
-
{
|
22 |
-
parent::__construct(array(), array('name' => $name), $lineno, $tag);
|
23 |
-
}
|
24 |
-
|
25 |
-
/**
|
26 |
-
* Compiles the node to PHP.
|
27 |
-
*
|
28 |
-
* @param Twig_Compiler A Twig_Compiler instance
|
29 |
-
*/
|
30 |
-
public function compile(Twig_Compiler $compiler)
|
31 |
-
{
|
32 |
-
$compiler
|
33 |
-
->addDebugInfo($this)
|
34 |
-
->write(sprintf("\$this->displayBlock('%s', \$context, \$blocks);\n", $this->getAttribute('name')))
|
35 |
-
;
|
36 |
-
}
|
37 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2009 Fabien Potencier
|
7 |
+
* (c) 2009 Armin Ronacher
|
8 |
+
*
|
9 |
+
* For the full copyright and license information, please view the LICENSE
|
10 |
+
* file that was distributed with this source code.
|
11 |
+
*/
|
12 |
+
|
13 |
+
/**
|
14 |
+
* Represents a block call node.
|
15 |
+
*
|
16 |
+
* @author Fabien Potencier <fabien@symfony.com>
|
17 |
+
*/
|
18 |
+
class Twig_Node_BlockReference extends Twig_Node implements Twig_NodeOutputInterface
|
19 |
+
{
|
20 |
+
public function __construct($name, $lineno, $tag = null)
|
21 |
+
{
|
22 |
+
parent::__construct(array(), array('name' => $name), $lineno, $tag);
|
23 |
+
}
|
24 |
+
|
25 |
+
/**
|
26 |
+
* Compiles the node to PHP.
|
27 |
+
*
|
28 |
+
* @param Twig_Compiler A Twig_Compiler instance
|
29 |
+
*/
|
30 |
+
public function compile(Twig_Compiler $compiler)
|
31 |
+
{
|
32 |
+
$compiler
|
33 |
+
->addDebugInfo($this)
|
34 |
+
->write(sprintf("\$this->displayBlock('%s', \$context, \$blocks);\n", $this->getAttribute('name')))
|
35 |
+
;
|
36 |
+
}
|
37 |
+
}
|
classes/Twig/Node/Body.php
CHANGED
@@ -1,19 +1,19 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2011 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
/**
|
13 |
-
* Represents a body node.
|
14 |
-
*
|
15 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
16 |
-
*/
|
17 |
-
class Twig_Node_Body extends Twig_Node
|
18 |
-
{
|
19 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2011 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Represents a body node.
|
14 |
+
*
|
15 |
+
* @author Fabien Potencier <fabien@symfony.com>
|
16 |
+
*/
|
17 |
+
class Twig_Node_Body extends Twig_Node
|
18 |
+
{
|
19 |
+
}
|
classes/Twig/Node/Do.php
CHANGED
@@ -1,38 +1,38 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2011 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
/**
|
13 |
-
* Represents a do node.
|
14 |
-
*
|
15 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
16 |
-
*/
|
17 |
-
class Twig_Node_Do extends Twig_Node
|
18 |
-
{
|
19 |
-
public function __construct(Twig_Node_Expression $expr, $lineno, $tag = null)
|
20 |
-
{
|
21 |
-
parent::__construct(array('expr' => $expr), array(), $lineno, $tag);
|
22 |
-
}
|
23 |
-
|
24 |
-
/**
|
25 |
-
* Compiles the node to PHP.
|
26 |
-
*
|
27 |
-
* @param Twig_Compiler A Twig_Compiler instance
|
28 |
-
*/
|
29 |
-
public function compile(Twig_Compiler $compiler)
|
30 |
-
{
|
31 |
-
$compiler
|
32 |
-
->addDebugInfo($this)
|
33 |
-
->write('')
|
34 |
-
->subcompile($this->getNode('expr'))
|
35 |
-
->raw(";\n")
|
36 |
-
;
|
37 |
-
}
|
38 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2011 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Represents a do node.
|
14 |
+
*
|
15 |
+
* @author Fabien Potencier <fabien@symfony.com>
|
16 |
+
*/
|
17 |
+
class Twig_Node_Do extends Twig_Node
|
18 |
+
{
|
19 |
+
public function __construct(Twig_Node_Expression $expr, $lineno, $tag = null)
|
20 |
+
{
|
21 |
+
parent::__construct(array('expr' => $expr), array(), $lineno, $tag);
|
22 |
+
}
|
23 |
+
|
24 |
+
/**
|
25 |
+
* Compiles the node to PHP.
|
26 |
+
*
|
27 |
+
* @param Twig_Compiler A Twig_Compiler instance
|
28 |
+
*/
|
29 |
+
public function compile(Twig_Compiler $compiler)
|
30 |
+
{
|
31 |
+
$compiler
|
32 |
+
->addDebugInfo($this)
|
33 |
+
->write('')
|
34 |
+
->subcompile($this->getNode('expr'))
|
35 |
+
->raw(";\n")
|
36 |
+
;
|
37 |
+
}
|
38 |
+
}
|
classes/Twig/Node/Embed.php
CHANGED
@@ -1,38 +1,38 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2012 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
/**
|
13 |
-
* Represents an embed node.
|
14 |
-
*
|
15 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
16 |
-
*/
|
17 |
-
class Twig_Node_Embed extends Twig_Node_Include
|
18 |
-
{
|
19 |
-
// we don't inject the module to avoid node visitors to traverse it twice (as it will be already visited in the main module)
|
20 |
-
public function __construct($filename, $index, Twig_Node_Expression $variables = null, $only = false, $ignoreMissing = false, $lineno, $tag = null)
|
21 |
-
{
|
22 |
-
parent::__construct(new Twig_Node_Expression_Constant('not_used', $lineno), $variables, $only, $ignoreMissing, $lineno, $tag);
|
23 |
-
|
24 |
-
$this->setAttribute('filename', $filename);
|
25 |
-
$this->setAttribute('index', $index);
|
26 |
-
}
|
27 |
-
|
28 |
-
protected function addGetTemplate(Twig_Compiler $compiler)
|
29 |
-
{
|
30 |
-
$compiler
|
31 |
-
->write("\$this->env->loadTemplate(")
|
32 |
-
->string($this->getAttribute('filename'))
|
33 |
-
->raw(', ')
|
34 |
-
->string($this->getAttribute('index'))
|
35 |
-
->raw(")")
|
36 |
-
;
|
37 |
-
}
|
38 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2012 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Represents an embed node.
|
14 |
+
*
|
15 |
+
* @author Fabien Potencier <fabien@symfony.com>
|
16 |
+
*/
|
17 |
+
class Twig_Node_Embed extends Twig_Node_Include
|
18 |
+
{
|
19 |
+
// we don't inject the module to avoid node visitors to traverse it twice (as it will be already visited in the main module)
|
20 |
+
public function __construct($filename, $index, Twig_Node_Expression $variables = null, $only = false, $ignoreMissing = false, $lineno, $tag = null)
|
21 |
+
{
|
22 |
+
parent::__construct(new Twig_Node_Expression_Constant('not_used', $lineno), $variables, $only, $ignoreMissing, $lineno, $tag);
|
23 |
+
|
24 |
+
$this->setAttribute('filename', $filename);
|
25 |
+
$this->setAttribute('index', $index);
|
26 |
+
}
|
27 |
+
|
28 |
+
protected function addGetTemplate(Twig_Compiler $compiler)
|
29 |
+
{
|
30 |
+
$compiler
|
31 |
+
->write("\$this->env->loadTemplate(")
|
32 |
+
->string($this->getAttribute('filename'))
|
33 |
+
->raw(', ')
|
34 |
+
->string($this->getAttribute('index'))
|
35 |
+
->raw(")")
|
36 |
+
;
|
37 |
+
}
|
38 |
+
}
|
classes/Twig/Node/Expression.php
CHANGED
@@ -1,20 +1,20 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2009 Fabien Potencier
|
7 |
-
* (c) 2009 Armin Ronacher
|
8 |
-
*
|
9 |
-
* For the full copyright and license information, please view the LICENSE
|
10 |
-
* file that was distributed with this source code.
|
11 |
-
*/
|
12 |
-
|
13 |
-
/**
|
14 |
-
* Abstract class for all nodes that represents an expression.
|
15 |
-
*
|
16 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
17 |
-
*/
|
18 |
-
abstract class Twig_Node_Expression extends Twig_Node
|
19 |
-
{
|
20 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2009 Fabien Potencier
|
7 |
+
* (c) 2009 Armin Ronacher
|
8 |
+
*
|
9 |
+
* For the full copyright and license information, please view the LICENSE
|
10 |
+
* file that was distributed with this source code.
|
11 |
+
*/
|
12 |
+
|
13 |
+
/**
|
14 |
+
* Abstract class for all nodes that represents an expression.
|
15 |
+
*
|
16 |
+
* @author Fabien Potencier <fabien@symfony.com>
|
17 |
+
*/
|
18 |
+
abstract class Twig_Node_Expression extends Twig_Node
|
19 |
+
{
|
20 |
+
}
|
classes/Twig/Node/Expression/Array.php
CHANGED
@@ -1,86 +1,86 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2009 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
class Twig_Node_Expression_Array extends Twig_Node_Expression
|
12 |
-
{
|
13 |
-
protected $index;
|
14 |
-
|
15 |
-
public function __construct(array $elements, $lineno)
|
16 |
-
{
|
17 |
-
parent::__construct($elements, array(), $lineno);
|
18 |
-
|
19 |
-
$this->index = -1;
|
20 |
-
foreach ($this->getKeyValuePairs() as $pair) {
|
21 |
-
if ($pair['key'] instanceof Twig_Node_Expression_Constant && ctype_digit((string) $pair['key']->getAttribute('value')) && $pair['key']->getAttribute('value') > $this->index) {
|
22 |
-
$this->index = $pair['key']->getAttribute('value');
|
23 |
-
}
|
24 |
-
}
|
25 |
-
}
|
26 |
-
|
27 |
-
public function getKeyValuePairs()
|
28 |
-
{
|
29 |
-
$pairs = array();
|
30 |
-
|
31 |
-
foreach (array_chunk($this->nodes, 2) as $pair) {
|
32 |
-
$pairs[] = array(
|
33 |
-
'key' => $pair[0],
|
34 |
-
'value' => $pair[1],
|
35 |
-
);
|
36 |
-
}
|
37 |
-
|
38 |
-
return $pairs;
|
39 |
-
}
|
40 |
-
|
41 |
-
public function hasElement(Twig_Node_Expression $key)
|
42 |
-
{
|
43 |
-
foreach ($this->getKeyValuePairs() as $pair) {
|
44 |
-
// we compare the string representation of the keys
|
45 |
-
// to avoid comparing the line numbers which are not relevant here.
|
46 |
-
if ((string) $key == (string) $pair['key']) {
|
47 |
-
return true;
|
48 |
-
}
|
49 |
-
}
|
50 |
-
|
51 |
-
return false;
|
52 |
-
}
|
53 |
-
|
54 |
-
public function addElement(Twig_Node_Expression $value, Twig_Node_Expression $key = null)
|
55 |
-
{
|
56 |
-
if (null === $key) {
|
57 |
-
$key = new Twig_Node_Expression_Constant(++$this->index, $value->getLine());
|
58 |
-
}
|
59 |
-
|
60 |
-
array_push($this->nodes, $key, $value);
|
61 |
-
}
|
62 |
-
|
63 |
-
/**
|
64 |
-
* Compiles the node to PHP.
|
65 |
-
*
|
66 |
-
* @param Twig_Compiler A Twig_Compiler instance
|
67 |
-
*/
|
68 |
-
public function compile(Twig_Compiler $compiler)
|
69 |
-
{
|
70 |
-
$compiler->raw('array(');
|
71 |
-
$first = true;
|
72 |
-
foreach ($this->getKeyValuePairs() as $pair) {
|
73 |
-
if (!$first) {
|
74 |
-
$compiler->raw(', ');
|
75 |
-
}
|
76 |
-
$first = false;
|
77 |
-
|
78 |
-
$compiler
|
79 |
-
->subcompile($pair['key'])
|
80 |
-
->raw(' => ')
|
81 |
-
->subcompile($pair['value'])
|
82 |
-
;
|
83 |
-
}
|
84 |
-
$compiler->raw(')');
|
85 |
-
}
|
86 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2009 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
class Twig_Node_Expression_Array extends Twig_Node_Expression
|
12 |
+
{
|
13 |
+
protected $index;
|
14 |
+
|
15 |
+
public function __construct(array $elements, $lineno)
|
16 |
+
{
|
17 |
+
parent::__construct($elements, array(), $lineno);
|
18 |
+
|
19 |
+
$this->index = -1;
|
20 |
+
foreach ($this->getKeyValuePairs() as $pair) {
|
21 |
+
if ($pair['key'] instanceof Twig_Node_Expression_Constant && ctype_digit((string) $pair['key']->getAttribute('value')) && $pair['key']->getAttribute('value') > $this->index) {
|
22 |
+
$this->index = $pair['key']->getAttribute('value');
|
23 |
+
}
|
24 |
+
}
|
25 |
+
}
|
26 |
+
|
27 |
+
public function getKeyValuePairs()
|
28 |
+
{
|
29 |
+
$pairs = array();
|
30 |
+
|
31 |
+
foreach (array_chunk($this->nodes, 2) as $pair) {
|
32 |
+
$pairs[] = array(
|
33 |
+
'key' => $pair[0],
|
34 |
+
'value' => $pair[1],
|
35 |
+
);
|
36 |
+
}
|
37 |
+
|
38 |
+
return $pairs;
|
39 |
+
}
|
40 |
+
|
41 |
+
public function hasElement(Twig_Node_Expression $key)
|
42 |
+
{
|
43 |
+
foreach ($this->getKeyValuePairs() as $pair) {
|
44 |
+
// we compare the string representation of the keys
|
45 |
+
// to avoid comparing the line numbers which are not relevant here.
|
46 |
+
if ((string) $key == (string) $pair['key']) {
|
47 |
+
return true;
|
48 |
+
}
|
49 |
+
}
|
50 |
+
|
51 |
+
return false;
|
52 |
+
}
|
53 |
+
|
54 |
+
public function addElement(Twig_Node_Expression $value, Twig_Node_Expression $key = null)
|
55 |
+
{
|
56 |
+
if (null === $key) {
|
57 |
+
$key = new Twig_Node_Expression_Constant(++$this->index, $value->getLine());
|
58 |
+
}
|
59 |
+
|
60 |
+
array_push($this->nodes, $key, $value);
|
61 |
+
}
|
62 |
+
|
63 |
+
/**
|
64 |
+
* Compiles the node to PHP.
|
65 |
+
*
|
66 |
+
* @param Twig_Compiler A Twig_Compiler instance
|
67 |
+
*/
|
68 |
+
public function compile(Twig_Compiler $compiler)
|
69 |
+
{
|
70 |
+
$compiler->raw('array(');
|
71 |
+
$first = true;
|
72 |
+
foreach ($this->getKeyValuePairs() as $pair) {
|
73 |
+
if (!$first) {
|
74 |
+
$compiler->raw(', ');
|
75 |
+
}
|
76 |
+
$first = false;
|
77 |
+
|
78 |
+
$compiler
|
79 |
+
->subcompile($pair['key'])
|
80 |
+
->raw(' => ')
|
81 |
+
->subcompile($pair['value'])
|
82 |
+
;
|
83 |
+
}
|
84 |
+
$compiler->raw(')');
|
85 |
+
}
|
86 |
+
}
|
classes/Twig/Node/Expression/AssignName.php
CHANGED
@@ -1,28 +1,28 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2009 Fabien Potencier
|
7 |
-
* (c) 2009 Armin Ronacher
|
8 |
-
*
|
9 |
-
* For the full copyright and license information, please view the LICENSE
|
10 |
-
* file that was distributed with this source code.
|
11 |
-
*/
|
12 |
-
|
13 |
-
class Twig_Node_Expression_AssignName extends Twig_Node_Expression_Name
|
14 |
-
{
|
15 |
-
/**
|
16 |
-
* Compiles the node to PHP.
|
17 |
-
*
|
18 |
-
* @param Twig_Compiler A Twig_Compiler instance
|
19 |
-
*/
|
20 |
-
public function compile(Twig_Compiler $compiler)
|
21 |
-
{
|
22 |
-
$compiler
|
23 |
-
->raw('$context[')
|
24 |
-
->string($this->getAttribute('name'))
|
25 |
-
->raw(']')
|
26 |
-
;
|
27 |
-
}
|
28 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2009 Fabien Potencier
|
7 |
+
* (c) 2009 Armin Ronacher
|
8 |
+
*
|
9 |
+
* For the full copyright and license information, please view the LICENSE
|
10 |
+
* file that was distributed with this source code.
|
11 |
+
*/
|
12 |
+
|
13 |
+
class Twig_Node_Expression_AssignName extends Twig_Node_Expression_Name
|
14 |
+
{
|
15 |
+
/**
|
16 |
+
* Compiles the node to PHP.
|
17 |
+
*
|
18 |
+
* @param Twig_Compiler A Twig_Compiler instance
|
19 |
+
*/
|
20 |
+
public function compile(Twig_Compiler $compiler)
|
21 |
+
{
|
22 |
+
$compiler
|
23 |
+
->raw('$context[')
|
24 |
+
->string($this->getAttribute('name'))
|
25 |
+
->raw(']')
|
26 |
+
;
|
27 |
+
}
|
28 |
+
}
|
classes/Twig/Node/Expression/Binary.php
CHANGED
@@ -1,40 +1,40 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2009 Fabien Potencier
|
7 |
-
* (c) 2009 Armin Ronacher
|
8 |
-
*
|
9 |
-
* For the full copyright and license information, please view the LICENSE
|
10 |
-
* file that was distributed with this source code.
|
11 |
-
*/
|
12 |
-
abstract class Twig_Node_Expression_Binary extends Twig_Node_Expression
|
13 |
-
{
|
14 |
-
public function __construct(Twig_NodeInterface $left, Twig_NodeInterface $right, $lineno)
|
15 |
-
{
|
16 |
-
parent::__construct(array('left' => $left, 'right' => $right), array(), $lineno);
|
17 |
-
}
|
18 |
-
|
19 |
-
/**
|
20 |
-
* Compiles the node to PHP.
|
21 |
-
*
|
22 |
-
* @param Twig_Compiler A Twig_Compiler instance
|
23 |
-
*/
|
24 |
-
public function compile(Twig_Compiler $compiler)
|
25 |
-
{
|
26 |
-
$compiler
|
27 |
-
->raw('(')
|
28 |
-
->subcompile($this->getNode('left'))
|
29 |
-
->raw(' ')
|
30 |
-
;
|
31 |
-
$this->operator($compiler);
|
32 |
-
$compiler
|
33 |
-
->raw(' ')
|
34 |
-
->subcompile($this->getNode('right'))
|
35 |
-
->raw(')')
|
36 |
-
;
|
37 |
-
}
|
38 |
-
|
39 |
-
abstract public function operator(Twig_Compiler $compiler);
|
40 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2009 Fabien Potencier
|
7 |
+
* (c) 2009 Armin Ronacher
|
8 |
+
*
|
9 |
+
* For the full copyright and license information, please view the LICENSE
|
10 |
+
* file that was distributed with this source code.
|
11 |
+
*/
|
12 |
+
abstract class Twig_Node_Expression_Binary extends Twig_Node_Expression
|
13 |
+
{
|
14 |
+
public function __construct(Twig_NodeInterface $left, Twig_NodeInterface $right, $lineno)
|
15 |
+
{
|
16 |
+
parent::__construct(array('left' => $left, 'right' => $right), array(), $lineno);
|
17 |
+
}
|
18 |
+
|
19 |
+
/**
|
20 |
+
* Compiles the node to PHP.
|
21 |
+
*
|
22 |
+
* @param Twig_Compiler A Twig_Compiler instance
|
23 |
+
*/
|
24 |
+
public function compile(Twig_Compiler $compiler)
|
25 |
+
{
|
26 |
+
$compiler
|
27 |
+
->raw('(')
|
28 |
+
->subcompile($this->getNode('left'))
|
29 |
+
->raw(' ')
|
30 |
+
;
|
31 |
+
$this->operator($compiler);
|
32 |
+
$compiler
|
33 |
+
->raw(' ')
|
34 |
+
->subcompile($this->getNode('right'))
|
35 |
+
->raw(')')
|
36 |
+
;
|
37 |
+
}
|
38 |
+
|
39 |
+
abstract public function operator(Twig_Compiler $compiler);
|
40 |
+
}
|
classes/Twig/Node/Expression/Binary/Add.php
CHANGED
@@ -1,18 +1,18 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2009 Fabien Potencier
|
7 |
-
* (c) 2009 Armin Ronacher
|
8 |
-
*
|
9 |
-
* For the full copyright and license information, please view the LICENSE
|
10 |
-
* file that was distributed with this source code.
|
11 |
-
*/
|
12 |
-
class Twig_Node_Expression_Binary_Add extends Twig_Node_Expression_Binary
|
13 |
-
{
|
14 |
-
public function operator(Twig_Compiler $compiler)
|
15 |
-
{
|
16 |
-
return $compiler->raw('+');
|
17 |
-
}
|
18 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2009 Fabien Potencier
|
7 |
+
* (c) 2009 Armin Ronacher
|
8 |
+
*
|
9 |
+
* For the full copyright and license information, please view the LICENSE
|
10 |
+
* file that was distributed with this source code.
|
11 |
+
*/
|
12 |
+
class Twig_Node_Expression_Binary_Add extends Twig_Node_Expression_Binary
|
13 |
+
{
|
14 |
+
public function operator(Twig_Compiler $compiler)
|
15 |
+
{
|
16 |
+
return $compiler->raw('+');
|
17 |
+
}
|
18 |
+
}
|
classes/Twig/Node/Expression/Binary/And.php
CHANGED
@@ -1,18 +1,18 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2009 Fabien Potencier
|
7 |
-
* (c) 2009 Armin Ronacher
|
8 |
-
*
|
9 |
-
* For the full copyright and license information, please view the LICENSE
|
10 |
-
* file that was distributed with this source code.
|
11 |
-
*/
|
12 |
-
class Twig_Node_Expression_Binary_And extends Twig_Node_Expression_Binary
|
13 |
-
{
|
14 |
-
public function operator(Twig_Compiler $compiler)
|
15 |
-
{
|
16 |
-
return $compiler->raw('&&');
|
17 |
-
}
|
18 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2009 Fabien Potencier
|
7 |
+
* (c) 2009 Armin Ronacher
|
8 |
+
*
|
9 |
+
* For the full copyright and license information, please view the LICENSE
|
10 |
+
* file that was distributed with this source code.
|
11 |
+
*/
|
12 |
+
class Twig_Node_Expression_Binary_And extends Twig_Node_Expression_Binary
|
13 |
+
{
|
14 |
+
public function operator(Twig_Compiler $compiler)
|
15 |
+
{
|
16 |
+
return $compiler->raw('&&');
|
17 |
+
}
|
18 |
+
}
|
classes/Twig/Node/Expression/Binary/BitwiseAnd.php
CHANGED
@@ -1,18 +1,18 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2009 Fabien Potencier
|
7 |
-
* (c) 2009 Armin Ronacher
|
8 |
-
*
|
9 |
-
* For the full copyright and license information, please view the LICENSE
|
10 |
-
* file that was distributed with this source code.
|
11 |
-
*/
|
12 |
-
class Twig_Node_Expression_Binary_BitwiseAnd extends Twig_Node_Expression_Binary
|
13 |
-
{
|
14 |
-
public function operator(Twig_Compiler $compiler)
|
15 |
-
{
|
16 |
-
return $compiler->raw('&');
|
17 |
-
}
|
18 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2009 Fabien Potencier
|
7 |
+
* (c) 2009 Armin Ronacher
|
8 |
+
*
|
9 |
+
* For the full copyright and license information, please view the LICENSE
|
10 |
+
* file that was distributed with this source code.
|
11 |
+
*/
|
12 |
+
class Twig_Node_Expression_Binary_BitwiseAnd extends Twig_Node_Expression_Binary
|
13 |
+
{
|
14 |
+
public function operator(Twig_Compiler $compiler)
|
15 |
+
{
|
16 |
+
return $compiler->raw('&');
|
17 |
+
}
|
18 |
+
}
|
classes/Twig/Node/Expression/Binary/BitwiseOr.php
CHANGED
@@ -1,18 +1,18 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2009 Fabien Potencier
|
7 |
-
* (c) 2009 Armin Ronacher
|
8 |
-
*
|
9 |
-
* For the full copyright and license information, please view the LICENSE
|
10 |
-
* file that was distributed with this source code.
|
11 |
-
*/
|
12 |
-
class Twig_Node_Expression_Binary_BitwiseOr extends Twig_Node_Expression_Binary
|
13 |
-
{
|
14 |
-
public function operator(Twig_Compiler $compiler)
|
15 |
-
{
|
16 |
-
return $compiler->raw('|');
|
17 |
-
}
|
18 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2009 Fabien Potencier
|
7 |
+
* (c) 2009 Armin Ronacher
|
8 |
+
*
|
9 |
+
* For the full copyright and license information, please view the LICENSE
|
10 |
+
* file that was distributed with this source code.
|
11 |
+
*/
|
12 |
+
class Twig_Node_Expression_Binary_BitwiseOr extends Twig_Node_Expression_Binary
|
13 |
+
{
|
14 |
+
public function operator(Twig_Compiler $compiler)
|
15 |
+
{
|
16 |
+
return $compiler->raw('|');
|
17 |
+
}
|
18 |
+
}
|
classes/Twig/Node/Expression/Binary/BitwiseXor.php
CHANGED
@@ -1,18 +1,18 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2009 Fabien Potencier
|
7 |
-
* (c) 2009 Armin Ronacher
|
8 |
-
*
|
9 |
-
* For the full copyright and license information, please view the LICENSE
|
10 |
-
* file that was distributed with this source code.
|
11 |
-
*/
|
12 |
-
class Twig_Node_Expression_Binary_BitwiseXor extends Twig_Node_Expression_Binary
|
13 |
-
{
|
14 |
-
public function operator(Twig_Compiler $compiler)
|
15 |
-
{
|
16 |
-
return $compiler->raw('^');
|
17 |
-
}
|
18 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2009 Fabien Potencier
|
7 |
+
* (c) 2009 Armin Ronacher
|
8 |
+
*
|
9 |
+
* For the full copyright and license information, please view the LICENSE
|
10 |
+
* file that was distributed with this source code.
|
11 |
+
*/
|
12 |
+
class Twig_Node_Expression_Binary_BitwiseXor extends Twig_Node_Expression_Binary
|
13 |
+
{
|
14 |
+
public function operator(Twig_Compiler $compiler)
|
15 |
+
{
|
16 |
+
return $compiler->raw('^');
|
17 |
+
}
|
18 |
+
}
|
classes/Twig/Node/Expression/Binary/Concat.php
CHANGED
@@ -1,18 +1,18 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2009 Fabien Potencier
|
7 |
-
* (c) 2009 Armin Ronacher
|
8 |
-
*
|
9 |
-
* For the full copyright and license information, please view the LICENSE
|
10 |
-
* file that was distributed with this source code.
|
11 |
-
*/
|
12 |
-
class Twig_Node_Expression_Binary_Concat extends Twig_Node_Expression_Binary
|
13 |
-
{
|
14 |
-
public function operator(Twig_Compiler $compiler)
|
15 |
-
{
|
16 |
-
return $compiler->raw('.');
|
17 |
-
}
|
18 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2009 Fabien Potencier
|
7 |
+
* (c) 2009 Armin Ronacher
|
8 |
+
*
|
9 |
+
* For the full copyright and license information, please view the LICENSE
|
10 |
+
* file that was distributed with this source code.
|
11 |
+
*/
|
12 |
+
class Twig_Node_Expression_Binary_Concat extends Twig_Node_Expression_Binary
|
13 |
+
{
|
14 |
+
public function operator(Twig_Compiler $compiler)
|
15 |
+
{
|
16 |
+
return $compiler->raw('.');
|
17 |
+
}
|
18 |
+
}
|
classes/Twig/Node/Expression/Binary/Div.php
CHANGED
@@ -1,18 +1,18 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2009 Fabien Potencier
|
7 |
-
* (c) 2009 Armin Ronacher
|
8 |
-
*
|
9 |
-
* For the full copyright and license information, please view the LICENSE
|
10 |
-
* file that was distributed with this source code.
|
11 |
-
*/
|
12 |
-
class Twig_Node_Expression_Binary_Div extends Twig_Node_Expression_Binary
|
13 |
-
{
|
14 |
-
public function operator(Twig_Compiler $compiler)
|
15 |
-
{
|
16 |
-
return $compiler->raw('/');
|
17 |
-
}
|
18 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2009 Fabien Potencier
|
7 |
+
* (c) 2009 Armin Ronacher
|
8 |
+
*
|
9 |
+
* For the full copyright and license information, please view the LICENSE
|
10 |
+
* file that was distributed with this source code.
|
11 |
+
*/
|
12 |
+
class Twig_Node_Expression_Binary_Div extends Twig_Node_Expression_Binary
|
13 |
+
{
|
14 |
+
public function operator(Twig_Compiler $compiler)
|
15 |
+
{
|
16 |
+
return $compiler->raw('/');
|
17 |
+
}
|
18 |
+
}
|
classes/Twig/Node/Expression/Binary/EndsWith.php
CHANGED
@@ -1,30 +1,30 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2013 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
class Twig_Node_Expression_Binary_EndsWith extends Twig_Node_Expression_Binary
|
12 |
-
{
|
13 |
-
public function compile(Twig_Compiler $compiler)
|
14 |
-
{
|
15 |
-
$compiler
|
16 |
-
->raw('(0 === substr_compare(')
|
17 |
-
->subcompile($this->getNode('left'))
|
18 |
-
->raw(', ')
|
19 |
-
->subcompile($this->getNode('right'))
|
20 |
-
->raw(', -strlen(')
|
21 |
-
->subcompile($this->getNode('right'))
|
22 |
-
->raw(')))')
|
23 |
-
;
|
24 |
-
}
|
25 |
-
|
26 |
-
public function operator(Twig_Compiler $compiler)
|
27 |
-
{
|
28 |
-
return $compiler->raw('');
|
29 |
-
}
|
30 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2013 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
class Twig_Node_Expression_Binary_EndsWith extends Twig_Node_Expression_Binary
|
12 |
+
{
|
13 |
+
public function compile(Twig_Compiler $compiler)
|
14 |
+
{
|
15 |
+
$compiler
|
16 |
+
->raw('(0 === substr_compare(')
|
17 |
+
->subcompile($this->getNode('left'))
|
18 |
+
->raw(', ')
|
19 |
+
->subcompile($this->getNode('right'))
|
20 |
+
->raw(', -strlen(')
|
21 |
+
->subcompile($this->getNode('right'))
|
22 |
+
->raw(')))')
|
23 |
+
;
|
24 |
+
}
|
25 |
+
|
26 |
+
public function operator(Twig_Compiler $compiler)
|
27 |
+
{
|
28 |
+
return $compiler->raw('');
|
29 |
+
}
|
30 |
+
}
|
classes/Twig/Node/Expression/Binary/Equal.php
CHANGED
@@ -1,17 +1,17 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2010 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
class Twig_Node_Expression_Binary_Equal extends Twig_Node_Expression_Binary
|
12 |
-
{
|
13 |
-
public function operator(Twig_Compiler $compiler)
|
14 |
-
{
|
15 |
-
return $compiler->raw('==');
|
16 |
-
}
|
17 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2010 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
class Twig_Node_Expression_Binary_Equal extends Twig_Node_Expression_Binary
|
12 |
+
{
|
13 |
+
public function operator(Twig_Compiler $compiler)
|
14 |
+
{
|
15 |
+
return $compiler->raw('==');
|
16 |
+
}
|
17 |
+
}
|
classes/Twig/Node/Expression/Binary/FloorDiv.php
CHANGED
@@ -1,29 +1,29 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2009 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
class Twig_Node_Expression_Binary_FloorDiv extends Twig_Node_Expression_Binary
|
12 |
-
{
|
13 |
-
/**
|
14 |
-
* Compiles the node to PHP.
|
15 |
-
*
|
16 |
-
* @param Twig_Compiler A Twig_Compiler instance
|
17 |
-
*/
|
18 |
-
public function compile(Twig_Compiler $compiler)
|
19 |
-
{
|
20 |
-
$compiler->raw('intval(floor(');
|
21 |
-
parent::compile($compiler);
|
22 |
-
$compiler->raw('))');
|
23 |
-
}
|
24 |
-
|
25 |
-
public function operator(Twig_Compiler $compiler)
|
26 |
-
{
|
27 |
-
return $compiler->raw('/');
|
28 |
-
}
|
29 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2009 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
class Twig_Node_Expression_Binary_FloorDiv extends Twig_Node_Expression_Binary
|
12 |
+
{
|
13 |
+
/**
|
14 |
+
* Compiles the node to PHP.
|
15 |
+
*
|
16 |
+
* @param Twig_Compiler A Twig_Compiler instance
|
17 |
+
*/
|
18 |
+
public function compile(Twig_Compiler $compiler)
|
19 |
+
{
|
20 |
+
$compiler->raw('intval(floor(');
|
21 |
+
parent::compile($compiler);
|
22 |
+
$compiler->raw('))');
|
23 |
+
}
|
24 |
+
|
25 |
+
public function operator(Twig_Compiler $compiler)
|
26 |
+
{
|
27 |
+
return $compiler->raw('/');
|
28 |
+
}
|
29 |
+
}
|
classes/Twig/Node/Expression/Binary/Greater.php
CHANGED
@@ -1,17 +1,17 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2010 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
class Twig_Node_Expression_Binary_Greater extends Twig_Node_Expression_Binary
|
12 |
-
{
|
13 |
-
public function operator(Twig_Compiler $compiler)
|
14 |
-
{
|
15 |
-
return $compiler->raw('>');
|
16 |
-
}
|
17 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2010 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
class Twig_Node_Expression_Binary_Greater extends Twig_Node_Expression_Binary
|
12 |
+
{
|
13 |
+
public function operator(Twig_Compiler $compiler)
|
14 |
+
{
|
15 |
+
return $compiler->raw('>');
|
16 |
+
}
|
17 |
+
}
|
classes/Twig/Node/Expression/Binary/GreaterEqual.php
CHANGED
@@ -1,17 +1,17 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2010 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
class Twig_Node_Expression_Binary_GreaterEqual extends Twig_Node_Expression_Binary
|
12 |
-
{
|
13 |
-
public function operator(Twig_Compiler $compiler)
|
14 |
-
{
|
15 |
-
return $compiler->raw('>=');
|
16 |
-
}
|
17 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2010 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
class Twig_Node_Expression_Binary_GreaterEqual extends Twig_Node_Expression_Binary
|
12 |
+
{
|
13 |
+
public function operator(Twig_Compiler $compiler)
|
14 |
+
{
|
15 |
+
return $compiler->raw('>=');
|
16 |
+
}
|
17 |
+
}
|
classes/Twig/Node/Expression/Binary/In.php
CHANGED
@@ -1,33 +1,33 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2010 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
class Twig_Node_Expression_Binary_In extends Twig_Node_Expression_Binary
|
12 |
-
{
|
13 |
-
/**
|
14 |
-
* Compiles the node to PHP.
|
15 |
-
*
|
16 |
-
* @param Twig_Compiler A Twig_Compiler instance
|
17 |
-
*/
|
18 |
-
public function compile(Twig_Compiler $compiler)
|
19 |
-
{
|
20 |
-
$compiler
|
21 |
-
->raw('twig_in_filter(')
|
22 |
-
->subcompile($this->getNode('left'))
|
23 |
-
->raw(', ')
|
24 |
-
->subcompile($this->getNode('right'))
|
25 |
-
->raw(')')
|
26 |
-
;
|
27 |
-
}
|
28 |
-
|
29 |
-
public function operator(Twig_Compiler $compiler)
|
30 |
-
{
|
31 |
-
return $compiler->raw('in');
|
32 |
-
}
|
33 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2010 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
class Twig_Node_Expression_Binary_In extends Twig_Node_Expression_Binary
|
12 |
+
{
|
13 |
+
/**
|
14 |
+
* Compiles the node to PHP.
|
15 |
+
*
|
16 |
+
* @param Twig_Compiler A Twig_Compiler instance
|
17 |
+
*/
|
18 |
+
public function compile(Twig_Compiler $compiler)
|
19 |
+
{
|
20 |
+
$compiler
|
21 |
+
->raw('twig_in_filter(')
|
22 |
+
->subcompile($this->getNode('left'))
|
23 |
+
->raw(', ')
|
24 |
+
->subcompile($this->getNode('right'))
|
25 |
+
->raw(')')
|
26 |
+
;
|
27 |
+
}
|
28 |
+
|
29 |
+
public function operator(Twig_Compiler $compiler)
|
30 |
+
{
|
31 |
+
return $compiler->raw('in');
|
32 |
+
}
|
33 |
+
}
|
classes/Twig/Node/Expression/Binary/Less.php
CHANGED
@@ -1,17 +1,17 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2010 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
class Twig_Node_Expression_Binary_Less extends Twig_Node_Expression_Binary
|
12 |
-
{
|
13 |
-
public function operator(Twig_Compiler $compiler)
|
14 |
-
{
|
15 |
-
return $compiler->raw('<');
|
16 |
-
}
|
17 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2010 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
class Twig_Node_Expression_Binary_Less extends Twig_Node_Expression_Binary
|
12 |
+
{
|
13 |
+
public function operator(Twig_Compiler $compiler)
|
14 |
+
{
|
15 |
+
return $compiler->raw('<');
|
16 |
+
}
|
17 |
+
}
|
classes/Twig/Node/Expression/Binary/LessEqual.php
CHANGED
@@ -1,17 +1,17 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2010 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
class Twig_Node_Expression_Binary_LessEqual extends Twig_Node_Expression_Binary
|
12 |
-
{
|
13 |
-
public function operator(Twig_Compiler $compiler)
|
14 |
-
{
|
15 |
-
return $compiler->raw('<=');
|
16 |
-
}
|
17 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2010 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
class Twig_Node_Expression_Binary_LessEqual extends Twig_Node_Expression_Binary
|
12 |
+
{
|
13 |
+
public function operator(Twig_Compiler $compiler)
|
14 |
+
{
|
15 |
+
return $compiler->raw('<=');
|
16 |
+
}
|
17 |
+
}
|
classes/Twig/Node/Expression/Binary/Matches.php
CHANGED
@@ -1,28 +1,28 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2013 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
class Twig_Node_Expression_Binary_Matches extends Twig_Node_Expression_Binary
|
12 |
-
{
|
13 |
-
public function compile(Twig_Compiler $compiler)
|
14 |
-
{
|
15 |
-
$compiler
|
16 |
-
->raw('preg_match(')
|
17 |
-
->subcompile($this->getNode('right'))
|
18 |
-
->raw(', ')
|
19 |
-
->subcompile($this->getNode('left'))
|
20 |
-
->raw(')')
|
21 |
-
;
|
22 |
-
}
|
23 |
-
|
24 |
-
public function operator(Twig_Compiler $compiler)
|
25 |
-
{
|
26 |
-
return $compiler->raw('');
|
27 |
-
}
|
28 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2013 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
class Twig_Node_Expression_Binary_Matches extends Twig_Node_Expression_Binary
|
12 |
+
{
|
13 |
+
public function compile(Twig_Compiler $compiler)
|
14 |
+
{
|
15 |
+
$compiler
|
16 |
+
->raw('preg_match(')
|
17 |
+
->subcompile($this->getNode('right'))
|
18 |
+
->raw(', ')
|
19 |
+
->subcompile($this->getNode('left'))
|
20 |
+
->raw(')')
|
21 |
+
;
|
22 |
+
}
|
23 |
+
|
24 |
+
public function operator(Twig_Compiler $compiler)
|
25 |
+
{
|
26 |
+
return $compiler->raw('');
|
27 |
+
}
|
28 |
+
}
|
classes/Twig/Node/Expression/Binary/Mod.php
CHANGED
@@ -1,18 +1,18 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2009 Fabien Potencier
|
7 |
-
* (c) 2009 Armin Ronacher
|
8 |
-
*
|
9 |
-
* For the full copyright and license information, please view the LICENSE
|
10 |
-
* file that was distributed with this source code.
|
11 |
-
*/
|
12 |
-
class Twig_Node_Expression_Binary_Mod extends Twig_Node_Expression_Binary
|
13 |
-
{
|
14 |
-
public function operator(Twig_Compiler $compiler)
|
15 |
-
{
|
16 |
-
return $compiler->raw('%');
|
17 |
-
}
|
18 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2009 Fabien Potencier
|
7 |
+
* (c) 2009 Armin Ronacher
|
8 |
+
*
|
9 |
+
* For the full copyright and license information, please view the LICENSE
|
10 |
+
* file that was distributed with this source code.
|
11 |
+
*/
|
12 |
+
class Twig_Node_Expression_Binary_Mod extends Twig_Node_Expression_Binary
|
13 |
+
{
|
14 |
+
public function operator(Twig_Compiler $compiler)
|
15 |
+
{
|
16 |
+
return $compiler->raw('%');
|
17 |
+
}
|
18 |
+
}
|
classes/Twig/Node/Expression/Binary/Mul.php
CHANGED
@@ -1,18 +1,18 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2009 Fabien Potencier
|
7 |
-
* (c) 2009 Armin Ronacher
|
8 |
-
*
|
9 |
-
* For the full copyright and license information, please view the LICENSE
|
10 |
-
* file that was distributed with this source code.
|
11 |
-
*/
|
12 |
-
class Twig_Node_Expression_Binary_Mul extends Twig_Node_Expression_Binary
|
13 |
-
{
|
14 |
-
public function operator(Twig_Compiler $compiler)
|
15 |
-
{
|
16 |
-
return $compiler->raw('*');
|
17 |
-
}
|
18 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2009 Fabien Potencier
|
7 |
+
* (c) 2009 Armin Ronacher
|
8 |
+
*
|
9 |
+
* For the full copyright and license information, please view the LICENSE
|
10 |
+
* file that was distributed with this source code.
|
11 |
+
*/
|
12 |
+
class Twig_Node_Expression_Binary_Mul extends Twig_Node_Expression_Binary
|
13 |
+
{
|
14 |
+
public function operator(Twig_Compiler $compiler)
|
15 |
+
{
|
16 |
+
return $compiler->raw('*');
|
17 |
+
}
|
18 |
+
}
|
classes/Twig/Node/Expression/Binary/NotEqual.php
CHANGED
@@ -1,17 +1,17 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2010 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
class Twig_Node_Expression_Binary_NotEqual extends Twig_Node_Expression_Binary
|
12 |
-
{
|
13 |
-
public function operator(Twig_Compiler $compiler)
|
14 |
-
{
|
15 |
-
return $compiler->raw('!=');
|
16 |
-
}
|
17 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2010 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
class Twig_Node_Expression_Binary_NotEqual extends Twig_Node_Expression_Binary
|
12 |
+
{
|
13 |
+
public function operator(Twig_Compiler $compiler)
|
14 |
+
{
|
15 |
+
return $compiler->raw('!=');
|
16 |
+
}
|
17 |
+
}
|
classes/Twig/Node/Expression/Binary/NotIn.php
CHANGED
@@ -1,33 +1,33 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2010 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
class Twig_Node_Expression_Binary_NotIn extends Twig_Node_Expression_Binary
|
12 |
-
{
|
13 |
-
/**
|
14 |
-
* Compiles the node to PHP.
|
15 |
-
*
|
16 |
-
* @param Twig_Compiler A Twig_Compiler instance
|
17 |
-
*/
|
18 |
-
public function compile(Twig_Compiler $compiler)
|
19 |
-
{
|
20 |
-
$compiler
|
21 |
-
->raw('!twig_in_filter(')
|
22 |
-
->subcompile($this->getNode('left'))
|
23 |
-
->raw(', ')
|
24 |
-
->subcompile($this->getNode('right'))
|
25 |
-
->raw(')')
|
26 |
-
;
|
27 |
-
}
|
28 |
-
|
29 |
-
public function operator(Twig_Compiler $compiler)
|
30 |
-
{
|
31 |
-
return $compiler->raw('not in');
|
32 |
-
}
|
33 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2010 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
class Twig_Node_Expression_Binary_NotIn extends Twig_Node_Expression_Binary
|
12 |
+
{
|
13 |
+
/**
|
14 |
+
* Compiles the node to PHP.
|
15 |
+
*
|
16 |
+
* @param Twig_Compiler A Twig_Compiler instance
|
17 |
+
*/
|
18 |
+
public function compile(Twig_Compiler $compiler)
|
19 |
+
{
|
20 |
+
$compiler
|
21 |
+
->raw('!twig_in_filter(')
|
22 |
+
->subcompile($this->getNode('left'))
|
23 |
+
->raw(', ')
|
24 |
+
->subcompile($this->getNode('right'))
|
25 |
+
->raw(')')
|
26 |
+
;
|
27 |
+
}
|
28 |
+
|
29 |
+
public function operator(Twig_Compiler $compiler)
|
30 |
+
{
|
31 |
+
return $compiler->raw('not in');
|
32 |
+
}
|
33 |
+
}
|
classes/Twig/Node/Expression/Binary/Or.php
CHANGED
@@ -1,18 +1,18 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2009 Fabien Potencier
|
7 |
-
* (c) 2009 Armin Ronacher
|
8 |
-
*
|
9 |
-
* For the full copyright and license information, please view the LICENSE
|
10 |
-
* file that was distributed with this source code.
|
11 |
-
*/
|
12 |
-
class Twig_Node_Expression_Binary_Or extends Twig_Node_Expression_Binary
|
13 |
-
{
|
14 |
-
public function operator(Twig_Compiler $compiler)
|
15 |
-
{
|
16 |
-
return $compiler->raw('||');
|
17 |
-
}
|
18 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2009 Fabien Potencier
|
7 |
+
* (c) 2009 Armin Ronacher
|
8 |
+
*
|
9 |
+
* For the full copyright and license information, please view the LICENSE
|
10 |
+
* file that was distributed with this source code.
|
11 |
+
*/
|
12 |
+
class Twig_Node_Expression_Binary_Or extends Twig_Node_Expression_Binary
|
13 |
+
{
|
14 |
+
public function operator(Twig_Compiler $compiler)
|
15 |
+
{
|
16 |
+
return $compiler->raw('||');
|
17 |
+
}
|
18 |
+
}
|
classes/Twig/Node/Expression/Binary/Power.php
CHANGED
@@ -1,33 +1,33 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2010 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
class Twig_Node_Expression_Binary_Power extends Twig_Node_Expression_Binary
|
12 |
-
{
|
13 |
-
/**
|
14 |
-
* Compiles the node to PHP.
|
15 |
-
*
|
16 |
-
* @param Twig_Compiler A Twig_Compiler instance
|
17 |
-
*/
|
18 |
-
public function compile(Twig_Compiler $compiler)
|
19 |
-
{
|
20 |
-
$compiler
|
21 |
-
->raw('pow(')
|
22 |
-
->subcompile($this->getNode('left'))
|
23 |
-
->raw(', ')
|
24 |
-
->subcompile($this->getNode('right'))
|
25 |
-
->raw(')')
|
26 |
-
;
|
27 |
-
}
|
28 |
-
|
29 |
-
public function operator(Twig_Compiler $compiler)
|
30 |
-
{
|
31 |
-
return $compiler->raw('**');
|
32 |
-
}
|
33 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2010 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
class Twig_Node_Expression_Binary_Power extends Twig_Node_Expression_Binary
|
12 |
+
{
|
13 |
+
/**
|
14 |
+
* Compiles the node to PHP.
|
15 |
+
*
|
16 |
+
* @param Twig_Compiler A Twig_Compiler instance
|
17 |
+
*/
|
18 |
+
public function compile(Twig_Compiler $compiler)
|
19 |
+
{
|
20 |
+
$compiler
|
21 |
+
->raw('pow(')
|
22 |
+
->subcompile($this->getNode('left'))
|
23 |
+
->raw(', ')
|
24 |
+
->subcompile($this->getNode('right'))
|
25 |
+
->raw(')')
|
26 |
+
;
|
27 |
+
}
|
28 |
+
|
29 |
+
public function operator(Twig_Compiler $compiler)
|
30 |
+
{
|
31 |
+
return $compiler->raw('**');
|
32 |
+
}
|
33 |
+
}
|
classes/Twig/Node/Expression/Binary/Range.php
CHANGED
@@ -1,33 +1,33 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2010 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
class Twig_Node_Expression_Binary_Range extends Twig_Node_Expression_Binary
|
12 |
-
{
|
13 |
-
/**
|
14 |
-
* Compiles the node to PHP.
|
15 |
-
*
|
16 |
-
* @param Twig_Compiler A Twig_Compiler instance
|
17 |
-
*/
|
18 |
-
public function compile(Twig_Compiler $compiler)
|
19 |
-
{
|
20 |
-
$compiler
|
21 |
-
->raw('range(')
|
22 |
-
->subcompile($this->getNode('left'))
|
23 |
-
->raw(', ')
|
24 |
-
->subcompile($this->getNode('right'))
|
25 |
-
->raw(')')
|
26 |
-
;
|
27 |
-
}
|
28 |
-
|
29 |
-
public function operator(Twig_Compiler $compiler)
|
30 |
-
{
|
31 |
-
return $compiler->raw('..');
|
32 |
-
}
|
33 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2010 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
class Twig_Node_Expression_Binary_Range extends Twig_Node_Expression_Binary
|
12 |
+
{
|
13 |
+
/**
|
14 |
+
* Compiles the node to PHP.
|
15 |
+
*
|
16 |
+
* @param Twig_Compiler A Twig_Compiler instance
|
17 |
+
*/
|
18 |
+
public function compile(Twig_Compiler $compiler)
|
19 |
+
{
|
20 |
+
$compiler
|
21 |
+
->raw('range(')
|
22 |
+
->subcompile($this->getNode('left'))
|
23 |
+
->raw(', ')
|
24 |
+
->subcompile($this->getNode('right'))
|
25 |
+
->raw(')')
|
26 |
+
;
|
27 |
+
}
|
28 |
+
|
29 |
+
public function operator(Twig_Compiler $compiler)
|
30 |
+
{
|
31 |
+
return $compiler->raw('..');
|
32 |
+
}
|
33 |
+
}
|
classes/Twig/Node/Expression/Binary/StartsWith.php
CHANGED
@@ -1,28 +1,28 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2013 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
class Twig_Node_Expression_Binary_StartsWith extends Twig_Node_Expression_Binary
|
12 |
-
{
|
13 |
-
public function compile(Twig_Compiler $compiler)
|
14 |
-
{
|
15 |
-
$compiler
|
16 |
-
->raw('(0 === strpos(')
|
17 |
-
->subcompile($this->getNode('left'))
|
18 |
-
->raw(', ')
|
19 |
-
->subcompile($this->getNode('right'))
|
20 |
-
->raw('))')
|
21 |
-
;
|
22 |
-
}
|
23 |
-
|
24 |
-
public function operator(Twig_Compiler $compiler)
|
25 |
-
{
|
26 |
-
return $compiler->raw('');
|
27 |
-
}
|
28 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2013 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
class Twig_Node_Expression_Binary_StartsWith extends Twig_Node_Expression_Binary
|
12 |
+
{
|
13 |
+
public function compile(Twig_Compiler $compiler)
|
14 |
+
{
|
15 |
+
$compiler
|
16 |
+
->raw('(0 === strpos(')
|
17 |
+
->subcompile($this->getNode('left'))
|
18 |
+
->raw(', ')
|
19 |
+
->subcompile($this->getNode('right'))
|
20 |
+
->raw('))')
|
21 |
+
;
|
22 |
+
}
|
23 |
+
|
24 |
+
public function operator(Twig_Compiler $compiler)
|
25 |
+
{
|
26 |
+
return $compiler->raw('');
|
27 |
+
}
|
28 |
+
}
|
classes/Twig/Node/Expression/Binary/Sub.php
CHANGED
@@ -1,18 +1,18 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2009 Fabien Potencier
|
7 |
-
* (c) 2009 Armin Ronacher
|
8 |
-
*
|
9 |
-
* For the full copyright and license information, please view the LICENSE
|
10 |
-
* file that was distributed with this source code.
|
11 |
-
*/
|
12 |
-
class Twig_Node_Expression_Binary_Sub extends Twig_Node_Expression_Binary
|
13 |
-
{
|
14 |
-
public function operator(Twig_Compiler $compiler)
|
15 |
-
{
|
16 |
-
return $compiler->raw('-');
|
17 |
-
}
|
18 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2009 Fabien Potencier
|
7 |
+
* (c) 2009 Armin Ronacher
|
8 |
+
*
|
9 |
+
* For the full copyright and license information, please view the LICENSE
|
10 |
+
* file that was distributed with this source code.
|
11 |
+
*/
|
12 |
+
class Twig_Node_Expression_Binary_Sub extends Twig_Node_Expression_Binary
|
13 |
+
{
|
14 |
+
public function operator(Twig_Compiler $compiler)
|
15 |
+
{
|
16 |
+
return $compiler->raw('-');
|
17 |
+
}
|
18 |
+
}
|
classes/Twig/Node/Expression/BlockReference.php
CHANGED
@@ -1,51 +1,51 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2009 Fabien Potencier
|
7 |
-
* (c) 2009 Armin Ronacher
|
8 |
-
*
|
9 |
-
* For the full copyright and license information, please view the LICENSE
|
10 |
-
* file that was distributed with this source code.
|
11 |
-
*/
|
12 |
-
|
13 |
-
/**
|
14 |
-
* Represents a block call node.
|
15 |
-
*
|
16 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
17 |
-
*/
|
18 |
-
class Twig_Node_Expression_BlockReference extends Twig_Node_Expression
|
19 |
-
{
|
20 |
-
public function __construct(Twig_NodeInterface $name, $asString = false, $lineno, $tag = null)
|
21 |
-
{
|
22 |
-
parent::__construct(array('name' => $name), array('as_string' => $asString, 'output' => false), $lineno, $tag);
|
23 |
-
}
|
24 |
-
|
25 |
-
/**
|
26 |
-
* Compiles the node to PHP.
|
27 |
-
*
|
28 |
-
* @param Twig_Compiler A Twig_Compiler instance
|
29 |
-
*/
|
30 |
-
public function compile(Twig_Compiler $compiler)
|
31 |
-
{
|
32 |
-
if ($this->getAttribute('as_string')) {
|
33 |
-
$compiler->raw('(string) ');
|
34 |
-
}
|
35 |
-
|
36 |
-
if ($this->getAttribute('output')) {
|
37 |
-
$compiler
|
38 |
-
->addDebugInfo($this)
|
39 |
-
->write("\$this->displayBlock(")
|
40 |
-
->subcompile($this->getNode('name'))
|
41 |
-
->raw(", \$context, \$blocks);\n")
|
42 |
-
;
|
43 |
-
} else {
|
44 |
-
$compiler
|
45 |
-
->raw("\$this->renderBlock(")
|
46 |
-
->subcompile($this->getNode('name'))
|
47 |
-
->raw(", \$context, \$blocks)")
|
48 |
-
;
|
49 |
-
}
|
50 |
-
}
|
51 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2009 Fabien Potencier
|
7 |
+
* (c) 2009 Armin Ronacher
|
8 |
+
*
|
9 |
+
* For the full copyright and license information, please view the LICENSE
|
10 |
+
* file that was distributed with this source code.
|
11 |
+
*/
|
12 |
+
|
13 |
+
/**
|
14 |
+
* Represents a block call node.
|
15 |
+
*
|
16 |
+
* @author Fabien Potencier <fabien@symfony.com>
|
17 |
+
*/
|
18 |
+
class Twig_Node_Expression_BlockReference extends Twig_Node_Expression
|
19 |
+
{
|
20 |
+
public function __construct(Twig_NodeInterface $name, $asString = false, $lineno, $tag = null)
|
21 |
+
{
|
22 |
+
parent::__construct(array('name' => $name), array('as_string' => $asString, 'output' => false), $lineno, $tag);
|
23 |
+
}
|
24 |
+
|
25 |
+
/**
|
26 |
+
* Compiles the node to PHP.
|
27 |
+
*
|
28 |
+
* @param Twig_Compiler A Twig_Compiler instance
|
29 |
+
*/
|
30 |
+
public function compile(Twig_Compiler $compiler)
|
31 |
+
{
|
32 |
+
if ($this->getAttribute('as_string')) {
|
33 |
+
$compiler->raw('(string) ');
|
34 |
+
}
|
35 |
+
|
36 |
+
if ($this->getAttribute('output')) {
|
37 |
+
$compiler
|
38 |
+
->addDebugInfo($this)
|
39 |
+
->write("\$this->displayBlock(")
|
40 |
+
->subcompile($this->getNode('name'))
|
41 |
+
->raw(", \$context, \$blocks);\n")
|
42 |
+
;
|
43 |
+
} else {
|
44 |
+
$compiler
|
45 |
+
->raw("\$this->renderBlock(")
|
46 |
+
->subcompile($this->getNode('name'))
|
47 |
+
->raw(", \$context, \$blocks)")
|
48 |
+
;
|
49 |
+
}
|
50 |
+
}
|
51 |
+
}
|
classes/Twig/Node/Expression/Call.php
CHANGED
@@ -1,176 +1,176 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2012 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
abstract class Twig_Node_Expression_Call extends Twig_Node_Expression
|
12 |
-
{
|
13 |
-
protected function compileCallable(Twig_Compiler $compiler)
|
14 |
-
{
|
15 |
-
$closingParenthesis = false;
|
16 |
-
if ($this->hasAttribute('callable') && $callable = $this->getAttribute('callable')) {
|
17 |
-
if (is_string($callable)) {
|
18 |
-
$compiler->raw($callable);
|
19 |
-
} elseif (is_array($callable) && $callable[0] instanceof Twig_ExtensionInterface) {
|
20 |
-
$compiler->raw(sprintf('$this->env->getExtension(\'%s\')->%s', $callable[0]->getName(), $callable[1]));
|
21 |
-
} else {
|
22 |
-
$type = ucfirst($this->getAttribute('type'));
|
23 |
-
$compiler->raw(sprintf('call_user_func_array($this->env->get%s(\'%s\')->getCallable(), array', $type, $this->getAttribute('name')));
|
24 |
-
$closingParenthesis = true;
|
25 |
-
}
|
26 |
-
} else {
|
27 |
-
$compiler->raw($this->getAttribute('thing')->compile());
|
28 |
-
}
|
29 |
-
|
30 |
-
$this->compileArguments($compiler);
|
31 |
-
|
32 |
-
if ($closingParenthesis) {
|
33 |
-
$compiler->raw(')');
|
34 |
-
}
|
35 |
-
}
|
36 |
-
|
37 |
-
protected function compileArguments(Twig_Compiler $compiler)
|
38 |
-
{
|
39 |
-
$compiler->raw('(');
|
40 |
-
|
41 |
-
$first = true;
|
42 |
-
|
43 |
-
if ($this->hasAttribute('needs_environment') && $this->getAttribute('needs_environment')) {
|
44 |
-
$compiler->raw('$this->env');
|
45 |
-
$first = false;
|
46 |
-
}
|
47 |
-
|
48 |
-
if ($this->hasAttribute('needs_context') && $this->getAttribute('needs_context')) {
|
49 |
-
if (!$first) {
|
50 |
-
$compiler->raw(', ');
|
51 |
-
}
|
52 |
-
$compiler->raw('$context');
|
53 |
-
$first = false;
|
54 |
-
}
|
55 |
-
|
56 |
-
if ($this->hasAttribute('arguments')) {
|
57 |
-
foreach ($this->getAttribute('arguments') as $argument) {
|
58 |
-
if (!$first) {
|
59 |
-
$compiler->raw(', ');
|
60 |
-
}
|
61 |
-
$compiler->string($argument);
|
62 |
-
$first = false;
|
63 |
-
}
|
64 |
-
}
|
65 |
-
|
66 |
-
if ($this->hasNode('node')) {
|
67 |
-
if (!$first) {
|
68 |
-
$compiler->raw(', ');
|
69 |
-
}
|
70 |
-
$compiler->subcompile($this->getNode('node'));
|
71 |
-
$first = false;
|
72 |
-
}
|
73 |
-
|
74 |
-
if ($this->hasNode('arguments') && null !== $this->getNode('arguments')) {
|
75 |
-
$callable = $this->hasAttribute('callable') ? $this->getAttribute('callable') : null;
|
76 |
-
|
77 |
-
$arguments = $this->getArguments($callable, $this->getNode('arguments'));
|
78 |
-
|
79 |
-
foreach ($arguments as $node) {
|
80 |
-
if (!$first) {
|
81 |
-
$compiler->raw(', ');
|
82 |
-
}
|
83 |
-
$compiler->subcompile($node);
|
84 |
-
$first = false;
|
85 |
-
}
|
86 |
-
}
|
87 |
-
|
88 |
-
$compiler->raw(')');
|
89 |
-
}
|
90 |
-
|
91 |
-
protected function getArguments($callable, $arguments)
|
92 |
-
{
|
93 |
-
$parameters = array();
|
94 |
-
$named = false;
|
95 |
-
foreach ($arguments as $name => $node) {
|
96 |
-
if (!is_int($name)) {
|
97 |
-
$named = true;
|
98 |
-
$name = $this->normalizeName($name);
|
99 |
-
} elseif ($named) {
|
100 |
-
throw new Twig_Error_Syntax(sprintf('Positional arguments cannot be used after named arguments for %s "%s".', $this->getAttribute('type'), $this->getAttribute('name')));
|
101 |
-
}
|
102 |
-
|
103 |
-
$parameters[$name] = $node;
|
104 |
-
}
|
105 |
-
|
106 |
-
if (!$named) {
|
107 |
-
return $parameters;
|
108 |
-
}
|
109 |
-
|
110 |
-
if (!$callable) {
|
111 |
-
throw new LogicException(sprintf('Named arguments are not supported for %s "%s".', $this->getAttribute('type'), $this->getAttribute('name')));
|
112 |
-
}
|
113 |
-
|
114 |
-
// manage named arguments
|
115 |
-
if (is_array($callable)) {
|
116 |
-
$r = new ReflectionMethod($callable[0], $callable[1]);
|
117 |
-
} elseif (is_object($callable) && !$callable instanceof Closure) {
|
118 |
-
$r = new ReflectionObject($callable);
|
119 |
-
$r = $r->getMethod('__invoke');
|
120 |
-
} else {
|
121 |
-
$r = new ReflectionFunction($callable);
|
122 |
-
}
|
123 |
-
|
124 |
-
$definition = $r->getParameters();
|
125 |
-
if ($this->hasNode('node')) {
|
126 |
-
array_shift($definition);
|
127 |
-
}
|
128 |
-
if ($this->hasAttribute('needs_environment') && $this->getAttribute('needs_environment')) {
|
129 |
-
array_shift($definition);
|
130 |
-
}
|
131 |
-
if ($this->hasAttribute('needs_context') && $this->getAttribute('needs_context')) {
|
132 |
-
array_shift($definition);
|
133 |
-
}
|
134 |
-
if ($this->hasAttribute('arguments') && null !== $this->getAttribute('arguments')) {
|
135 |
-
foreach ($this->getAttribute('arguments') as $argument) {
|
136 |
-
array_shift($definition);
|
137 |
-
}
|
138 |
-
}
|
139 |
-
|
140 |
-
$arguments = array();
|
141 |
-
$pos = 0;
|
142 |
-
foreach ($definition as $param) {
|
143 |
-
$name = $this->normalizeName($param->name);
|
144 |
-
|
145 |
-
if (array_key_exists($name, $parameters)) {
|
146 |
-
if (array_key_exists($pos, $parameters)) {
|
147 |
-
throw new Twig_Error_Syntax(sprintf('Argument "%s" is defined twice for %s "%s".', $name, $this->getAttribute('type'), $this->getAttribute('name')));
|
148 |
-
}
|
149 |
-
|
150 |
-
$arguments[] = $parameters[$name];
|
151 |
-
unset($parameters[$name]);
|
152 |
-
} elseif (array_key_exists($pos, $parameters)) {
|
153 |
-
$arguments[] = $parameters[$pos];
|
154 |
-
unset($parameters[$pos]);
|
155 |
-
++$pos;
|
156 |
-
} elseif ($param->isDefaultValueAvailable()) {
|
157 |
-
$arguments[] = new Twig_Node_Expression_Constant($param->getDefaultValue(), -1);
|
158 |
-
} elseif ($param->isOptional()) {
|
159 |
-
break;
|
160 |
-
} else {
|
161 |
-
throw new Twig_Error_Syntax(sprintf('Value for argument "%s" is required for %s "%s".', $name, $this->getAttribute('type'), $this->getAttribute('name')));
|
162 |
-
}
|
163 |
-
}
|
164 |
-
|
165 |
-
if (!empty($parameters)) {
|
166 |
-
throw new Twig_Error_Syntax(sprintf('Unknown argument%s "%s" for %s "%s".', count($parameters) > 1 ? 's' : '', implode('", "', array_keys($parameters)), $this->getAttribute('type'), $this->getAttribute('name')));
|
167 |
-
}
|
168 |
-
|
169 |
-
return $arguments;
|
170 |
-
}
|
171 |
-
|
172 |
-
protected function normalizeName($name)
|
173 |
-
{
|
174 |
-
return strtolower(preg_replace(array('/([A-Z]+)([A-Z][a-z])/', '/([a-z\d])([A-Z])/'), array('\\1_\\2', '\\1_\\2'), $name));
|
175 |
-
}
|
176 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2012 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
abstract class Twig_Node_Expression_Call extends Twig_Node_Expression
|
12 |
+
{
|
13 |
+
protected function compileCallable(Twig_Compiler $compiler)
|
14 |
+
{
|
15 |
+
$closingParenthesis = false;
|
16 |
+
if ($this->hasAttribute('callable') && $callable = $this->getAttribute('callable')) {
|
17 |
+
if (is_string($callable)) {
|
18 |
+
$compiler->raw($callable);
|
19 |
+
} elseif (is_array($callable) && $callable[0] instanceof Twig_ExtensionInterface) {
|
20 |
+
$compiler->raw(sprintf('$this->env->getExtension(\'%s\')->%s', $callable[0]->getName(), $callable[1]));
|
21 |
+
} else {
|
22 |
+
$type = ucfirst($this->getAttribute('type'));
|
23 |
+
$compiler->raw(sprintf('call_user_func_array($this->env->get%s(\'%s\')->getCallable(), array', $type, $this->getAttribute('name')));
|
24 |
+
$closingParenthesis = true;
|
25 |
+
}
|
26 |
+
} else {
|
27 |
+
$compiler->raw($this->getAttribute('thing')->compile());
|
28 |
+
}
|
29 |
+
|
30 |
+
$this->compileArguments($compiler);
|
31 |
+
|
32 |
+
if ($closingParenthesis) {
|
33 |
+
$compiler->raw(')');
|
34 |
+
}
|
35 |
+
}
|
36 |
+
|
37 |
+
protected function compileArguments(Twig_Compiler $compiler)
|
38 |
+
{
|
39 |
+
$compiler->raw('(');
|
40 |
+
|
41 |
+
$first = true;
|
42 |
+
|
43 |
+
if ($this->hasAttribute('needs_environment') && $this->getAttribute('needs_environment')) {
|
44 |
+
$compiler->raw('$this->env');
|
45 |
+
$first = false;
|
46 |
+
}
|
47 |
+
|
48 |
+
if ($this->hasAttribute('needs_context') && $this->getAttribute('needs_context')) {
|
49 |
+
if (!$first) {
|
50 |
+
$compiler->raw(', ');
|
51 |
+
}
|
52 |
+
$compiler->raw('$context');
|
53 |
+
$first = false;
|
54 |
+
}
|
55 |
+
|
56 |
+
if ($this->hasAttribute('arguments')) {
|
57 |
+
foreach ($this->getAttribute('arguments') as $argument) {
|
58 |
+
if (!$first) {
|
59 |
+
$compiler->raw(', ');
|
60 |
+
}
|
61 |
+
$compiler->string($argument);
|
62 |
+
$first = false;
|
63 |
+
}
|
64 |
+
}
|
65 |
+
|
66 |
+
if ($this->hasNode('node')) {
|
67 |
+
if (!$first) {
|
68 |
+
$compiler->raw(', ');
|
69 |
+
}
|
70 |
+
$compiler->subcompile($this->getNode('node'));
|
71 |
+
$first = false;
|
72 |
+
}
|
73 |
+
|
74 |
+
if ($this->hasNode('arguments') && null !== $this->getNode('arguments')) {
|
75 |
+
$callable = $this->hasAttribute('callable') ? $this->getAttribute('callable') : null;
|
76 |
+
|
77 |
+
$arguments = $this->getArguments($callable, $this->getNode('arguments'));
|
78 |
+
|
79 |
+
foreach ($arguments as $node) {
|
80 |
+
if (!$first) {
|
81 |
+
$compiler->raw(', ');
|
82 |
+
}
|
83 |
+
$compiler->subcompile($node);
|
84 |
+
$first = false;
|
85 |
+
}
|
86 |
+
}
|
87 |
+
|
88 |
+
$compiler->raw(')');
|
89 |
+
}
|
90 |
+
|
91 |
+
protected function getArguments($callable, $arguments)
|
92 |
+
{
|
93 |
+
$parameters = array();
|
94 |
+
$named = false;
|
95 |
+
foreach ($arguments as $name => $node) {
|
96 |
+
if (!is_int($name)) {
|
97 |
+
$named = true;
|
98 |
+
$name = $this->normalizeName($name);
|
99 |
+
} elseif ($named) {
|
100 |
+
throw new Twig_Error_Syntax(sprintf('Positional arguments cannot be used after named arguments for %s "%s".', $this->getAttribute('type'), $this->getAttribute('name')));
|
101 |
+
}
|
102 |
+
|
103 |
+
$parameters[$name] = $node;
|
104 |
+
}
|
105 |
+
|
106 |
+
if (!$named) {
|
107 |
+
return $parameters;
|
108 |
+
}
|
109 |
+
|
110 |
+
if (!$callable) {
|
111 |
+
throw new LogicException(sprintf('Named arguments are not supported for %s "%s".', $this->getAttribute('type'), $this->getAttribute('name')));
|
112 |
+
}
|
113 |
+
|
114 |
+
// manage named arguments
|
115 |
+
if (is_array($callable)) {
|
116 |
+
$r = new ReflectionMethod($callable[0], $callable[1]);
|
117 |
+
} elseif (is_object($callable) && !$callable instanceof Closure) {
|
118 |
+
$r = new ReflectionObject($callable);
|
119 |
+
$r = $r->getMethod('__invoke');
|
120 |
+
} else {
|
121 |
+
$r = new ReflectionFunction($callable);
|
122 |
+
}
|
123 |
+
|
124 |
+
$definition = $r->getParameters();
|
125 |
+
if ($this->hasNode('node')) {
|
126 |
+
array_shift($definition);
|
127 |
+
}
|
128 |
+
if ($this->hasAttribute('needs_environment') && $this->getAttribute('needs_environment')) {
|
129 |
+
array_shift($definition);
|
130 |
+
}
|
131 |
+
if ($this->hasAttribute('needs_context') && $this->getAttribute('needs_context')) {
|
132 |
+
array_shift($definition);
|
133 |
+
}
|
134 |
+
if ($this->hasAttribute('arguments') && null !== $this->getAttribute('arguments')) {
|
135 |
+
foreach ($this->getAttribute('arguments') as $argument) {
|
136 |
+
array_shift($definition);
|
137 |
+
}
|
138 |
+
}
|
139 |
+
|
140 |
+
$arguments = array();
|
141 |
+
$pos = 0;
|
142 |
+
foreach ($definition as $param) {
|
143 |
+
$name = $this->normalizeName($param->name);
|
144 |
+
|
145 |
+
if (array_key_exists($name, $parameters)) {
|
146 |
+
if (array_key_exists($pos, $parameters)) {
|
147 |
+
throw new Twig_Error_Syntax(sprintf('Argument "%s" is defined twice for %s "%s".', $name, $this->getAttribute('type'), $this->getAttribute('name')));
|
148 |
+
}
|
149 |
+
|
150 |
+
$arguments[] = $parameters[$name];
|
151 |
+
unset($parameters[$name]);
|
152 |
+
} elseif (array_key_exists($pos, $parameters)) {
|
153 |
+
$arguments[] = $parameters[$pos];
|
154 |
+
unset($parameters[$pos]);
|
155 |
+
++$pos;
|
156 |
+
} elseif ($param->isDefaultValueAvailable()) {
|
157 |
+
$arguments[] = new Twig_Node_Expression_Constant($param->getDefaultValue(), -1);
|
158 |
+
} elseif ($param->isOptional()) {
|
159 |
+
break;
|
160 |
+
} else {
|
161 |
+
throw new Twig_Error_Syntax(sprintf('Value for argument "%s" is required for %s "%s".', $name, $this->getAttribute('type'), $this->getAttribute('name')));
|
162 |
+
}
|
163 |
+
}
|
164 |
+
|
165 |
+
if (!empty($parameters)) {
|
166 |
+
throw new Twig_Error_Syntax(sprintf('Unknown argument%s "%s" for %s "%s".', count($parameters) > 1 ? 's' : '', implode('", "', array_keys($parameters)), $this->getAttribute('type'), $this->getAttribute('name')));
|
167 |
+
}
|
168 |
+
|
169 |
+
return $arguments;
|
170 |
+
}
|
171 |
+
|
172 |
+
protected function normalizeName($name)
|
173 |
+
{
|
174 |
+
return strtolower(preg_replace(array('/([A-Z]+)([A-Z][a-z])/', '/([a-z\d])([A-Z])/'), array('\\1_\\2', '\\1_\\2'), $name));
|
175 |
+
}
|
176 |
+
}
|
classes/Twig/Node/Expression/Conditional.php
CHANGED
@@ -1,31 +1,31 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2009 Fabien Potencier
|
7 |
-
* (c) 2009 Armin Ronacher
|
8 |
-
*
|
9 |
-
* For the full copyright and license information, please view the LICENSE
|
10 |
-
* file that was distributed with this source code.
|
11 |
-
*/
|
12 |
-
class Twig_Node_Expression_Conditional extends Twig_Node_Expression
|
13 |
-
{
|
14 |
-
public function __construct(Twig_Node_Expression $expr1, Twig_Node_Expression $expr2, Twig_Node_Expression $expr3, $lineno)
|
15 |
-
{
|
16 |
-
parent::__construct(array('expr1' => $expr1, 'expr2' => $expr2, 'expr3' => $expr3), array(), $lineno);
|
17 |
-
}
|
18 |
-
|
19 |
-
public function compile(Twig_Compiler $compiler)
|
20 |
-
{
|
21 |
-
$compiler
|
22 |
-
->raw('((')
|
23 |
-
->subcompile($this->getNode('expr1'))
|
24 |
-
->raw(') ? (')
|
25 |
-
->subcompile($this->getNode('expr2'))
|
26 |
-
->raw(') : (')
|
27 |
-
->subcompile($this->getNode('expr3'))
|
28 |
-
->raw('))')
|
29 |
-
;
|
30 |
-
}
|
31 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2009 Fabien Potencier
|
7 |
+
* (c) 2009 Armin Ronacher
|
8 |
+
*
|
9 |
+
* For the full copyright and license information, please view the LICENSE
|
10 |
+
* file that was distributed with this source code.
|
11 |
+
*/
|
12 |
+
class Twig_Node_Expression_Conditional extends Twig_Node_Expression
|
13 |
+
{
|
14 |
+
public function __construct(Twig_Node_Expression $expr1, Twig_Node_Expression $expr2, Twig_Node_Expression $expr3, $lineno)
|
15 |
+
{
|
16 |
+
parent::__construct(array('expr1' => $expr1, 'expr2' => $expr2, 'expr3' => $expr3), array(), $lineno);
|
17 |
+
}
|
18 |
+
|
19 |
+
public function compile(Twig_Compiler $compiler)
|
20 |
+
{
|
21 |
+
$compiler
|
22 |
+
->raw('((')
|
23 |
+
->subcompile($this->getNode('expr1'))
|
24 |
+
->raw(') ? (')
|
25 |
+
->subcompile($this->getNode('expr2'))
|
26 |
+
->raw(') : (')
|
27 |
+
->subcompile($this->getNode('expr3'))
|
28 |
+
->raw('))')
|
29 |
+
;
|
30 |
+
}
|
31 |
+
}
|
classes/Twig/Node/Expression/Constant.php
CHANGED
@@ -1,23 +1,23 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2009 Fabien Potencier
|
7 |
-
* (c) 2009 Armin Ronacher
|
8 |
-
*
|
9 |
-
* For the full copyright and license information, please view the LICENSE
|
10 |
-
* file that was distributed with this source code.
|
11 |
-
*/
|
12 |
-
class Twig_Node_Expression_Constant extends Twig_Node_Expression
|
13 |
-
{
|
14 |
-
public function __construct($value, $lineno)
|
15 |
-
{
|
16 |
-
parent::__construct(array(), array('value' => $value), $lineno);
|
17 |
-
}
|
18 |
-
|
19 |
-
public function compile(Twig_Compiler $compiler)
|
20 |
-
{
|
21 |
-
$compiler->repr($this->getAttribute('value'));
|
22 |
-
}
|
23 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2009 Fabien Potencier
|
7 |
+
* (c) 2009 Armin Ronacher
|
8 |
+
*
|
9 |
+
* For the full copyright and license information, please view the LICENSE
|
10 |
+
* file that was distributed with this source code.
|
11 |
+
*/
|
12 |
+
class Twig_Node_Expression_Constant extends Twig_Node_Expression
|
13 |
+
{
|
14 |
+
public function __construct($value, $lineno)
|
15 |
+
{
|
16 |
+
parent::__construct(array(), array('value' => $value), $lineno);
|
17 |
+
}
|
18 |
+
|
19 |
+
public function compile(Twig_Compiler $compiler)
|
20 |
+
{
|
21 |
+
$compiler->repr($this->getAttribute('value'));
|
22 |
+
}
|
23 |
+
}
|
classes/Twig/Node/Expression/ExtensionReference.php
CHANGED
@@ -1,33 +1,33 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2009 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
/**
|
13 |
-
* Represents an extension call node.
|
14 |
-
*
|
15 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
16 |
-
*/
|
17 |
-
class Twig_Node_Expression_ExtensionReference extends Twig_Node_Expression
|
18 |
-
{
|
19 |
-
public function __construct($name, $lineno, $tag = null)
|
20 |
-
{
|
21 |
-
parent::__construct(array(), array('name' => $name), $lineno, $tag);
|
22 |
-
}
|
23 |
-
|
24 |
-
/**
|
25 |
-
* Compiles the node to PHP.
|
26 |
-
*
|
27 |
-
* @param Twig_Compiler A Twig_Compiler instance
|
28 |
-
*/
|
29 |
-
public function compile(Twig_Compiler $compiler)
|
30 |
-
{
|
31 |
-
$compiler->raw(sprintf("\$this->env->getExtension('%s')", $this->getAttribute('name')));
|
32 |
-
}
|
33 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2009 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Represents an extension call node.
|
14 |
+
*
|
15 |
+
* @author Fabien Potencier <fabien@symfony.com>
|
16 |
+
*/
|
17 |
+
class Twig_Node_Expression_ExtensionReference extends Twig_Node_Expression
|
18 |
+
{
|
19 |
+
public function __construct($name, $lineno, $tag = null)
|
20 |
+
{
|
21 |
+
parent::__construct(array(), array('name' => $name), $lineno, $tag);
|
22 |
+
}
|
23 |
+
|
24 |
+
/**
|
25 |
+
* Compiles the node to PHP.
|
26 |
+
*
|
27 |
+
* @param Twig_Compiler A Twig_Compiler instance
|
28 |
+
*/
|
29 |
+
public function compile(Twig_Compiler $compiler)
|
30 |
+
{
|
31 |
+
$compiler->raw(sprintf("\$this->env->getExtension('%s')", $this->getAttribute('name')));
|
32 |
+
}
|
33 |
+
}
|
classes/Twig/Node/Expression/Filter.php
CHANGED
@@ -1,36 +1,36 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2009 Fabien Potencier
|
7 |
-
* (c) 2009 Armin Ronacher
|
8 |
-
*
|
9 |
-
* For the full copyright and license information, please view the LICENSE
|
10 |
-
* file that was distributed with this source code.
|
11 |
-
*/
|
12 |
-
class Twig_Node_Expression_Filter extends Twig_Node_Expression_Call
|
13 |
-
{
|
14 |
-
public function __construct(Twig_NodeInterface $node, Twig_Node_Expression_Constant $filterName, Twig_NodeInterface $arguments, $lineno, $tag = null)
|
15 |
-
{
|
16 |
-
parent::__construct(array('node' => $node, 'filter' => $filterName, 'arguments' => $arguments), array(), $lineno, $tag);
|
17 |
-
}
|
18 |
-
|
19 |
-
public function compile(Twig_Compiler $compiler)
|
20 |
-
{
|
21 |
-
$name = $this->getNode('filter')->getAttribute('value');
|
22 |
-
$filter = $compiler->getEnvironment()->getFilter($name);
|
23 |
-
|
24 |
-
$this->setAttribute('name', $name);
|
25 |
-
$this->setAttribute('type', 'filter');
|
26 |
-
$this->setAttribute('thing', $filter);
|
27 |
-
$this->setAttribute('needs_environment', $filter->needsEnvironment());
|
28 |
-
$this->setAttribute('needs_context', $filter->needsContext());
|
29 |
-
$this->setAttribute('arguments', $filter->getArguments());
|
30 |
-
if ($filter instanceof Twig_FilterCallableInterface || $filter instanceof Twig_SimpleFilter) {
|
31 |
-
$this->setAttribute('callable', $filter->getCallable());
|
32 |
-
}
|
33 |
-
|
34 |
-
$this->compileCallable($compiler);
|
35 |
-
}
|
36 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2009 Fabien Potencier
|
7 |
+
* (c) 2009 Armin Ronacher
|
8 |
+
*
|
9 |
+
* For the full copyright and license information, please view the LICENSE
|
10 |
+
* file that was distributed with this source code.
|
11 |
+
*/
|
12 |
+
class Twig_Node_Expression_Filter extends Twig_Node_Expression_Call
|
13 |
+
{
|
14 |
+
public function __construct(Twig_NodeInterface $node, Twig_Node_Expression_Constant $filterName, Twig_NodeInterface $arguments, $lineno, $tag = null)
|
15 |
+
{
|
16 |
+
parent::__construct(array('node' => $node, 'filter' => $filterName, 'arguments' => $arguments), array(), $lineno, $tag);
|
17 |
+
}
|
18 |
+
|
19 |
+
public function compile(Twig_Compiler $compiler)
|
20 |
+
{
|
21 |
+
$name = $this->getNode('filter')->getAttribute('value');
|
22 |
+
$filter = $compiler->getEnvironment()->getFilter($name);
|
23 |
+
|
24 |
+
$this->setAttribute('name', $name);
|
25 |
+
$this->setAttribute('type', 'filter');
|
26 |
+
$this->setAttribute('thing', $filter);
|
27 |
+
$this->setAttribute('needs_environment', $filter->needsEnvironment());
|
28 |
+
$this->setAttribute('needs_context', $filter->needsContext());
|
29 |
+
$this->setAttribute('arguments', $filter->getArguments());
|
30 |
+
if ($filter instanceof Twig_FilterCallableInterface || $filter instanceof Twig_SimpleFilter) {
|
31 |
+
$this->setAttribute('callable', $filter->getCallable());
|
32 |
+
}
|
33 |
+
|
34 |
+
$this->compileCallable($compiler);
|
35 |
+
}
|
36 |
+
}
|
classes/Twig/Node/Expression/Filter/Default.php
CHANGED
@@ -1,43 +1,43 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2011 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
/**
|
13 |
-
* Returns the value or the default value when it is undefined or empty.
|
14 |
-
*
|
15 |
-
* <pre>
|
16 |
-
* {{ var.foo|default('foo item on var is not defined') }}
|
17 |
-
* </pre>
|
18 |
-
*
|
19 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
20 |
-
*/
|
21 |
-
class Twig_Node_Expression_Filter_Default extends Twig_Node_Expression_Filter
|
22 |
-
{
|
23 |
-
public function __construct(Twig_NodeInterface $node, Twig_Node_Expression_Constant $filterName, Twig_NodeInterface $arguments, $lineno, $tag = null)
|
24 |
-
{
|
25 |
-
$default = new Twig_Node_Expression_Filter($node, new Twig_Node_Expression_Constant('default', $node->getLine()), $arguments, $node->getLine());
|
26 |
-
|
27 |
-
if ('default' === $filterName->getAttribute('value') && ($node instanceof Twig_Node_Expression_Name || $node instanceof Twig_Node_Expression_GetAttr)) {
|
28 |
-
$test = new Twig_Node_Expression_Test_Defined(clone $node, 'defined', new Twig_Node(), $node->getLine());
|
29 |
-
$false = count($arguments) ? $arguments->getNode(0) : new Twig_Node_Expression_Constant('', $node->getLine());
|
30 |
-
|
31 |
-
$node = new Twig_Node_Expression_Conditional($test, $default, $false, $node->getLine());
|
32 |
-
} else {
|
33 |
-
$node = $default;
|
34 |
-
}
|
35 |
-
|
36 |
-
parent::__construct($node, $filterName, $arguments, $lineno, $tag);
|
37 |
-
}
|
38 |
-
|
39 |
-
public function compile(Twig_Compiler $compiler)
|
40 |
-
{
|
41 |
-
$compiler->subcompile($this->getNode('node'));
|
42 |
-
}
|
43 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2011 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Returns the value or the default value when it is undefined or empty.
|
14 |
+
*
|
15 |
+
* <pre>
|
16 |
+
* {{ var.foo|default('foo item on var is not defined') }}
|
17 |
+
* </pre>
|
18 |
+
*
|
19 |
+
* @author Fabien Potencier <fabien@symfony.com>
|
20 |
+
*/
|
21 |
+
class Twig_Node_Expression_Filter_Default extends Twig_Node_Expression_Filter
|
22 |
+
{
|
23 |
+
public function __construct(Twig_NodeInterface $node, Twig_Node_Expression_Constant $filterName, Twig_NodeInterface $arguments, $lineno, $tag = null)
|
24 |
+
{
|
25 |
+
$default = new Twig_Node_Expression_Filter($node, new Twig_Node_Expression_Constant('default', $node->getLine()), $arguments, $node->getLine());
|
26 |
+
|
27 |
+
if ('default' === $filterName->getAttribute('value') && ($node instanceof Twig_Node_Expression_Name || $node instanceof Twig_Node_Expression_GetAttr)) {
|
28 |
+
$test = new Twig_Node_Expression_Test_Defined(clone $node, 'defined', new Twig_Node(), $node->getLine());
|
29 |
+
$false = count($arguments) ? $arguments->getNode(0) : new Twig_Node_Expression_Constant('', $node->getLine());
|
30 |
+
|
31 |
+
$node = new Twig_Node_Expression_Conditional($test, $default, $false, $node->getLine());
|
32 |
+
} else {
|
33 |
+
$node = $default;
|
34 |
+
}
|
35 |
+
|
36 |
+
parent::__construct($node, $filterName, $arguments, $lineno, $tag);
|
37 |
+
}
|
38 |
+
|
39 |
+
public function compile(Twig_Compiler $compiler)
|
40 |
+
{
|
41 |
+
$compiler->subcompile($this->getNode('node'));
|
42 |
+
}
|
43 |
+
}
|
classes/Twig/Node/Expression/Function.php
CHANGED
@@ -1,35 +1,35 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2010 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
class Twig_Node_Expression_Function extends Twig_Node_Expression_Call
|
12 |
-
{
|
13 |
-
public function __construct($name, Twig_NodeInterface $arguments, $lineno)
|
14 |
-
{
|
15 |
-
parent::__construct(array('arguments' => $arguments), array('name' => $name), $lineno);
|
16 |
-
}
|
17 |
-
|
18 |
-
public function compile(Twig_Compiler $compiler)
|
19 |
-
{
|
20 |
-
$name = $this->getAttribute('name');
|
21 |
-
$function = $compiler->getEnvironment()->getFunction($name);
|
22 |
-
|
23 |
-
$this->setAttribute('name', $name);
|
24 |
-
$this->setAttribute('type', 'function');
|
25 |
-
$this->setAttribute('thing', $function);
|
26 |
-
$this->setAttribute('needs_environment', $function->needsEnvironment());
|
27 |
-
$this->setAttribute('needs_context', $function->needsContext());
|
28 |
-
$this->setAttribute('arguments', $function->getArguments());
|
29 |
-
if ($function instanceof Twig_FunctionCallableInterface || $function instanceof Twig_SimpleFunction) {
|
30 |
-
$this->setAttribute('callable', $function->getCallable());
|
31 |
-
}
|
32 |
-
|
33 |
-
$this->compileCallable($compiler);
|
34 |
-
}
|
35 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2010 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
class Twig_Node_Expression_Function extends Twig_Node_Expression_Call
|
12 |
+
{
|
13 |
+
public function __construct($name, Twig_NodeInterface $arguments, $lineno)
|
14 |
+
{
|
15 |
+
parent::__construct(array('arguments' => $arguments), array('name' => $name), $lineno);
|
16 |
+
}
|
17 |
+
|
18 |
+
public function compile(Twig_Compiler $compiler)
|
19 |
+
{
|
20 |
+
$name = $this->getAttribute('name');
|
21 |
+
$function = $compiler->getEnvironment()->getFunction($name);
|
22 |
+
|
23 |
+
$this->setAttribute('name', $name);
|
24 |
+
$this->setAttribute('type', 'function');
|
25 |
+
$this->setAttribute('thing', $function);
|
26 |
+
$this->setAttribute('needs_environment', $function->needsEnvironment());
|
27 |
+
$this->setAttribute('needs_context', $function->needsContext());
|
28 |
+
$this->setAttribute('arguments', $function->getArguments());
|
29 |
+
if ($function instanceof Twig_FunctionCallableInterface || $function instanceof Twig_SimpleFunction) {
|
30 |
+
$this->setAttribute('callable', $function->getCallable());
|
31 |
+
}
|
32 |
+
|
33 |
+
$this->compileCallable($compiler);
|
34 |
+
}
|
35 |
+
}
|
classes/Twig/Node/Expression/GetAttr.php
CHANGED
@@ -1,53 +1,53 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2009 Fabien Potencier
|
7 |
-
* (c) 2009 Armin Ronacher
|
8 |
-
*
|
9 |
-
* For the full copyright and license information, please view the LICENSE
|
10 |
-
* file that was distributed with this source code.
|
11 |
-
*/
|
12 |
-
class Twig_Node_Expression_GetAttr extends Twig_Node_Expression
|
13 |
-
{
|
14 |
-
public function __construct(Twig_Node_Expression $node, Twig_Node_Expression $attribute, Twig_Node_Expression_Array $arguments, $type, $lineno)
|
15 |
-
{
|
16 |
-
parent::__construct(array('node' => $node, 'attribute' => $attribute, 'arguments' => $arguments), array('type' => $type, 'is_defined_test' => false, 'ignore_strict_check' => false, 'disable_c_ext' => false), $lineno);
|
17 |
-
}
|
18 |
-
|
19 |
-
public function compile(Twig_Compiler $compiler)
|
20 |
-
{
|
21 |
-
if (function_exists('twig_template_get_attributes') && !$this->getAttribute('disable_c_ext')) {
|
22 |
-
$compiler->raw('twig_template_get_attributes($this, ');
|
23 |
-
} else {
|
24 |
-
$compiler->raw('$this->getAttribute(');
|
25 |
-
}
|
26 |
-
|
27 |
-
if ($this->getAttribute('ignore_strict_check')) {
|
28 |
-
$this->getNode('node')->setAttribute('ignore_strict_check', true);
|
29 |
-
}
|
30 |
-
|
31 |
-
$compiler->subcompile($this->getNode('node'));
|
32 |
-
|
33 |
-
$compiler->raw(', ')->subcompile($this->getNode('attribute'));
|
34 |
-
|
35 |
-
if (count($this->getNode('arguments')) || Twig_Template::ANY_CALL !== $this->getAttribute('type') || $this->getAttribute('is_defined_test') || $this->getAttribute('ignore_strict_check')) {
|
36 |
-
$compiler->raw(', ')->subcompile($this->getNode('arguments'));
|
37 |
-
|
38 |
-
if (Twig_Template::ANY_CALL !== $this->getAttribute('type') || $this->getAttribute('is_defined_test') || $this->getAttribute('ignore_strict_check')) {
|
39 |
-
$compiler->raw(', ')->repr($this->getAttribute('type'));
|
40 |
-
}
|
41 |
-
|
42 |
-
if ($this->getAttribute('is_defined_test') || $this->getAttribute('ignore_strict_check')) {
|
43 |
-
$compiler->raw(', '.($this->getAttribute('is_defined_test') ? 'true' : 'false'));
|
44 |
-
}
|
45 |
-
|
46 |
-
if ($this->getAttribute('ignore_strict_check')) {
|
47 |
-
$compiler->raw(', '.($this->getAttribute('ignore_strict_check') ? 'true' : 'false'));
|
48 |
-
}
|
49 |
-
}
|
50 |
-
|
51 |
-
$compiler->raw(')');
|
52 |
-
}
|
53 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2009 Fabien Potencier
|
7 |
+
* (c) 2009 Armin Ronacher
|
8 |
+
*
|
9 |
+
* For the full copyright and license information, please view the LICENSE
|
10 |
+
* file that was distributed with this source code.
|
11 |
+
*/
|
12 |
+
class Twig_Node_Expression_GetAttr extends Twig_Node_Expression
|
13 |
+
{
|
14 |
+
public function __construct(Twig_Node_Expression $node, Twig_Node_Expression $attribute, Twig_Node_Expression_Array $arguments, $type, $lineno)
|
15 |
+
{
|
16 |
+
parent::__construct(array('node' => $node, 'attribute' => $attribute, 'arguments' => $arguments), array('type' => $type, 'is_defined_test' => false, 'ignore_strict_check' => false, 'disable_c_ext' => false), $lineno);
|
17 |
+
}
|
18 |
+
|
19 |
+
public function compile(Twig_Compiler $compiler)
|
20 |
+
{
|
21 |
+
if (function_exists('twig_template_get_attributes') && !$this->getAttribute('disable_c_ext')) {
|
22 |
+
$compiler->raw('twig_template_get_attributes($this, ');
|
23 |
+
} else {
|
24 |
+
$compiler->raw('$this->getAttribute(');
|
25 |
+
}
|
26 |
+
|
27 |
+
if ($this->getAttribute('ignore_strict_check')) {
|
28 |
+
$this->getNode('node')->setAttribute('ignore_strict_check', true);
|
29 |
+
}
|
30 |
+
|
31 |
+
$compiler->subcompile($this->getNode('node'));
|
32 |
+
|
33 |
+
$compiler->raw(', ')->subcompile($this->getNode('attribute'));
|
34 |
+
|
35 |
+
if (count($this->getNode('arguments')) || Twig_Template::ANY_CALL !== $this->getAttribute('type') || $this->getAttribute('is_defined_test') || $this->getAttribute('ignore_strict_check')) {
|
36 |
+
$compiler->raw(', ')->subcompile($this->getNode('arguments'));
|
37 |
+
|
38 |
+
if (Twig_Template::ANY_CALL !== $this->getAttribute('type') || $this->getAttribute('is_defined_test') || $this->getAttribute('ignore_strict_check')) {
|
39 |
+
$compiler->raw(', ')->repr($this->getAttribute('type'));
|
40 |
+
}
|
41 |
+
|
42 |
+
if ($this->getAttribute('is_defined_test') || $this->getAttribute('ignore_strict_check')) {
|
43 |
+
$compiler->raw(', '.($this->getAttribute('is_defined_test') ? 'true' : 'false'));
|
44 |
+
}
|
45 |
+
|
46 |
+
if ($this->getAttribute('ignore_strict_check')) {
|
47 |
+
$compiler->raw(', '.($this->getAttribute('ignore_strict_check') ? 'true' : 'false'));
|
48 |
+
}
|
49 |
+
}
|
50 |
+
|
51 |
+
$compiler->raw(')');
|
52 |
+
}
|
53 |
+
}
|
classes/Twig/Node/Expression/MethodCall.php
CHANGED
@@ -1,41 +1,41 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2012 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
class Twig_Node_Expression_MethodCall extends Twig_Node_Expression
|
12 |
-
{
|
13 |
-
public function __construct(Twig_Node_Expression $node, $method, Twig_Node_Expression_Array $arguments, $lineno)
|
14 |
-
{
|
15 |
-
parent::__construct(array('node' => $node, 'arguments' => $arguments), array('method' => $method, 'safe' => false), $lineno);
|
16 |
-
|
17 |
-
if ($node instanceof Twig_Node_Expression_Name) {
|
18 |
-
$node->setAttribute('always_defined', true);
|
19 |
-
}
|
20 |
-
}
|
21 |
-
|
22 |
-
public function compile(Twig_Compiler $compiler)
|
23 |
-
{
|
24 |
-
$compiler
|
25 |
-
->subcompile($this->getNode('node'))
|
26 |
-
->raw('->')
|
27 |
-
->raw($this->getAttribute('method'))
|
28 |
-
->raw('(')
|
29 |
-
;
|
30 |
-
$first = true;
|
31 |
-
foreach ($this->getNode('arguments')->getKeyValuePairs() as $pair) {
|
32 |
-
if (!$first) {
|
33 |
-
$compiler->raw(', ');
|
34 |
-
}
|
35 |
-
$first = false;
|
36 |
-
|
37 |
-
$compiler->subcompile($pair['value']);
|
38 |
-
}
|
39 |
-
$compiler->raw(')');
|
40 |
-
}
|
41 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2012 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
class Twig_Node_Expression_MethodCall extends Twig_Node_Expression
|
12 |
+
{
|
13 |
+
public function __construct(Twig_Node_Expression $node, $method, Twig_Node_Expression_Array $arguments, $lineno)
|
14 |
+
{
|
15 |
+
parent::__construct(array('node' => $node, 'arguments' => $arguments), array('method' => $method, 'safe' => false), $lineno);
|
16 |
+
|
17 |
+
if ($node instanceof Twig_Node_Expression_Name) {
|
18 |
+
$node->setAttribute('always_defined', true);
|
19 |
+
}
|
20 |
+
}
|
21 |
+
|
22 |
+
public function compile(Twig_Compiler $compiler)
|
23 |
+
{
|
24 |
+
$compiler
|
25 |
+
->subcompile($this->getNode('node'))
|
26 |
+
->raw('->')
|
27 |
+
->raw($this->getAttribute('method'))
|
28 |
+
->raw('(')
|
29 |
+
;
|
30 |
+
$first = true;
|
31 |
+
foreach ($this->getNode('arguments')->getKeyValuePairs() as $pair) {
|
32 |
+
if (!$first) {
|
33 |
+
$compiler->raw(', ');
|
34 |
+
}
|
35 |
+
$first = false;
|
36 |
+
|
37 |
+
$compiler->subcompile($pair['value']);
|
38 |
+
}
|
39 |
+
$compiler->raw(')');
|
40 |
+
}
|
41 |
+
}
|
classes/Twig/Node/Expression/Name.php
CHANGED
@@ -1,88 +1,88 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2009 Fabien Potencier
|
7 |
-
* (c) 2009 Armin Ronacher
|
8 |
-
*
|
9 |
-
* For the full copyright and license information, please view the LICENSE
|
10 |
-
* file that was distributed with this source code.
|
11 |
-
*/
|
12 |
-
class Twig_Node_Expression_Name extends Twig_Node_Expression
|
13 |
-
{
|
14 |
-
protected $specialVars = array(
|
15 |
-
'_self' => '$this',
|
16 |
-
'_context' => '$context',
|
17 |
-
'_charset' => '$this->env->getCharset()',
|
18 |
-
);
|
19 |
-
|
20 |
-
public function __construct($name, $lineno)
|
21 |
-
{
|
22 |
-
parent::__construct(array(), array('name' => $name, 'is_defined_test' => false, 'ignore_strict_check' => false, 'always_defined' => false), $lineno);
|
23 |
-
}
|
24 |
-
|
25 |
-
public function compile(Twig_Compiler $compiler)
|
26 |
-
{
|
27 |
-
$name = $this->getAttribute('name');
|
28 |
-
|
29 |
-
if ($this->getAttribute('is_defined_test')) {
|
30 |
-
if ($this->isSpecial()) {
|
31 |
-
$compiler->repr(true);
|
32 |
-
} else {
|
33 |
-
$compiler->raw('array_key_exists(')->repr($name)->raw(', $context)');
|
34 |
-
}
|
35 |
-
} elseif ($this->isSpecial()) {
|
36 |
-
$compiler->raw($this->specialVars[$name]);
|
37 |
-
} elseif ($this->getAttribute('always_defined')) {
|
38 |
-
$compiler
|
39 |
-
->raw('$context[')
|
40 |
-
->string($name)
|
41 |
-
->raw(']')
|
42 |
-
;
|
43 |
-
} else {
|
44 |
-
// remove the non-PHP 5.4 version when PHP 5.3 support is dropped
|
45 |
-
// as the non-optimized version is just a workaround for slow ternary operator
|
46 |
-
// when the context has a lot of variables
|
47 |
-
if (version_compare(phpversion(), '5.4.0RC1', '>=')) {
|
48 |
-
// PHP 5.4 ternary operator performance was optimized
|
49 |
-
$compiler
|
50 |
-
->raw('(isset($context[')
|
51 |
-
->string($name)
|
52 |
-
->raw(']) ? $context[')
|
53 |
-
->string($name)
|
54 |
-
->raw('] : ')
|
55 |
-
;
|
56 |
-
|
57 |
-
if ($this->getAttribute('ignore_strict_check') || !$compiler->getEnvironment()->isStrictVariables()) {
|
58 |
-
$compiler->raw('null)');
|
59 |
-
} else {
|
60 |
-
$compiler->raw('$this->getContext($context, ')->string($name)->raw('))');
|
61 |
-
}
|
62 |
-
} else {
|
63 |
-
$compiler
|
64 |
-
->raw('$this->getContext($context, ')
|
65 |
-
->string($name)
|
66 |
-
;
|
67 |
-
|
68 |
-
if ($this->getAttribute('ignore_strict_check')) {
|
69 |
-
$compiler->raw(', true');
|
70 |
-
}
|
71 |
-
|
72 |
-
$compiler
|
73 |
-
->raw(')')
|
74 |
-
;
|
75 |
-
}
|
76 |
-
}
|
77 |
-
}
|
78 |
-
|
79 |
-
public function isSpecial()
|
80 |
-
{
|
81 |
-
return isset($this->specialVars[$this->getAttribute('name')]);
|
82 |
-
}
|
83 |
-
|
84 |
-
public function isSimple()
|
85 |
-
{
|
86 |
-
return !$this->isSpecial() && !$this->getAttribute('is_defined_test');
|
87 |
-
}
|
88 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2009 Fabien Potencier
|
7 |
+
* (c) 2009 Armin Ronacher
|
8 |
+
*
|
9 |
+
* For the full copyright and license information, please view the LICENSE
|
10 |
+
* file that was distributed with this source code.
|
11 |
+
*/
|
12 |
+
class Twig_Node_Expression_Name extends Twig_Node_Expression
|
13 |
+
{
|
14 |
+
protected $specialVars = array(
|
15 |
+
'_self' => '$this',
|
16 |
+
'_context' => '$context',
|
17 |
+
'_charset' => '$this->env->getCharset()',
|
18 |
+
);
|
19 |
+
|
20 |
+
public function __construct($name, $lineno)
|
21 |
+
{
|
22 |
+
parent::__construct(array(), array('name' => $name, 'is_defined_test' => false, 'ignore_strict_check' => false, 'always_defined' => false), $lineno);
|
23 |
+
}
|
24 |
+
|
25 |
+
public function compile(Twig_Compiler $compiler)
|
26 |
+
{
|
27 |
+
$name = $this->getAttribute('name');
|
28 |
+
|
29 |
+
if ($this->getAttribute('is_defined_test')) {
|
30 |
+
if ($this->isSpecial()) {
|
31 |
+
$compiler->repr(true);
|
32 |
+
} else {
|
33 |
+
$compiler->raw('array_key_exists(')->repr($name)->raw(', $context)');
|
34 |
+
}
|
35 |
+
} elseif ($this->isSpecial()) {
|
36 |
+
$compiler->raw($this->specialVars[$name]);
|
37 |
+
} elseif ($this->getAttribute('always_defined')) {
|
38 |
+
$compiler
|
39 |
+
->raw('$context[')
|
40 |
+
->string($name)
|
41 |
+
->raw(']')
|
42 |
+
;
|
43 |
+
} else {
|
44 |
+
// remove the non-PHP 5.4 version when PHP 5.3 support is dropped
|
45 |
+
// as the non-optimized version is just a workaround for slow ternary operator
|
46 |
+
// when the context has a lot of variables
|
47 |
+
if (version_compare(phpversion(), '5.4.0RC1', '>=')) {
|
48 |
+
// PHP 5.4 ternary operator performance was optimized
|
49 |
+
$compiler
|
50 |
+
->raw('(isset($context[')
|
51 |
+
->string($name)
|
52 |
+
->raw(']) ? $context[')
|
53 |
+
->string($name)
|
54 |
+
->raw('] : ')
|
55 |
+
;
|
56 |
+
|
57 |
+
if ($this->getAttribute('ignore_strict_check') || !$compiler->getEnvironment()->isStrictVariables()) {
|
58 |
+
$compiler->raw('null)');
|
59 |
+
} else {
|
60 |
+
$compiler->raw('$this->getContext($context, ')->string($name)->raw('))');
|
61 |
+
}
|
62 |
+
} else {
|
63 |
+
$compiler
|
64 |
+
->raw('$this->getContext($context, ')
|
65 |
+
->string($name)
|
66 |
+
;
|
67 |
+
|
68 |
+
if ($this->getAttribute('ignore_strict_check')) {
|
69 |
+
$compiler->raw(', true');
|
70 |
+
}
|
71 |
+
|
72 |
+
$compiler
|
73 |
+
->raw(')')
|
74 |
+
;
|
75 |
+
}
|
76 |
+
}
|
77 |
+
}
|
78 |
+
|
79 |
+
public function isSpecial()
|
80 |
+
{
|
81 |
+
return isset($this->specialVars[$this->getAttribute('name')]);
|
82 |
+
}
|
83 |
+
|
84 |
+
public function isSimple()
|
85 |
+
{
|
86 |
+
return !$this->isSpecial() && !$this->getAttribute('is_defined_test');
|
87 |
+
}
|
88 |
+
}
|
classes/Twig/Node/Expression/Parent.php
CHANGED
@@ -1,47 +1,47 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2009 Fabien Potencier
|
7 |
-
* (c) 2009 Armin Ronacher
|
8 |
-
*
|
9 |
-
* For the full copyright and license information, please view the LICENSE
|
10 |
-
* file that was distributed with this source code.
|
11 |
-
*/
|
12 |
-
|
13 |
-
/**
|
14 |
-
* Represents a parent node.
|
15 |
-
*
|
16 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
17 |
-
*/
|
18 |
-
class Twig_Node_Expression_Parent extends Twig_Node_Expression
|
19 |
-
{
|
20 |
-
public function __construct($name, $lineno, $tag = null)
|
21 |
-
{
|
22 |
-
parent::__construct(array(), array('output' => false, 'name' => $name), $lineno, $tag);
|
23 |
-
}
|
24 |
-
|
25 |
-
/**
|
26 |
-
* Compiles the node to PHP.
|
27 |
-
*
|
28 |
-
* @param Twig_Compiler A Twig_Compiler instance
|
29 |
-
*/
|
30 |
-
public function compile(Twig_Compiler $compiler)
|
31 |
-
{
|
32 |
-
if ($this->getAttribute('output')) {
|
33 |
-
$compiler
|
34 |
-
->addDebugInfo($this)
|
35 |
-
->write("\$this->displayParentBlock(")
|
36 |
-
->string($this->getAttribute('name'))
|
37 |
-
->raw(", \$context, \$blocks);\n")
|
38 |
-
;
|
39 |
-
} else {
|
40 |
-
$compiler
|
41 |
-
->raw("\$this->renderParentBlock(")
|
42 |
-
->string($this->getAttribute('name'))
|
43 |
-
->raw(", \$context, \$blocks)")
|
44 |
-
;
|
45 |
-
}
|
46 |
-
}
|
47 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2009 Fabien Potencier
|
7 |
+
* (c) 2009 Armin Ronacher
|
8 |
+
*
|
9 |
+
* For the full copyright and license information, please view the LICENSE
|
10 |
+
* file that was distributed with this source code.
|
11 |
+
*/
|
12 |
+
|
13 |
+
/**
|
14 |
+
* Represents a parent node.
|
15 |
+
*
|
16 |
+
* @author Fabien Potencier <fabien@symfony.com>
|
17 |
+
*/
|
18 |
+
class Twig_Node_Expression_Parent extends Twig_Node_Expression
|
19 |
+
{
|
20 |
+
public function __construct($name, $lineno, $tag = null)
|
21 |
+
{
|
22 |
+
parent::__construct(array(), array('output' => false, 'name' => $name), $lineno, $tag);
|
23 |
+
}
|
24 |
+
|
25 |
+
/**
|
26 |
+
* Compiles the node to PHP.
|
27 |
+
*
|
28 |
+
* @param Twig_Compiler A Twig_Compiler instance
|
29 |
+
*/
|
30 |
+
public function compile(Twig_Compiler $compiler)
|
31 |
+
{
|
32 |
+
if ($this->getAttribute('output')) {
|
33 |
+
$compiler
|
34 |
+
->addDebugInfo($this)
|
35 |
+
->write("\$this->displayParentBlock(")
|
36 |
+
->string($this->getAttribute('name'))
|
37 |
+
->raw(", \$context, \$blocks);\n")
|
38 |
+
;
|
39 |
+
} else {
|
40 |
+
$compiler
|
41 |
+
->raw("\$this->renderParentBlock(")
|
42 |
+
->string($this->getAttribute('name'))
|
43 |
+
->raw(", \$context, \$blocks)")
|
44 |
+
;
|
45 |
+
}
|
46 |
+
}
|
47 |
+
}
|
classes/Twig/Node/Expression/TempName.php
CHANGED
@@ -1,26 +1,26 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2011 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
class Twig_Node_Expression_TempName extends Twig_Node_Expression
|
12 |
-
{
|
13 |
-
public function __construct($name, $lineno)
|
14 |
-
{
|
15 |
-
parent::__construct(array(), array('name' => $name), $lineno);
|
16 |
-
}
|
17 |
-
|
18 |
-
public function compile(Twig_Compiler $compiler)
|
19 |
-
{
|
20 |
-
$compiler
|
21 |
-
->raw('$_')
|
22 |
-
->raw($this->getAttribute('name'))
|
23 |
-
->raw('_')
|
24 |
-
;
|
25 |
-
}
|
26 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2011 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
class Twig_Node_Expression_TempName extends Twig_Node_Expression
|
12 |
+
{
|
13 |
+
public function __construct($name, $lineno)
|
14 |
+
{
|
15 |
+
parent::__construct(array(), array('name' => $name), $lineno);
|
16 |
+
}
|
17 |
+
|
18 |
+
public function compile(Twig_Compiler $compiler)
|
19 |
+
{
|
20 |
+
$compiler
|
21 |
+
->raw('$_')
|
22 |
+
->raw($this->getAttribute('name'))
|
23 |
+
->raw('_')
|
24 |
+
;
|
25 |
+
}
|
26 |
+
}
|
classes/Twig/Node/Expression/Test.php
CHANGED
@@ -1,32 +1,32 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2010 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
class Twig_Node_Expression_Test extends Twig_Node_Expression_Call
|
12 |
-
{
|
13 |
-
public function __construct(Twig_NodeInterface $node, $name, Twig_NodeInterface $arguments = null, $lineno)
|
14 |
-
{
|
15 |
-
parent::__construct(array('node' => $node, 'arguments' => $arguments), array('name' => $name), $lineno);
|
16 |
-
}
|
17 |
-
|
18 |
-
public function compile(Twig_Compiler $compiler)
|
19 |
-
{
|
20 |
-
$name = $this->getAttribute('name');
|
21 |
-
$test = $compiler->getEnvironment()->getTest($name);
|
22 |
-
|
23 |
-
$this->setAttribute('name', $name);
|
24 |
-
$this->setAttribute('type', 'test');
|
25 |
-
$this->setAttribute('thing', $test);
|
26 |
-
if ($test instanceof Twig_TestCallableInterface || $test instanceof Twig_SimpleTest) {
|
27 |
-
$this->setAttribute('callable', $test->getCallable());
|
28 |
-
}
|
29 |
-
|
30 |
-
$this->compileCallable($compiler);
|
31 |
-
}
|
32 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2010 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
class Twig_Node_Expression_Test extends Twig_Node_Expression_Call
|
12 |
+
{
|
13 |
+
public function __construct(Twig_NodeInterface $node, $name, Twig_NodeInterface $arguments = null, $lineno)
|
14 |
+
{
|
15 |
+
parent::__construct(array('node' => $node, 'arguments' => $arguments), array('name' => $name), $lineno);
|
16 |
+
}
|
17 |
+
|
18 |
+
public function compile(Twig_Compiler $compiler)
|
19 |
+
{
|
20 |
+
$name = $this->getAttribute('name');
|
21 |
+
$test = $compiler->getEnvironment()->getTest($name);
|
22 |
+
|
23 |
+
$this->setAttribute('name', $name);
|
24 |
+
$this->setAttribute('type', 'test');
|
25 |
+
$this->setAttribute('thing', $test);
|
26 |
+
if ($test instanceof Twig_TestCallableInterface || $test instanceof Twig_SimpleTest) {
|
27 |
+
$this->setAttribute('callable', $test->getCallable());
|
28 |
+
}
|
29 |
+
|
30 |
+
$this->compileCallable($compiler);
|
31 |
+
}
|
32 |
+
}
|
classes/Twig/Node/Expression/Test/Constant.php
CHANGED
@@ -1,46 +1,46 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2011 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
/**
|
13 |
-
* Checks if a variable is the exact same value as a constant.
|
14 |
-
*
|
15 |
-
* <pre>
|
16 |
-
* {% if post.status is constant('Post::PUBLISHED') %}
|
17 |
-
* the status attribute is exactly the same as Post::PUBLISHED
|
18 |
-
* {% endif %}
|
19 |
-
* </pre>
|
20 |
-
*
|
21 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
22 |
-
*/
|
23 |
-
class Twig_Node_Expression_Test_Constant extends Twig_Node_Expression_Test
|
24 |
-
{
|
25 |
-
public function compile(Twig_Compiler $compiler)
|
26 |
-
{
|
27 |
-
$compiler
|
28 |
-
->raw('(')
|
29 |
-
->subcompile($this->getNode('node'))
|
30 |
-
->raw(' === constant(')
|
31 |
-
;
|
32 |
-
|
33 |
-
if ($this->getNode('arguments')->hasNode(1)) {
|
34 |
-
$compiler
|
35 |
-
->raw('get_class(')
|
36 |
-
->subcompile($this->getNode('arguments')->getNode(1))
|
37 |
-
->raw(')."::".')
|
38 |
-
;
|
39 |
-
}
|
40 |
-
|
41 |
-
$compiler
|
42 |
-
->subcompile($this->getNode('arguments')->getNode(0))
|
43 |
-
->raw('))')
|
44 |
-
;
|
45 |
-
}
|
46 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2011 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Checks if a variable is the exact same value as a constant.
|
14 |
+
*
|
15 |
+
* <pre>
|
16 |
+
* {% if post.status is constant('Post::PUBLISHED') %}
|
17 |
+
* the status attribute is exactly the same as Post::PUBLISHED
|
18 |
+
* {% endif %}
|
19 |
+
* </pre>
|
20 |
+
*
|
21 |
+
* @author Fabien Potencier <fabien@symfony.com>
|
22 |
+
*/
|
23 |
+
class Twig_Node_Expression_Test_Constant extends Twig_Node_Expression_Test
|
24 |
+
{
|
25 |
+
public function compile(Twig_Compiler $compiler)
|
26 |
+
{
|
27 |
+
$compiler
|
28 |
+
->raw('(')
|
29 |
+
->subcompile($this->getNode('node'))
|
30 |
+
->raw(' === constant(')
|
31 |
+
;
|
32 |
+
|
33 |
+
if ($this->getNode('arguments')->hasNode(1)) {
|
34 |
+
$compiler
|
35 |
+
->raw('get_class(')
|
36 |
+
->subcompile($this->getNode('arguments')->getNode(1))
|
37 |
+
->raw(')."::".')
|
38 |
+
;
|
39 |
+
}
|
40 |
+
|
41 |
+
$compiler
|
42 |
+
->subcompile($this->getNode('arguments')->getNode(0))
|
43 |
+
->raw('))')
|
44 |
+
;
|
45 |
+
}
|
46 |
+
}
|
classes/Twig/Node/Expression/Test/Defined.php
CHANGED
@@ -1,54 +1,54 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2011 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
/**
|
13 |
-
* Checks if a variable is defined in the current context.
|
14 |
-
*
|
15 |
-
* <pre>
|
16 |
-
* {# defined works with variable names and variable attributes #}
|
17 |
-
* {% if foo is defined %}
|
18 |
-
* {# ... #}
|
19 |
-
* {% endif %}
|
20 |
-
* </pre>
|
21 |
-
*
|
22 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
23 |
-
*/
|
24 |
-
class Twig_Node_Expression_Test_Defined extends Twig_Node_Expression_Test
|
25 |
-
{
|
26 |
-
public function __construct(Twig_NodeInterface $node, $name, Twig_NodeInterface $arguments = null, $lineno)
|
27 |
-
{
|
28 |
-
parent::__construct($node, $name, $arguments, $lineno);
|
29 |
-
|
30 |
-
if ($node instanceof Twig_Node_Expression_Name) {
|
31 |
-
$node->setAttribute('is_defined_test', true);
|
32 |
-
} elseif ($node instanceof Twig_Node_Expression_GetAttr) {
|
33 |
-
$node->setAttribute('is_defined_test', true);
|
34 |
-
|
35 |
-
$this->changeIgnoreStrictCheck($node);
|
36 |
-
} else {
|
37 |
-
throw new Twig_Error_Syntax('The "defined" test only works with simple variables', $this->getLine());
|
38 |
-
}
|
39 |
-
}
|
40 |
-
|
41 |
-
protected function changeIgnoreStrictCheck(Twig_Node_Expression_GetAttr $node)
|
42 |
-
{
|
43 |
-
$node->setAttribute('ignore_strict_check', true);
|
44 |
-
|
45 |
-
if ($node->getNode('node') instanceof Twig_Node_Expression_GetAttr) {
|
46 |
-
$this->changeIgnoreStrictCheck($node->getNode('node'));
|
47 |
-
}
|
48 |
-
}
|
49 |
-
|
50 |
-
public function compile(Twig_Compiler $compiler)
|
51 |
-
{
|
52 |
-
$compiler->subcompile($this->getNode('node'));
|
53 |
-
}
|
54 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2011 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Checks if a variable is defined in the current context.
|
14 |
+
*
|
15 |
+
* <pre>
|
16 |
+
* {# defined works with variable names and variable attributes #}
|
17 |
+
* {% if foo is defined %}
|
18 |
+
* {# ... #}
|
19 |
+
* {% endif %}
|
20 |
+
* </pre>
|
21 |
+
*
|
22 |
+
* @author Fabien Potencier <fabien@symfony.com>
|
23 |
+
*/
|
24 |
+
class Twig_Node_Expression_Test_Defined extends Twig_Node_Expression_Test
|
25 |
+
{
|
26 |
+
public function __construct(Twig_NodeInterface $node, $name, Twig_NodeInterface $arguments = null, $lineno)
|
27 |
+
{
|
28 |
+
parent::__construct($node, $name, $arguments, $lineno);
|
29 |
+
|
30 |
+
if ($node instanceof Twig_Node_Expression_Name) {
|
31 |
+
$node->setAttribute('is_defined_test', true);
|
32 |
+
} elseif ($node instanceof Twig_Node_Expression_GetAttr) {
|
33 |
+
$node->setAttribute('is_defined_test', true);
|
34 |
+
|
35 |
+
$this->changeIgnoreStrictCheck($node);
|
36 |
+
} else {
|
37 |
+
throw new Twig_Error_Syntax('The "defined" test only works with simple variables', $this->getLine());
|
38 |
+
}
|
39 |
+
}
|
40 |
+
|
41 |
+
protected function changeIgnoreStrictCheck(Twig_Node_Expression_GetAttr $node)
|
42 |
+
{
|
43 |
+
$node->setAttribute('ignore_strict_check', true);
|
44 |
+
|
45 |
+
if ($node->getNode('node') instanceof Twig_Node_Expression_GetAttr) {
|
46 |
+
$this->changeIgnoreStrictCheck($node->getNode('node'));
|
47 |
+
}
|
48 |
+
}
|
49 |
+
|
50 |
+
public function compile(Twig_Compiler $compiler)
|
51 |
+
{
|
52 |
+
$compiler->subcompile($this->getNode('node'));
|
53 |
+
}
|
54 |
+
}
|
classes/Twig/Node/Expression/Test/Divisibleby.php
CHANGED
@@ -1,33 +1,33 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2011 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
/**
|
13 |
-
* Checks if a variable is divisible by a number.
|
14 |
-
*
|
15 |
-
* <pre>
|
16 |
-
* {% if loop.index is divisible by(3) %}
|
17 |
-
* </pre>
|
18 |
-
*
|
19 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
20 |
-
*/
|
21 |
-
class Twig_Node_Expression_Test_Divisibleby extends Twig_Node_Expression_Test
|
22 |
-
{
|
23 |
-
public function compile(Twig_Compiler $compiler)
|
24 |
-
{
|
25 |
-
$compiler
|
26 |
-
->raw('(0 == ')
|
27 |
-
->subcompile($this->getNode('node'))
|
28 |
-
->raw(' % ')
|
29 |
-
->subcompile($this->getNode('arguments')->getNode(0))
|
30 |
-
->raw(')')
|
31 |
-
;
|
32 |
-
}
|
33 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2011 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Checks if a variable is divisible by a number.
|
14 |
+
*
|
15 |
+
* <pre>
|
16 |
+
* {% if loop.index is divisible by(3) %}
|
17 |
+
* </pre>
|
18 |
+
*
|
19 |
+
* @author Fabien Potencier <fabien@symfony.com>
|
20 |
+
*/
|
21 |
+
class Twig_Node_Expression_Test_Divisibleby extends Twig_Node_Expression_Test
|
22 |
+
{
|
23 |
+
public function compile(Twig_Compiler $compiler)
|
24 |
+
{
|
25 |
+
$compiler
|
26 |
+
->raw('(0 == ')
|
27 |
+
->subcompile($this->getNode('node'))
|
28 |
+
->raw(' % ')
|
29 |
+
->subcompile($this->getNode('arguments')->getNode(0))
|
30 |
+
->raw(')')
|
31 |
+
;
|
32 |
+
}
|
33 |
+
}
|
classes/Twig/Node/Expression/Test/Even.php
CHANGED
@@ -1,32 +1,32 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2011 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
/**
|
13 |
-
* Checks if a number is even.
|
14 |
-
*
|
15 |
-
* <pre>
|
16 |
-
* {{ var is even }}
|
17 |
-
* </pre>
|
18 |
-
*
|
19 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
20 |
-
*/
|
21 |
-
class Twig_Node_Expression_Test_Even extends Twig_Node_Expression_Test
|
22 |
-
{
|
23 |
-
public function compile(Twig_Compiler $compiler)
|
24 |
-
{
|
25 |
-
$compiler
|
26 |
-
->raw('(')
|
27 |
-
->subcompile($this->getNode('node'))
|
28 |
-
->raw(' % 2 == 0')
|
29 |
-
->raw(')')
|
30 |
-
;
|
31 |
-
}
|
32 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2011 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Checks if a number is even.
|
14 |
+
*
|
15 |
+
* <pre>
|
16 |
+
* {{ var is even }}
|
17 |
+
* </pre>
|
18 |
+
*
|
19 |
+
* @author Fabien Potencier <fabien@symfony.com>
|
20 |
+
*/
|
21 |
+
class Twig_Node_Expression_Test_Even extends Twig_Node_Expression_Test
|
22 |
+
{
|
23 |
+
public function compile(Twig_Compiler $compiler)
|
24 |
+
{
|
25 |
+
$compiler
|
26 |
+
->raw('(')
|
27 |
+
->subcompile($this->getNode('node'))
|
28 |
+
->raw(' % 2 == 0')
|
29 |
+
->raw(')')
|
30 |
+
;
|
31 |
+
}
|
32 |
+
}
|
classes/Twig/Node/Expression/Test/Null.php
CHANGED
@@ -1,31 +1,31 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2011 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
/**
|
13 |
-
* Checks that a variable is null.
|
14 |
-
*
|
15 |
-
* <pre>
|
16 |
-
* {{ var is none }}
|
17 |
-
* </pre>
|
18 |
-
*
|
19 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
20 |
-
*/
|
21 |
-
class Twig_Node_Expression_Test_Null extends Twig_Node_Expression_Test
|
22 |
-
{
|
23 |
-
public function compile(Twig_Compiler $compiler)
|
24 |
-
{
|
25 |
-
$compiler
|
26 |
-
->raw('(null === ')
|
27 |
-
->subcompile($this->getNode('node'))
|
28 |
-
->raw(')')
|
29 |
-
;
|
30 |
-
}
|
31 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2011 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Checks that a variable is null.
|
14 |
+
*
|
15 |
+
* <pre>
|
16 |
+
* {{ var is none }}
|
17 |
+
* </pre>
|
18 |
+
*
|
19 |
+
* @author Fabien Potencier <fabien@symfony.com>
|
20 |
+
*/
|
21 |
+
class Twig_Node_Expression_Test_Null extends Twig_Node_Expression_Test
|
22 |
+
{
|
23 |
+
public function compile(Twig_Compiler $compiler)
|
24 |
+
{
|
25 |
+
$compiler
|
26 |
+
->raw('(null === ')
|
27 |
+
->subcompile($this->getNode('node'))
|
28 |
+
->raw(')')
|
29 |
+
;
|
30 |
+
}
|
31 |
+
}
|
classes/Twig/Node/Expression/Test/Odd.php
CHANGED
@@ -1,32 +1,32 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2011 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
/**
|
13 |
-
* Checks if a number is odd.
|
14 |
-
*
|
15 |
-
* <pre>
|
16 |
-
* {{ var is odd }}
|
17 |
-
* </pre>
|
18 |
-
*
|
19 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
20 |
-
*/
|
21 |
-
class Twig_Node_Expression_Test_Odd extends Twig_Node_Expression_Test
|
22 |
-
{
|
23 |
-
public function compile(Twig_Compiler $compiler)
|
24 |
-
{
|
25 |
-
$compiler
|
26 |
-
->raw('(')
|
27 |
-
->subcompile($this->getNode('node'))
|
28 |
-
->raw(' % 2 == 1')
|
29 |
-
->raw(')')
|
30 |
-
;
|
31 |
-
}
|
32 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2011 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Checks if a number is odd.
|
14 |
+
*
|
15 |
+
* <pre>
|
16 |
+
* {{ var is odd }}
|
17 |
+
* </pre>
|
18 |
+
*
|
19 |
+
* @author Fabien Potencier <fabien@symfony.com>
|
20 |
+
*/
|
21 |
+
class Twig_Node_Expression_Test_Odd extends Twig_Node_Expression_Test
|
22 |
+
{
|
23 |
+
public function compile(Twig_Compiler $compiler)
|
24 |
+
{
|
25 |
+
$compiler
|
26 |
+
->raw('(')
|
27 |
+
->subcompile($this->getNode('node'))
|
28 |
+
->raw(' % 2 == 1')
|
29 |
+
->raw(')')
|
30 |
+
;
|
31 |
+
}
|
32 |
+
}
|
classes/Twig/Node/Expression/Test/Sameas.php
CHANGED
@@ -1,29 +1,29 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2011 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
/**
|
13 |
-
* Checks if a variable is the same as another one (=== in PHP).
|
14 |
-
*
|
15 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
16 |
-
*/
|
17 |
-
class Twig_Node_Expression_Test_Sameas extends Twig_Node_Expression_Test
|
18 |
-
{
|
19 |
-
public function compile(Twig_Compiler $compiler)
|
20 |
-
{
|
21 |
-
$compiler
|
22 |
-
->raw('(')
|
23 |
-
->subcompile($this->getNode('node'))
|
24 |
-
->raw(' === ')
|
25 |
-
->subcompile($this->getNode('arguments')->getNode(0))
|
26 |
-
->raw(')')
|
27 |
-
;
|
28 |
-
}
|
29 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2011 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Checks if a variable is the same as another one (=== in PHP).
|
14 |
+
*
|
15 |
+
* @author Fabien Potencier <fabien@symfony.com>
|
16 |
+
*/
|
17 |
+
class Twig_Node_Expression_Test_Sameas extends Twig_Node_Expression_Test
|
18 |
+
{
|
19 |
+
public function compile(Twig_Compiler $compiler)
|
20 |
+
{
|
21 |
+
$compiler
|
22 |
+
->raw('(')
|
23 |
+
->subcompile($this->getNode('node'))
|
24 |
+
->raw(' === ')
|
25 |
+
->subcompile($this->getNode('arguments')->getNode(0))
|
26 |
+
->raw(')')
|
27 |
+
;
|
28 |
+
}
|
29 |
+
}
|
classes/Twig/Node/Expression/Unary.php
CHANGED
@@ -1,30 +1,30 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2009 Fabien Potencier
|
7 |
-
* (c) 2009 Armin Ronacher
|
8 |
-
*
|
9 |
-
* For the full copyright and license information, please view the LICENSE
|
10 |
-
* file that was distributed with this source code.
|
11 |
-
*/
|
12 |
-
abstract class Twig_Node_Expression_Unary extends Twig_Node_Expression
|
13 |
-
{
|
14 |
-
public function __construct(Twig_NodeInterface $node, $lineno)
|
15 |
-
{
|
16 |
-
parent::__construct(array('node' => $node), array(), $lineno);
|
17 |
-
}
|
18 |
-
|
19 |
-
public function compile(Twig_Compiler $compiler)
|
20 |
-
{
|
21 |
-
$compiler->raw('(');
|
22 |
-
$this->operator($compiler);
|
23 |
-
$compiler
|
24 |
-
->subcompile($this->getNode('node'))
|
25 |
-
->raw(')')
|
26 |
-
;
|
27 |
-
}
|
28 |
-
|
29 |
-
abstract public function operator(Twig_Compiler $compiler);
|
30 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2009 Fabien Potencier
|
7 |
+
* (c) 2009 Armin Ronacher
|
8 |
+
*
|
9 |
+
* For the full copyright and license information, please view the LICENSE
|
10 |
+
* file that was distributed with this source code.
|
11 |
+
*/
|
12 |
+
abstract class Twig_Node_Expression_Unary extends Twig_Node_Expression
|
13 |
+
{
|
14 |
+
public function __construct(Twig_NodeInterface $node, $lineno)
|
15 |
+
{
|
16 |
+
parent::__construct(array('node' => $node), array(), $lineno);
|
17 |
+
}
|
18 |
+
|
19 |
+
public function compile(Twig_Compiler $compiler)
|
20 |
+
{
|
21 |
+
$compiler->raw('(');
|
22 |
+
$this->operator($compiler);
|
23 |
+
$compiler
|
24 |
+
->subcompile($this->getNode('node'))
|
25 |
+
->raw(')')
|
26 |
+
;
|
27 |
+
}
|
28 |
+
|
29 |
+
abstract public function operator(Twig_Compiler $compiler);
|
30 |
+
}
|
classes/Twig/Node/Expression/Unary/Neg.php
CHANGED
@@ -1,18 +1,18 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2009 Fabien Potencier
|
7 |
-
* (c) 2009 Armin Ronacher
|
8 |
-
*
|
9 |
-
* For the full copyright and license information, please view the LICENSE
|
10 |
-
* file that was distributed with this source code.
|
11 |
-
*/
|
12 |
-
class Twig_Node_Expression_Unary_Neg extends Twig_Node_Expression_Unary
|
13 |
-
{
|
14 |
-
public function operator(Twig_Compiler $compiler)
|
15 |
-
{
|
16 |
-
$compiler->raw('-');
|
17 |
-
}
|
18 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2009 Fabien Potencier
|
7 |
+
* (c) 2009 Armin Ronacher
|
8 |
+
*
|
9 |
+
* For the full copyright and license information, please view the LICENSE
|
10 |
+
* file that was distributed with this source code.
|
11 |
+
*/
|
12 |
+
class Twig_Node_Expression_Unary_Neg extends Twig_Node_Expression_Unary
|
13 |
+
{
|
14 |
+
public function operator(Twig_Compiler $compiler)
|
15 |
+
{
|
16 |
+
$compiler->raw('-');
|
17 |
+
}
|
18 |
+
}
|
classes/Twig/Node/Expression/Unary/Not.php
CHANGED
@@ -1,18 +1,18 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2009 Fabien Potencier
|
7 |
-
* (c) 2009 Armin Ronacher
|
8 |
-
*
|
9 |
-
* For the full copyright and license information, please view the LICENSE
|
10 |
-
* file that was distributed with this source code.
|
11 |
-
*/
|
12 |
-
class Twig_Node_Expression_Unary_Not extends Twig_Node_Expression_Unary
|
13 |
-
{
|
14 |
-
public function operator(Twig_Compiler $compiler)
|
15 |
-
{
|
16 |
-
$compiler->raw('!');
|
17 |
-
}
|
18 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2009 Fabien Potencier
|
7 |
+
* (c) 2009 Armin Ronacher
|
8 |
+
*
|
9 |
+
* For the full copyright and license information, please view the LICENSE
|
10 |
+
* file that was distributed with this source code.
|
11 |
+
*/
|
12 |
+
class Twig_Node_Expression_Unary_Not extends Twig_Node_Expression_Unary
|
13 |
+
{
|
14 |
+
public function operator(Twig_Compiler $compiler)
|
15 |
+
{
|
16 |
+
$compiler->raw('!');
|
17 |
+
}
|
18 |
+
}
|
classes/Twig/Node/Expression/Unary/Pos.php
CHANGED
@@ -1,18 +1,18 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2009 Fabien Potencier
|
7 |
-
* (c) 2009 Armin Ronacher
|
8 |
-
*
|
9 |
-
* For the full copyright and license information, please view the LICENSE
|
10 |
-
* file that was distributed with this source code.
|
11 |
-
*/
|
12 |
-
class Twig_Node_Expression_Unary_Pos extends Twig_Node_Expression_Unary
|
13 |
-
{
|
14 |
-
public function operator(Twig_Compiler $compiler)
|
15 |
-
{
|
16 |
-
$compiler->raw('+');
|
17 |
-
}
|
18 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2009 Fabien Potencier
|
7 |
+
* (c) 2009 Armin Ronacher
|
8 |
+
*
|
9 |
+
* For the full copyright and license information, please view the LICENSE
|
10 |
+
* file that was distributed with this source code.
|
11 |
+
*/
|
12 |
+
class Twig_Node_Expression_Unary_Pos extends Twig_Node_Expression_Unary
|
13 |
+
{
|
14 |
+
public function operator(Twig_Compiler $compiler)
|
15 |
+
{
|
16 |
+
$compiler->raw('+');
|
17 |
+
}
|
18 |
+
}
|
classes/Twig/Node/Flush.php
CHANGED
@@ -1,36 +1,36 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2011 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
/**
|
13 |
-
* Represents a flush node.
|
14 |
-
*
|
15 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
16 |
-
*/
|
17 |
-
class Twig_Node_Flush extends Twig_Node
|
18 |
-
{
|
19 |
-
public function __construct($lineno, $tag)
|
20 |
-
{
|
21 |
-
parent::__construct(array(), array(), $lineno, $tag);
|
22 |
-
}
|
23 |
-
|
24 |
-
/**
|
25 |
-
* Compiles the node to PHP.
|
26 |
-
*
|
27 |
-
* @param Twig_Compiler A Twig_Compiler instance
|
28 |
-
*/
|
29 |
-
public function compile(Twig_Compiler $compiler)
|
30 |
-
{
|
31 |
-
$compiler
|
32 |
-
->addDebugInfo($this)
|
33 |
-
->write("flush();\n")
|
34 |
-
;
|
35 |
-
}
|
36 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2011 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Represents a flush node.
|
14 |
+
*
|
15 |
+
* @author Fabien Potencier <fabien@symfony.com>
|
16 |
+
*/
|
17 |
+
class Twig_Node_Flush extends Twig_Node
|
18 |
+
{
|
19 |
+
public function __construct($lineno, $tag)
|
20 |
+
{
|
21 |
+
parent::__construct(array(), array(), $lineno, $tag);
|
22 |
+
}
|
23 |
+
|
24 |
+
/**
|
25 |
+
* Compiles the node to PHP.
|
26 |
+
*
|
27 |
+
* @param Twig_Compiler A Twig_Compiler instance
|
28 |
+
*/
|
29 |
+
public function compile(Twig_Compiler $compiler)
|
30 |
+
{
|
31 |
+
$compiler
|
32 |
+
->addDebugInfo($this)
|
33 |
+
->write("flush();\n")
|
34 |
+
;
|
35 |
+
}
|
36 |
+
}
|
classes/Twig/Node/For.php
CHANGED
@@ -1,112 +1,112 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2009 Fabien Potencier
|
7 |
-
* (c) 2009 Armin Ronacher
|
8 |
-
*
|
9 |
-
* For the full copyright and license information, please view the LICENSE
|
10 |
-
* file that was distributed with this source code.
|
11 |
-
*/
|
12 |
-
|
13 |
-
/**
|
14 |
-
* Represents a for node.
|
15 |
-
*
|
16 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
17 |
-
*/
|
18 |
-
class Twig_Node_For extends Twig_Node
|
19 |
-
{
|
20 |
-
protected $loop;
|
21 |
-
|
22 |
-
public function __construct(Twig_Node_Expression_AssignName $keyTarget, Twig_Node_Expression_AssignName $valueTarget, Twig_Node_Expression $seq, Twig_Node_Expression $ifexpr = null, Twig_NodeInterface $body, Twig_NodeInterface $else = null, $lineno, $tag = null)
|
23 |
-
{
|
24 |
-
$body = new Twig_Node(array($body, $this->loop = new Twig_Node_ForLoop($lineno, $tag)));
|
25 |
-
|
26 |
-
if (null !== $ifexpr) {
|
27 |
-
$body = new Twig_Node_If(new Twig_Node(array($ifexpr, $body)), null, $lineno, $tag);
|
28 |
-
}
|
29 |
-
|
30 |
-
parent::__construct(array('key_target' => $keyTarget, 'value_target' => $valueTarget, 'seq' => $seq, 'body' => $body, 'else' => $else), array('with_loop' => true, 'ifexpr' => null !== $ifexpr), $lineno, $tag);
|
31 |
-
}
|
32 |
-
|
33 |
-
/**
|
34 |
-
* Compiles the node to PHP.
|
35 |
-
*
|
36 |
-
* @param Twig_Compiler A Twig_Compiler instance
|
37 |
-
*/
|
38 |
-
public function compile(Twig_Compiler $compiler)
|
39 |
-
{
|
40 |
-
$compiler
|
41 |
-
->addDebugInfo($this)
|
42 |
-
// the (array) cast bypasses a PHP 5.2.6 bug
|
43 |
-
->write("\$context['_parent'] = (array) \$context;\n")
|
44 |
-
->write("\$context['_seq'] = twig_ensure_traversable(")
|
45 |
-
->subcompile($this->getNode('seq'))
|
46 |
-
->raw(");\n")
|
47 |
-
;
|
48 |
-
|
49 |
-
if (null !== $this->getNode('else')) {
|
50 |
-
$compiler->write("\$context['_iterated'] = false;\n");
|
51 |
-
}
|
52 |
-
|
53 |
-
if ($this->getAttribute('with_loop')) {
|
54 |
-
$compiler
|
55 |
-
->write("\$context['loop'] = array(\n")
|
56 |
-
->write(" 'parent' => \$context['_parent'],\n")
|
57 |
-
->write(" 'index0' => 0,\n")
|
58 |
-
->write(" 'index' => 1,\n")
|
59 |
-
->write(" 'first' => true,\n")
|
60 |
-
->write(");\n")
|
61 |
-
;
|
62 |
-
|
63 |
-
if (!$this->getAttribute('ifexpr')) {
|
64 |
-
$compiler
|
65 |
-
->write("if (is_array(\$context['_seq']) || (is_object(\$context['_seq']) && \$context['_seq'] instanceof Countable)) {\n")
|
66 |
-
->indent()
|
67 |
-
->write("\$length = count(\$context['_seq']);\n")
|
68 |
-
->write("\$context['loop']['revindex0'] = \$length - 1;\n")
|
69 |
-
->write("\$context['loop']['revindex'] = \$length;\n")
|
70 |
-
->write("\$context['loop']['length'] = \$length;\n")
|
71 |
-
->write("\$context['loop']['last'] = 1 === \$length;\n")
|
72 |
-
->outdent()
|
73 |
-
->write("}\n")
|
74 |
-
;
|
75 |
-
}
|
76 |
-
}
|
77 |
-
|
78 |
-
$this->loop->setAttribute('else', null !== $this->getNode('else'));
|
79 |
-
$this->loop->setAttribute('with_loop', $this->getAttribute('with_loop'));
|
80 |
-
$this->loop->setAttribute('ifexpr', $this->getAttribute('ifexpr'));
|
81 |
-
|
82 |
-
$compiler
|
83 |
-
->write("foreach (\$context['_seq'] as ")
|
84 |
-
->subcompile($this->getNode('key_target'))
|
85 |
-
->raw(" => ")
|
86 |
-
->subcompile($this->getNode('value_target'))
|
87 |
-
->raw(") {\n")
|
88 |
-
->indent()
|
89 |
-
->subcompile($this->getNode('body'))
|
90 |
-
->outdent()
|
91 |
-
->write("}\n")
|
92 |
-
;
|
93 |
-
|
94 |
-
if (null !== $this->getNode('else')) {
|
95 |
-
$compiler
|
96 |
-
->write("if (!\$context['_iterated']) {\n")
|
97 |
-
->indent()
|
98 |
-
->subcompile($this->getNode('else'))
|
99 |
-
->outdent()
|
100 |
-
->write("}\n")
|
101 |
-
;
|
102 |
-
}
|
103 |
-
|
104 |
-
$compiler->write("\$_parent = \$context['_parent'];\n");
|
105 |
-
|
106 |
-
// remove some "private" loop variables (needed for nested loops)
|
107 |
-
$compiler->write('unset($context[\'_seq\'], $context[\'_iterated\'], $context[\''.$this->getNode('key_target')->getAttribute('name').'\'], $context[\''.$this->getNode('value_target')->getAttribute('name').'\'], $context[\'_parent\'], $context[\'loop\']);'."\n");
|
108 |
-
|
109 |
-
// keep the values set in the inner context for variables defined in the outer context
|
110 |
-
$compiler->write("\$context = array_intersect_key(\$context, \$_parent) + \$_parent;\n");
|
111 |
-
}
|
112 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2009 Fabien Potencier
|
7 |
+
* (c) 2009 Armin Ronacher
|
8 |
+
*
|
9 |
+
* For the full copyright and license information, please view the LICENSE
|
10 |
+
* file that was distributed with this source code.
|
11 |
+
*/
|
12 |
+
|
13 |
+
/**
|
14 |
+
* Represents a for node.
|
15 |
+
*
|
16 |
+
* @author Fabien Potencier <fabien@symfony.com>
|
17 |
+
*/
|
18 |
+
class Twig_Node_For extends Twig_Node
|
19 |
+
{
|
20 |
+
protected $loop;
|
21 |
+
|
22 |
+
public function __construct(Twig_Node_Expression_AssignName $keyTarget, Twig_Node_Expression_AssignName $valueTarget, Twig_Node_Expression $seq, Twig_Node_Expression $ifexpr = null, Twig_NodeInterface $body, Twig_NodeInterface $else = null, $lineno, $tag = null)
|
23 |
+
{
|
24 |
+
$body = new Twig_Node(array($body, $this->loop = new Twig_Node_ForLoop($lineno, $tag)));
|
25 |
+
|
26 |
+
if (null !== $ifexpr) {
|
27 |
+
$body = new Twig_Node_If(new Twig_Node(array($ifexpr, $body)), null, $lineno, $tag);
|
28 |
+
}
|
29 |
+
|
30 |
+
parent::__construct(array('key_target' => $keyTarget, 'value_target' => $valueTarget, 'seq' => $seq, 'body' => $body, 'else' => $else), array('with_loop' => true, 'ifexpr' => null !== $ifexpr), $lineno, $tag);
|
31 |
+
}
|
32 |
+
|
33 |
+
/**
|
34 |
+
* Compiles the node to PHP.
|
35 |
+
*
|
36 |
+
* @param Twig_Compiler A Twig_Compiler instance
|
37 |
+
*/
|
38 |
+
public function compile(Twig_Compiler $compiler)
|
39 |
+
{
|
40 |
+
$compiler
|
41 |
+
->addDebugInfo($this)
|
42 |
+
// the (array) cast bypasses a PHP 5.2.6 bug
|
43 |
+
->write("\$context['_parent'] = (array) \$context;\n")
|
44 |
+
->write("\$context['_seq'] = twig_ensure_traversable(")
|
45 |
+
->subcompile($this->getNode('seq'))
|
46 |
+
->raw(");\n")
|
47 |
+
;
|
48 |
+
|
49 |
+
if (null !== $this->getNode('else')) {
|
50 |
+
$compiler->write("\$context['_iterated'] = false;\n");
|
51 |
+
}
|
52 |
+
|
53 |
+
if ($this->getAttribute('with_loop')) {
|
54 |
+
$compiler
|
55 |
+
->write("\$context['loop'] = array(\n")
|
56 |
+
->write(" 'parent' => \$context['_parent'],\n")
|
57 |
+
->write(" 'index0' => 0,\n")
|
58 |
+
->write(" 'index' => 1,\n")
|
59 |
+
->write(" 'first' => true,\n")
|
60 |
+
->write(");\n")
|
61 |
+
;
|
62 |
+
|
63 |
+
if (!$this->getAttribute('ifexpr')) {
|
64 |
+
$compiler
|
65 |
+
->write("if (is_array(\$context['_seq']) || (is_object(\$context['_seq']) && \$context['_seq'] instanceof Countable)) {\n")
|
66 |
+
->indent()
|
67 |
+
->write("\$length = count(\$context['_seq']);\n")
|
68 |
+
->write("\$context['loop']['revindex0'] = \$length - 1;\n")
|
69 |
+
->write("\$context['loop']['revindex'] = \$length;\n")
|
70 |
+
->write("\$context['loop']['length'] = \$length;\n")
|
71 |
+
->write("\$context['loop']['last'] = 1 === \$length;\n")
|
72 |
+
->outdent()
|
73 |
+
->write("}\n")
|
74 |
+
;
|
75 |
+
}
|
76 |
+
}
|
77 |
+
|
78 |
+
$this->loop->setAttribute('else', null !== $this->getNode('else'));
|
79 |
+
$this->loop->setAttribute('with_loop', $this->getAttribute('with_loop'));
|
80 |
+
$this->loop->setAttribute('ifexpr', $this->getAttribute('ifexpr'));
|
81 |
+
|
82 |
+
$compiler
|
83 |
+
->write("foreach (\$context['_seq'] as ")
|
84 |
+
->subcompile($this->getNode('key_target'))
|
85 |
+
->raw(" => ")
|
86 |
+
->subcompile($this->getNode('value_target'))
|
87 |
+
->raw(") {\n")
|
88 |
+
->indent()
|
89 |
+
->subcompile($this->getNode('body'))
|
90 |
+
->outdent()
|
91 |
+
->write("}\n")
|
92 |
+
;
|
93 |
+
|
94 |
+
if (null !== $this->getNode('else')) {
|
95 |
+
$compiler
|
96 |
+
->write("if (!\$context['_iterated']) {\n")
|
97 |
+
->indent()
|
98 |
+
->subcompile($this->getNode('else'))
|
99 |
+
->outdent()
|
100 |
+
->write("}\n")
|
101 |
+
;
|
102 |
+
}
|
103 |
+
|
104 |
+
$compiler->write("\$_parent = \$context['_parent'];\n");
|
105 |
+
|
106 |
+
// remove some "private" loop variables (needed for nested loops)
|
107 |
+
$compiler->write('unset($context[\'_seq\'], $context[\'_iterated\'], $context[\''.$this->getNode('key_target')->getAttribute('name').'\'], $context[\''.$this->getNode('value_target')->getAttribute('name').'\'], $context[\'_parent\'], $context[\'loop\']);'."\n");
|
108 |
+
|
109 |
+
// keep the values set in the inner context for variables defined in the outer context
|
110 |
+
$compiler->write("\$context = array_intersect_key(\$context, \$_parent) + \$_parent;\n");
|
111 |
+
}
|
112 |
+
}
|
classes/Twig/Node/ForLoop.php
CHANGED
@@ -1,55 +1,55 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2011 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
/**
|
13 |
-
* Internal node used by the for node.
|
14 |
-
*
|
15 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
16 |
-
*/
|
17 |
-
class Twig_Node_ForLoop extends Twig_Node
|
18 |
-
{
|
19 |
-
public function __construct($lineno, $tag = null)
|
20 |
-
{
|
21 |
-
parent::__construct(array(), array('with_loop' => false, 'ifexpr' => false, 'else' => false), $lineno, $tag);
|
22 |
-
}
|
23 |
-
|
24 |
-
/**
|
25 |
-
* Compiles the node to PHP.
|
26 |
-
*
|
27 |
-
* @param Twig_Compiler A Twig_Compiler instance
|
28 |
-
*/
|
29 |
-
public function compile(Twig_Compiler $compiler)
|
30 |
-
{
|
31 |
-
if ($this->getAttribute('else')) {
|
32 |
-
$compiler->write("\$context['_iterated'] = true;\n");
|
33 |
-
}
|
34 |
-
|
35 |
-
if ($this->getAttribute('with_loop')) {
|
36 |
-
$compiler
|
37 |
-
->write("++\$context['loop']['index0'];\n")
|
38 |
-
->write("++\$context['loop']['index'];\n")
|
39 |
-
->write("\$context['loop']['first'] = false;\n")
|
40 |
-
;
|
41 |
-
|
42 |
-
if (!$this->getAttribute('ifexpr')) {
|
43 |
-
$compiler
|
44 |
-
->write("if (isset(\$context['loop']['length'])) {\n")
|
45 |
-
->indent()
|
46 |
-
->write("--\$context['loop']['revindex0'];\n")
|
47 |
-
->write("--\$context['loop']['revindex'];\n")
|
48 |
-
->write("\$context['loop']['last'] = 0 === \$context['loop']['revindex0'];\n")
|
49 |
-
->outdent()
|
50 |
-
->write("}\n")
|
51 |
-
;
|
52 |
-
}
|
53 |
-
}
|
54 |
-
}
|
55 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2011 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Internal node used by the for node.
|
14 |
+
*
|
15 |
+
* @author Fabien Potencier <fabien@symfony.com>
|
16 |
+
*/
|
17 |
+
class Twig_Node_ForLoop extends Twig_Node
|
18 |
+
{
|
19 |
+
public function __construct($lineno, $tag = null)
|
20 |
+
{
|
21 |
+
parent::__construct(array(), array('with_loop' => false, 'ifexpr' => false, 'else' => false), $lineno, $tag);
|
22 |
+
}
|
23 |
+
|
24 |
+
/**
|
25 |
+
* Compiles the node to PHP.
|
26 |
+
*
|
27 |
+
* @param Twig_Compiler A Twig_Compiler instance
|
28 |
+
*/
|
29 |
+
public function compile(Twig_Compiler $compiler)
|
30 |
+
{
|
31 |
+
if ($this->getAttribute('else')) {
|
32 |
+
$compiler->write("\$context['_iterated'] = true;\n");
|
33 |
+
}
|
34 |
+
|
35 |
+
if ($this->getAttribute('with_loop')) {
|
36 |
+
$compiler
|
37 |
+
->write("++\$context['loop']['index0'];\n")
|
38 |
+
->write("++\$context['loop']['index'];\n")
|
39 |
+
->write("\$context['loop']['first'] = false;\n")
|
40 |
+
;
|
41 |
+
|
42 |
+
if (!$this->getAttribute('ifexpr')) {
|
43 |
+
$compiler
|
44 |
+
->write("if (isset(\$context['loop']['length'])) {\n")
|
45 |
+
->indent()
|
46 |
+
->write("--\$context['loop']['revindex0'];\n")
|
47 |
+
->write("--\$context['loop']['revindex'];\n")
|
48 |
+
->write("\$context['loop']['last'] = 0 === \$context['loop']['revindex0'];\n")
|
49 |
+
->outdent()
|
50 |
+
->write("}\n")
|
51 |
+
;
|
52 |
+
}
|
53 |
+
}
|
54 |
+
}
|
55 |
+
}
|
classes/Twig/Node/If.php
CHANGED
@@ -1,66 +1,66 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2009 Fabien Potencier
|
7 |
-
* (c) 2009 Armin Ronacher
|
8 |
-
*
|
9 |
-
* For the full copyright and license information, please view the LICENSE
|
10 |
-
* file that was distributed with this source code.
|
11 |
-
*/
|
12 |
-
|
13 |
-
/**
|
14 |
-
* Represents an if node.
|
15 |
-
*
|
16 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
17 |
-
*/
|
18 |
-
class Twig_Node_If extends Twig_Node
|
19 |
-
{
|
20 |
-
public function __construct(Twig_NodeInterface $tests, Twig_NodeInterface $else = null, $lineno, $tag = null)
|
21 |
-
{
|
22 |
-
parent::__construct(array('tests' => $tests, 'else' => $else), array(), $lineno, $tag);
|
23 |
-
}
|
24 |
-
|
25 |
-
/**
|
26 |
-
* Compiles the node to PHP.
|
27 |
-
*
|
28 |
-
* @param Twig_Compiler A Twig_Compiler instance
|
29 |
-
*/
|
30 |
-
public function compile(Twig_Compiler $compiler)
|
31 |
-
{
|
32 |
-
$compiler->addDebugInfo($this);
|
33 |
-
for ($i = 0, $count = count($this->getNode('tests')); $i < $count; $i += 2) {
|
34 |
-
if ($i > 0) {
|
35 |
-
$compiler
|
36 |
-
->outdent()
|
37 |
-
->write("} elseif (")
|
38 |
-
;
|
39 |
-
} else {
|
40 |
-
$compiler
|
41 |
-
->write('if (')
|
42 |
-
;
|
43 |
-
}
|
44 |
-
|
45 |
-
$compiler
|
46 |
-
->subcompile($this->getNode('tests')->getNode($i))
|
47 |
-
->raw(") {\n")
|
48 |
-
->indent()
|
49 |
-
->subcompile($this->getNode('tests')->getNode($i + 1))
|
50 |
-
;
|
51 |
-
}
|
52 |
-
|
53 |
-
if ($this->hasNode('else') && null !== $this->getNode('else')) {
|
54 |
-
$compiler
|
55 |
-
->outdent()
|
56 |
-
->write("} else {\n")
|
57 |
-
->indent()
|
58 |
-
->subcompile($this->getNode('else'))
|
59 |
-
;
|
60 |
-
}
|
61 |
-
|
62 |
-
$compiler
|
63 |
-
->outdent()
|
64 |
-
->write("}\n");
|
65 |
-
}
|
66 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2009 Fabien Potencier
|
7 |
+
* (c) 2009 Armin Ronacher
|
8 |
+
*
|
9 |
+
* For the full copyright and license information, please view the LICENSE
|
10 |
+
* file that was distributed with this source code.
|
11 |
+
*/
|
12 |
+
|
13 |
+
/**
|
14 |
+
* Represents an if node.
|
15 |
+
*
|
16 |
+
* @author Fabien Potencier <fabien@symfony.com>
|
17 |
+
*/
|
18 |
+
class Twig_Node_If extends Twig_Node
|
19 |
+
{
|
20 |
+
public function __construct(Twig_NodeInterface $tests, Twig_NodeInterface $else = null, $lineno, $tag = null)
|
21 |
+
{
|
22 |
+
parent::__construct(array('tests' => $tests, 'else' => $else), array(), $lineno, $tag);
|
23 |
+
}
|
24 |
+
|
25 |
+
/**
|
26 |
+
* Compiles the node to PHP.
|
27 |
+
*
|
28 |
+
* @param Twig_Compiler A Twig_Compiler instance
|
29 |
+
*/
|
30 |
+
public function compile(Twig_Compiler $compiler)
|
31 |
+
{
|
32 |
+
$compiler->addDebugInfo($this);
|
33 |
+
for ($i = 0, $count = count($this->getNode('tests')); $i < $count; $i += 2) {
|
34 |
+
if ($i > 0) {
|
35 |
+
$compiler
|
36 |
+
->outdent()
|
37 |
+
->write("} elseif (")
|
38 |
+
;
|
39 |
+
} else {
|
40 |
+
$compiler
|
41 |
+
->write('if (')
|
42 |
+
;
|
43 |
+
}
|
44 |
+
|
45 |
+
$compiler
|
46 |
+
->subcompile($this->getNode('tests')->getNode($i))
|
47 |
+
->raw(") {\n")
|
48 |
+
->indent()
|
49 |
+
->subcompile($this->getNode('tests')->getNode($i + 1))
|
50 |
+
;
|
51 |
+
}
|
52 |
+
|
53 |
+
if ($this->hasNode('else') && null !== $this->getNode('else')) {
|
54 |
+
$compiler
|
55 |
+
->outdent()
|
56 |
+
->write("} else {\n")
|
57 |
+
->indent()
|
58 |
+
->subcompile($this->getNode('else'))
|
59 |
+
;
|
60 |
+
}
|
61 |
+
|
62 |
+
$compiler
|
63 |
+
->outdent()
|
64 |
+
->write("}\n");
|
65 |
+
}
|
66 |
+
}
|
classes/Twig/Node/Import.php
CHANGED
@@ -1,50 +1,50 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2009 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
/**
|
13 |
-
* Represents an import node.
|
14 |
-
*
|
15 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
16 |
-
*/
|
17 |
-
class Twig_Node_Import extends Twig_Node
|
18 |
-
{
|
19 |
-
public function __construct(Twig_Node_Expression $expr, Twig_Node_Expression $var, $lineno, $tag = null)
|
20 |
-
{
|
21 |
-
parent::__construct(array('expr' => $expr, 'var' => $var), array(), $lineno, $tag);
|
22 |
-
}
|
23 |
-
|
24 |
-
/**
|
25 |
-
* Compiles the node to PHP.
|
26 |
-
*
|
27 |
-
* @param Twig_Compiler A Twig_Compiler instance
|
28 |
-
*/
|
29 |
-
public function compile(Twig_Compiler $compiler)
|
30 |
-
{
|
31 |
-
$compiler
|
32 |
-
->addDebugInfo($this)
|
33 |
-
->write('')
|
34 |
-
->subcompile($this->getNode('var'))
|
35 |
-
->raw(' = ')
|
36 |
-
;
|
37 |
-
|
38 |
-
if ($this->getNode('expr') instanceof Twig_Node_Expression_Name && '_self' === $this->getNode('expr')->getAttribute('name')) {
|
39 |
-
$compiler->raw("\$this");
|
40 |
-
} else {
|
41 |
-
$compiler
|
42 |
-
->raw('$this->env->loadTemplate(')
|
43 |
-
->subcompile($this->getNode('expr'))
|
44 |
-
->raw(")")
|
45 |
-
;
|
46 |
-
}
|
47 |
-
|
48 |
-
$compiler->raw(";\n");
|
49 |
-
}
|
50 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2009 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Represents an import node.
|
14 |
+
*
|
15 |
+
* @author Fabien Potencier <fabien@symfony.com>
|
16 |
+
*/
|
17 |
+
class Twig_Node_Import extends Twig_Node
|
18 |
+
{
|
19 |
+
public function __construct(Twig_Node_Expression $expr, Twig_Node_Expression $var, $lineno, $tag = null)
|
20 |
+
{
|
21 |
+
parent::__construct(array('expr' => $expr, 'var' => $var), array(), $lineno, $tag);
|
22 |
+
}
|
23 |
+
|
24 |
+
/**
|
25 |
+
* Compiles the node to PHP.
|
26 |
+
*
|
27 |
+
* @param Twig_Compiler A Twig_Compiler instance
|
28 |
+
*/
|
29 |
+
public function compile(Twig_Compiler $compiler)
|
30 |
+
{
|
31 |
+
$compiler
|
32 |
+
->addDebugInfo($this)
|
33 |
+
->write('')
|
34 |
+
->subcompile($this->getNode('var'))
|
35 |
+
->raw(' = ')
|
36 |
+
;
|
37 |
+
|
38 |
+
if ($this->getNode('expr') instanceof Twig_Node_Expression_Name && '_self' === $this->getNode('expr')->getAttribute('name')) {
|
39 |
+
$compiler->raw("\$this");
|
40 |
+
} else {
|
41 |
+
$compiler
|
42 |
+
->raw('$this->env->loadTemplate(')
|
43 |
+
->subcompile($this->getNode('expr'))
|
44 |
+
->raw(")")
|
45 |
+
;
|
46 |
+
}
|
47 |
+
|
48 |
+
$compiler->raw(";\n");
|
49 |
+
}
|
50 |
+
}
|
classes/Twig/Node/Include.php
CHANGED
@@ -1,99 +1,99 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2009 Fabien Potencier
|
7 |
-
* (c) 2009 Armin Ronacher
|
8 |
-
*
|
9 |
-
* For the full copyright and license information, please view the LICENSE
|
10 |
-
* file that was distributed with this source code.
|
11 |
-
*/
|
12 |
-
|
13 |
-
/**
|
14 |
-
* Represents an include node.
|
15 |
-
*
|
16 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
17 |
-
*/
|
18 |
-
class Twig_Node_Include extends Twig_Node implements Twig_NodeOutputInterface
|
19 |
-
{
|
20 |
-
public function __construct(Twig_Node_Expression $expr, Twig_Node_Expression $variables = null, $only = false, $ignoreMissing = false, $lineno, $tag = null)
|
21 |
-
{
|
22 |
-
parent::__construct(array('expr' => $expr, 'variables' => $variables), array('only' => (bool) $only, 'ignore_missing' => (bool) $ignoreMissing), $lineno, $tag);
|
23 |
-
}
|
24 |
-
|
25 |
-
/**
|
26 |
-
* Compiles the node to PHP.
|
27 |
-
*
|
28 |
-
* @param Twig_Compiler A Twig_Compiler instance
|
29 |
-
*/
|
30 |
-
public function compile(Twig_Compiler $compiler)
|
31 |
-
{
|
32 |
-
$compiler->addDebugInfo($this);
|
33 |
-
|
34 |
-
if ($this->getAttribute('ignore_missing')) {
|
35 |
-
$compiler
|
36 |
-
->write("try {\n")
|
37 |
-
->indent()
|
38 |
-
;
|
39 |
-
}
|
40 |
-
|
41 |
-
$this->addGetTemplate($compiler);
|
42 |
-
|
43 |
-
$compiler->raw('->display(');
|
44 |
-
|
45 |
-
$this->addTemplateArguments($compiler);
|
46 |
-
|
47 |
-
$compiler->raw(");\n");
|
48 |
-
|
49 |
-
if ($this->getAttribute('ignore_missing')) {
|
50 |
-
$compiler
|
51 |
-
->outdent()
|
52 |
-
->write("} catch (Twig_Error_Loader \$e) {\n")
|
53 |
-
->indent()
|
54 |
-
->write("// ignore missing template\n")
|
55 |
-
->outdent()
|
56 |
-
->write("}\n\n")
|
57 |
-
;
|
58 |
-
}
|
59 |
-
}
|
60 |
-
|
61 |
-
protected function addGetTemplate(Twig_Compiler $compiler)
|
62 |
-
{
|
63 |
-
if ($this->getNode('expr') instanceof Twig_Node_Expression_Constant) {
|
64 |
-
$compiler
|
65 |
-
->write("\$this->env->loadTemplate(")
|
66 |
-
->subcompile($this->getNode('expr'))
|
67 |
-
->raw(")")
|
68 |
-
;
|
69 |
-
} else {
|
70 |
-
$compiler
|
71 |
-
->write("\$template = \$this->env->resolveTemplate(")
|
72 |
-
->subcompile($this->getNode('expr'))
|
73 |
-
->raw(");\n")
|
74 |
-
->write('$template')
|
75 |
-
;
|
76 |
-
}
|
77 |
-
}
|
78 |
-
|
79 |
-
protected function addTemplateArguments(Twig_Compiler $compiler)
|
80 |
-
{
|
81 |
-
if (false === $this->getAttribute('only')) {
|
82 |
-
if (null === $this->getNode('variables')) {
|
83 |
-
$compiler->raw('$context');
|
84 |
-
} else {
|
85 |
-
$compiler
|
86 |
-
->raw('array_merge($context, ')
|
87 |
-
->subcompile($this->getNode('variables'))
|
88 |
-
->raw(')')
|
89 |
-
;
|
90 |
-
}
|
91 |
-
} else {
|
92 |
-
if (null === $this->getNode('variables')) {
|
93 |
-
$compiler->raw('array()');
|
94 |
-
} else {
|
95 |
-
$compiler->subcompile($this->getNode('variables'));
|
96 |
-
}
|
97 |
-
}
|
98 |
-
}
|
99 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2009 Fabien Potencier
|
7 |
+
* (c) 2009 Armin Ronacher
|
8 |
+
*
|
9 |
+
* For the full copyright and license information, please view the LICENSE
|
10 |
+
* file that was distributed with this source code.
|
11 |
+
*/
|
12 |
+
|
13 |
+
/**
|
14 |
+
* Represents an include node.
|
15 |
+
*
|
16 |
+
* @author Fabien Potencier <fabien@symfony.com>
|
17 |
+
*/
|
18 |
+
class Twig_Node_Include extends Twig_Node implements Twig_NodeOutputInterface
|
19 |
+
{
|
20 |
+
public function __construct(Twig_Node_Expression $expr, Twig_Node_Expression $variables = null, $only = false, $ignoreMissing = false, $lineno, $tag = null)
|
21 |
+
{
|
22 |
+
parent::__construct(array('expr' => $expr, 'variables' => $variables), array('only' => (bool) $only, 'ignore_missing' => (bool) $ignoreMissing), $lineno, $tag);
|
23 |
+
}
|
24 |
+
|
25 |
+
/**
|
26 |
+
* Compiles the node to PHP.
|
27 |
+
*
|
28 |
+
* @param Twig_Compiler A Twig_Compiler instance
|
29 |
+
*/
|
30 |
+
public function compile(Twig_Compiler $compiler)
|
31 |
+
{
|
32 |
+
$compiler->addDebugInfo($this);
|
33 |
+
|
34 |
+
if ($this->getAttribute('ignore_missing')) {
|
35 |
+
$compiler
|
36 |
+
->write("try {\n")
|
37 |
+
->indent()
|
38 |
+
;
|
39 |
+
}
|
40 |
+
|
41 |
+
$this->addGetTemplate($compiler);
|
42 |
+
|
43 |
+
$compiler->raw('->display(');
|
44 |
+
|
45 |
+
$this->addTemplateArguments($compiler);
|
46 |
+
|
47 |
+
$compiler->raw(");\n");
|
48 |
+
|
49 |
+
if ($this->getAttribute('ignore_missing')) {
|
50 |
+
$compiler
|
51 |
+
->outdent()
|
52 |
+
->write("} catch (Twig_Error_Loader \$e) {\n")
|
53 |
+
->indent()
|
54 |
+
->write("// ignore missing template\n")
|
55 |
+
->outdent()
|
56 |
+
->write("}\n\n")
|
57 |
+
;
|
58 |
+
}
|
59 |
+
}
|
60 |
+
|
61 |
+
protected function addGetTemplate(Twig_Compiler $compiler)
|
62 |
+
{
|
63 |
+
if ($this->getNode('expr') instanceof Twig_Node_Expression_Constant) {
|
64 |
+
$compiler
|
65 |
+
->write("\$this->env->loadTemplate(")
|
66 |
+
->subcompile($this->getNode('expr'))
|
67 |
+
->raw(")")
|
68 |
+
;
|
69 |
+
} else {
|
70 |
+
$compiler
|
71 |
+
->write("\$template = \$this->env->resolveTemplate(")
|
72 |
+
->subcompile($this->getNode('expr'))
|
73 |
+
->raw(");\n")
|
74 |
+
->write('$template')
|
75 |
+
;
|
76 |
+
}
|
77 |
+
}
|
78 |
+
|
79 |
+
protected function addTemplateArguments(Twig_Compiler $compiler)
|
80 |
+
{
|
81 |
+
if (false === $this->getAttribute('only')) {
|
82 |
+
if (null === $this->getNode('variables')) {
|
83 |
+
$compiler->raw('$context');
|
84 |
+
} else {
|
85 |
+
$compiler
|
86 |
+
->raw('array_merge($context, ')
|
87 |
+
->subcompile($this->getNode('variables'))
|
88 |
+
->raw(')')
|
89 |
+
;
|
90 |
+
}
|
91 |
+
} else {
|
92 |
+
if (null === $this->getNode('variables')) {
|
93 |
+
$compiler->raw('array()');
|
94 |
+
} else {
|
95 |
+
$compiler->subcompile($this->getNode('variables'));
|
96 |
+
}
|
97 |
+
}
|
98 |
+
}
|
99 |
+
}
|
classes/Twig/Node/Macro.php
CHANGED
@@ -1,96 +1,96 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2009 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
/**
|
13 |
-
* Represents a macro node.
|
14 |
-
*
|
15 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
16 |
-
*/
|
17 |
-
class Twig_Node_Macro extends Twig_Node
|
18 |
-
{
|
19 |
-
public function __construct($name, Twig_NodeInterface $body, Twig_NodeInterface $arguments, $lineno, $tag = null)
|
20 |
-
{
|
21 |
-
parent::__construct(array('body' => $body, 'arguments' => $arguments), array('name' => $name), $lineno, $tag);
|
22 |
-
}
|
23 |
-
|
24 |
-
/**
|
25 |
-
* Compiles the node to PHP.
|
26 |
-
*
|
27 |
-
* @param Twig_Compiler A Twig_Compiler instance
|
28 |
-
*/
|
29 |
-
public function compile(Twig_Compiler $compiler)
|
30 |
-
{
|
31 |
-
$compiler
|
32 |
-
->addDebugInfo($this)
|
33 |
-
->write(sprintf("public function get%s(", $this->getAttribute('name')))
|
34 |
-
;
|
35 |
-
|
36 |
-
$count = count($this->getNode('arguments'));
|
37 |
-
$pos = 0;
|
38 |
-
foreach ($this->getNode('arguments') as $name => $default) {
|
39 |
-
$compiler
|
40 |
-
->raw('$_'.$name.' = ')
|
41 |
-
->subcompile($default)
|
42 |
-
;
|
43 |
-
|
44 |
-
if (++$pos < $count) {
|
45 |
-
$compiler->raw(', ');
|
46 |
-
}
|
47 |
-
}
|
48 |
-
|
49 |
-
$compiler
|
50 |
-
->raw(")\n")
|
51 |
-
->write("{\n")
|
52 |
-
->indent()
|
53 |
-
;
|
54 |
-
|
55 |
-
if (!count($this->getNode('arguments'))) {
|
56 |
-
$compiler->write("\$context = \$this->env->getGlobals();\n\n");
|
57 |
-
} else {
|
58 |
-
$compiler
|
59 |
-
->write("\$context = \$this->env->mergeGlobals(array(\n")
|
60 |
-
->indent()
|
61 |
-
;
|
62 |
-
|
63 |
-
foreach ($this->getNode('arguments') as $name => $default) {
|
64 |
-
$compiler
|
65 |
-
->write('')
|
66 |
-
->string($name)
|
67 |
-
->raw(' => $_'.$name)
|
68 |
-
->raw(",\n")
|
69 |
-
;
|
70 |
-
}
|
71 |
-
|
72 |
-
$compiler
|
73 |
-
->outdent()
|
74 |
-
->write("));\n\n")
|
75 |
-
;
|
76 |
-
}
|
77 |
-
|
78 |
-
$compiler
|
79 |
-
->write("\$blocks = array();\n\n")
|
80 |
-
->write("ob_start();\n")
|
81 |
-
->write("try {\n")
|
82 |
-
->indent()
|
83 |
-
->subcompile($this->getNode('body'))
|
84 |
-
->outdent()
|
85 |
-
->write("} catch (Exception \$e) {\n")
|
86 |
-
->indent()
|
87 |
-
->write("ob_end_clean();\n\n")
|
88 |
-
->write("throw \$e;\n")
|
89 |
-
->outdent()
|
90 |
-
->write("}\n\n")
|
91 |
-
->write("return ('' === \$tmp = ob_get_clean()) ? '' : new Twig_Markup(\$tmp, \$this->env->getCharset());\n")
|
92 |
-
->outdent()
|
93 |
-
->write("}\n\n")
|
94 |
-
;
|
95 |
-
}
|
96 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2009 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Represents a macro node.
|
14 |
+
*
|
15 |
+
* @author Fabien Potencier <fabien@symfony.com>
|
16 |
+
*/
|
17 |
+
class Twig_Node_Macro extends Twig_Node
|
18 |
+
{
|
19 |
+
public function __construct($name, Twig_NodeInterface $body, Twig_NodeInterface $arguments, $lineno, $tag = null)
|
20 |
+
{
|
21 |
+
parent::__construct(array('body' => $body, 'arguments' => $arguments), array('name' => $name), $lineno, $tag);
|
22 |
+
}
|
23 |
+
|
24 |
+
/**
|
25 |
+
* Compiles the node to PHP.
|
26 |
+
*
|
27 |
+
* @param Twig_Compiler A Twig_Compiler instance
|
28 |
+
*/
|
29 |
+
public function compile(Twig_Compiler $compiler)
|
30 |
+
{
|
31 |
+
$compiler
|
32 |
+
->addDebugInfo($this)
|
33 |
+
->write(sprintf("public function get%s(", $this->getAttribute('name')))
|
34 |
+
;
|
35 |
+
|
36 |
+
$count = count($this->getNode('arguments'));
|
37 |
+
$pos = 0;
|
38 |
+
foreach ($this->getNode('arguments') as $name => $default) {
|
39 |
+
$compiler
|
40 |
+
->raw('$_'.$name.' = ')
|
41 |
+
->subcompile($default)
|
42 |
+
;
|
43 |
+
|
44 |
+
if (++$pos < $count) {
|
45 |
+
$compiler->raw(', ');
|
46 |
+
}
|
47 |
+
}
|
48 |
+
|
49 |
+
$compiler
|
50 |
+
->raw(")\n")
|
51 |
+
->write("{\n")
|
52 |
+
->indent()
|
53 |
+
;
|
54 |
+
|
55 |
+
if (!count($this->getNode('arguments'))) {
|
56 |
+
$compiler->write("\$context = \$this->env->getGlobals();\n\n");
|
57 |
+
} else {
|
58 |
+
$compiler
|
59 |
+
->write("\$context = \$this->env->mergeGlobals(array(\n")
|
60 |
+
->indent()
|
61 |
+
;
|
62 |
+
|
63 |
+
foreach ($this->getNode('arguments') as $name => $default) {
|
64 |
+
$compiler
|
65 |
+
->write('')
|
66 |
+
->string($name)
|
67 |
+
->raw(' => $_'.$name)
|
68 |
+
->raw(",\n")
|
69 |
+
;
|
70 |
+
}
|
71 |
+
|
72 |
+
$compiler
|
73 |
+
->outdent()
|
74 |
+
->write("));\n\n")
|
75 |
+
;
|
76 |
+
}
|
77 |
+
|
78 |
+
$compiler
|
79 |
+
->write("\$blocks = array();\n\n")
|
80 |
+
->write("ob_start();\n")
|
81 |
+
->write("try {\n")
|
82 |
+
->indent()
|
83 |
+
->subcompile($this->getNode('body'))
|
84 |
+
->outdent()
|
85 |
+
->write("} catch (Exception \$e) {\n")
|
86 |
+
->indent()
|
87 |
+
->write("ob_end_clean();\n\n")
|
88 |
+
->write("throw \$e;\n")
|
89 |
+
->outdent()
|
90 |
+
->write("}\n\n")
|
91 |
+
->write("return ('' === \$tmp = ob_get_clean()) ? '' : new Twig_Markup(\$tmp, \$this->env->getCharset());\n")
|
92 |
+
->outdent()
|
93 |
+
->write("}\n\n")
|
94 |
+
;
|
95 |
+
}
|
96 |
+
}
|
classes/Twig/Node/Module.php
CHANGED
@@ -1,383 +1,383 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2009 Fabien Potencier
|
7 |
-
* (c) 2009 Armin Ronacher
|
8 |
-
*
|
9 |
-
* For the full copyright and license information, please view the LICENSE
|
10 |
-
* file that was distributed with this source code.
|
11 |
-
*/
|
12 |
-
|
13 |
-
/**
|
14 |
-
* Represents a module node.
|
15 |
-
*
|
16 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
17 |
-
*/
|
18 |
-
class Twig_Node_Module extends Twig_Node
|
19 |
-
{
|
20 |
-
public function __construct(Twig_NodeInterface $body, Twig_Node_Expression $parent = null, Twig_NodeInterface $blocks, Twig_NodeInterface $macros, Twig_NodeInterface $traits, $embeddedTemplates, $filename)
|
21 |
-
{
|
22 |
-
// embedded templates are set as attributes so that they are only visited once by the visitors
|
23 |
-
parent::__construct(array('parent' => $parent, 'body' => $body, 'blocks' => $blocks, 'macros' => $macros, 'traits' => $traits), array('filename' => $filename, 'index' => null, 'embedded_templates' => $embeddedTemplates), 1);
|
24 |
-
}
|
25 |
-
|
26 |
-
public function setIndex($index)
|
27 |
-
{
|
28 |
-
$this->setAttribute('index', $index);
|
29 |
-
}
|
30 |
-
|
31 |
-
/**
|
32 |
-
* Compiles the node to PHP.
|
33 |
-
*
|
34 |
-
* @param Twig_Compiler A Twig_Compiler instance
|
35 |
-
*/
|
36 |
-
public function compile(Twig_Compiler $compiler)
|
37 |
-
{
|
38 |
-
$this->compileTemplate($compiler);
|
39 |
-
|
40 |
-
foreach ($this->getAttribute('embedded_templates') as $template) {
|
41 |
-
$compiler->subcompile($template);
|
42 |
-
}
|
43 |
-
}
|
44 |
-
|
45 |
-
protected function compileTemplate(Twig_Compiler $compiler)
|
46 |
-
{
|
47 |
-
if (!$this->getAttribute('index')) {
|
48 |
-
$compiler->write('<?php');
|
49 |
-
}
|
50 |
-
|
51 |
-
$this->compileClassHeader($compiler);
|
52 |
-
|
53 |
-
if (count($this->getNode('blocks')) || count($this->getNode('traits')) || null === $this->getNode('parent') || $this->getNode('parent') instanceof Twig_Node_Expression_Constant) {
|
54 |
-
$this->compileConstructor($compiler);
|
55 |
-
}
|
56 |
-
|
57 |
-
$this->compileGetParent($compiler);
|
58 |
-
|
59 |
-
$this->compileDisplayHeader($compiler);
|
60 |
-
|
61 |
-
$this->compileDisplayBody($compiler);
|
62 |
-
|
63 |
-
$this->compileDisplayFooter($compiler);
|
64 |
-
|
65 |
-
$compiler->subcompile($this->getNode('blocks'));
|
66 |
-
|
67 |
-
$this->compileMacros($compiler);
|
68 |
-
|
69 |
-
$this->compileGetTemplateName($compiler);
|
70 |
-
|
71 |
-
$this->compileIsTraitable($compiler);
|
72 |
-
|
73 |
-
$this->compileDebugInfo($compiler);
|
74 |
-
|
75 |
-
$this->compileClassFooter($compiler);
|
76 |
-
}
|
77 |
-
|
78 |
-
protected function compileGetParent(Twig_Compiler $compiler)
|
79 |
-
{
|
80 |
-
if (null === $this->getNode('parent')) {
|
81 |
-
return;
|
82 |
-
}
|
83 |
-
|
84 |
-
$compiler
|
85 |
-
->write("protected function doGetParent(array \$context)\n", "{\n")
|
86 |
-
->indent()
|
87 |
-
->write("return ")
|
88 |
-
;
|
89 |
-
|
90 |
-
if ($this->getNode('parent') instanceof Twig_Node_Expression_Constant) {
|
91 |
-
$compiler->subcompile($this->getNode('parent'));
|
92 |
-
} else {
|
93 |
-
$compiler
|
94 |
-
->raw("\$this->env->resolveTemplate(")
|
95 |
-
->subcompile($this->getNode('parent'))
|
96 |
-
->raw(")")
|
97 |
-
;
|
98 |
-
}
|
99 |
-
|
100 |
-
$compiler
|
101 |
-
->raw(";\n")
|
102 |
-
->outdent()
|
103 |
-
->write("}\n\n")
|
104 |
-
;
|
105 |
-
}
|
106 |
-
|
107 |
-
protected function compileDisplayBody(Twig_Compiler $compiler)
|
108 |
-
{
|
109 |
-
$compiler->subcompile($this->getNode('body'));
|
110 |
-
|
111 |
-
if (null !== $this->getNode('parent')) {
|
112 |
-
if ($this->getNode('parent') instanceof Twig_Node_Expression_Constant) {
|
113 |
-
$compiler->write("\$this->parent");
|
114 |
-
} else {
|
115 |
-
$compiler->write("\$this->getParent(\$context)");
|
116 |
-
}
|
117 |
-
$compiler->raw("->display(\$context, array_merge(\$this->blocks, \$blocks));\n");
|
118 |
-
}
|
119 |
-
}
|
120 |
-
|
121 |
-
protected function compileClassHeader(Twig_Compiler $compiler)
|
122 |
-
{
|
123 |
-
$compiler
|
124 |
-
->write("\n\n")
|
125 |
-
// if the filename contains */, add a blank to avoid a PHP parse error
|
126 |
-
->write("/* ".str_replace('*/', '* /', $this->getAttribute('filename'))." */\n")
|
127 |
-
->write('class '.$compiler->getEnvironment()->getTemplateClass($this->getAttribute('filename'), $this->getAttribute('index')))
|
128 |
-
->raw(sprintf(" extends %s\n", $compiler->getEnvironment()->getBaseTemplateClass()))
|
129 |
-
->write("{\n")
|
130 |
-
->indent()
|
131 |
-
;
|
132 |
-
}
|
133 |
-
|
134 |
-
protected function compileConstructor(Twig_Compiler $compiler)
|
135 |
-
{
|
136 |
-
$compiler
|
137 |
-
->write("public function __construct(Twig_Environment \$env)\n", "{\n")
|
138 |
-
->indent()
|
139 |
-
->write("parent::__construct(\$env);\n\n")
|
140 |
-
;
|
141 |
-
|
142 |
-
// parent
|
143 |
-
if (null === $this->getNode('parent')) {
|
144 |
-
$compiler->write("\$this->parent = false;\n\n");
|
145 |
-
} elseif ($this->getNode('parent') instanceof Twig_Node_Expression_Constant) {
|
146 |
-
$compiler
|
147 |
-
->write("\$this->parent = \$this->env->loadTemplate(")
|
148 |
-
->subcompile($this->getNode('parent'))
|
149 |
-
->raw(");\n\n")
|
150 |
-
;
|
151 |
-
}
|
152 |
-
|
153 |
-
$countTraits = count($this->getNode('traits'));
|
154 |
-
if ($countTraits) {
|
155 |
-
// traits
|
156 |
-
foreach ($this->getNode('traits') as $i => $trait) {
|
157 |
-
$this->compileLoadTemplate($compiler, $trait->getNode('template'), sprintf('$_trait_%s', $i));
|
158 |
-
|
159 |
-
$compiler
|
160 |
-
->addDebugInfo($trait->getNode('template'))
|
161 |
-
->write(sprintf("if (!\$_trait_%s->isTraitable()) {\n", $i))
|
162 |
-
->indent()
|
163 |
-
->write("throw new Twig_Error_Runtime('Template \"'.")
|
164 |
-
->subcompile($trait->getNode('template'))
|
165 |
-
->raw(".'\" cannot be used as a trait.');\n")
|
166 |
-
->outdent()
|
167 |
-
->write("}\n")
|
168 |
-
->write(sprintf("\$_trait_%s_blocks = \$_trait_%s->getBlocks();\n\n", $i, $i))
|
169 |
-
;
|
170 |
-
|
171 |
-
foreach ($trait->getNode('targets') as $key => $value) {
|
172 |
-
$compiler
|
173 |
-
->write(sprintf("if (!isset(\$_trait_%s_blocks[", $i))
|
174 |
-
->string($key)
|
175 |
-
->raw("])) {\n")
|
176 |
-
->indent()
|
177 |
-
->write("throw new Twig_Error_Runtime(sprintf('Block ")
|
178 |
-
->string($key)
|
179 |
-
->raw(" is not defined in trait ")
|
180 |
-
->subcompile($trait->getNode('template'))
|
181 |
-
->raw(".'));\n")
|
182 |
-
->outdent()
|
183 |
-
->write("}\n\n")
|
184 |
-
|
185 |
-
->write(sprintf("\$_trait_%s_blocks[", $i))
|
186 |
-
->subcompile($value)
|
187 |
-
->raw(sprintf("] = \$_trait_%s_blocks[", $i))
|
188 |
-
->string($key)
|
189 |
-
->raw(sprintf("]; unset(\$_trait_%s_blocks[", $i))
|
190 |
-
->string($key)
|
191 |
-
->raw("]);\n\n")
|
192 |
-
;
|
193 |
-
}
|
194 |
-
}
|
195 |
-
|
196 |
-
if ($countTraits > 1) {
|
197 |
-
$compiler
|
198 |
-
->write("\$this->traits = array_merge(\n")
|
199 |
-
->indent()
|
200 |
-
;
|
201 |
-
|
202 |
-
for ($i = 0; $i < $countTraits; $i++) {
|
203 |
-
$compiler
|
204 |
-
->write(sprintf("\$_trait_%s_blocks".($i == $countTraits - 1 ? '' : ',')."\n", $i))
|
205 |
-
;
|
206 |
-
}
|
207 |
-
|
208 |
-
$compiler
|
209 |
-
->outdent()
|
210 |
-
->write(");\n\n")
|
211 |
-
;
|
212 |
-
} else {
|
213 |
-
$compiler
|
214 |
-
->write("\$this->traits = \$_trait_0_blocks;\n\n")
|
215 |
-
;
|
216 |
-
}
|
217 |
-
|
218 |
-
$compiler
|
219 |
-
->write("\$this->blocks = array_merge(\n")
|
220 |
-
->indent()
|
221 |
-
->write("\$this->traits,\n")
|
222 |
-
->write("array(\n")
|
223 |
-
;
|
224 |
-
} else {
|
225 |
-
$compiler
|
226 |
-
->write("\$this->blocks = array(\n")
|
227 |
-
;
|
228 |
-
}
|
229 |
-
|
230 |
-
// blocks
|
231 |
-
$compiler
|
232 |
-
->indent()
|
233 |
-
;
|
234 |
-
|
235 |
-
foreach ($this->getNode('blocks') as $name => $node) {
|
236 |
-
$compiler
|
237 |
-
->write(sprintf("'%s' => array(\$this, 'block_%s'),\n", $name, $name))
|
238 |
-
;
|
239 |
-
}
|
240 |
-
|
241 |
-
if ($countTraits) {
|
242 |
-
$compiler
|
243 |
-
->outdent()
|
244 |
-
->write(")\n")
|
245 |
-
;
|
246 |
-
}
|
247 |
-
|
248 |
-
$compiler
|
249 |
-
->outdent()
|
250 |
-
->write(");\n")
|
251 |
-
->outdent()
|
252 |
-
->write("}\n\n");
|
253 |
-
;
|
254 |
-
}
|
255 |
-
|
256 |
-
protected function compileDisplayHeader(Twig_Compiler $compiler)
|
257 |
-
{
|
258 |
-
$compiler
|
259 |
-
->write("protected function doDisplay(array \$context, array \$blocks = array())\n", "{\n")
|
260 |
-
->indent()
|
261 |
-
;
|
262 |
-
}
|
263 |
-
|
264 |
-
protected function compileDisplayFooter(Twig_Compiler $compiler)
|
265 |
-
{
|
266 |
-
$compiler
|
267 |
-
->outdent()
|
268 |
-
->write("}\n\n")
|
269 |
-
;
|
270 |
-
}
|
271 |
-
|
272 |
-
protected function compileClassFooter(Twig_Compiler $compiler)
|
273 |
-
{
|
274 |
-
$compiler
|
275 |
-
->outdent()
|
276 |
-
->write("}\n")
|
277 |
-
;
|
278 |
-
}
|
279 |
-
|
280 |
-
protected function compileMacros(Twig_Compiler $compiler)
|
281 |
-
{
|
282 |
-
$compiler->subcompile($this->getNode('macros'));
|
283 |
-
}
|
284 |
-
|
285 |
-
protected function compileGetTemplateName(Twig_Compiler $compiler)
|
286 |
-
{
|
287 |
-
$compiler
|
288 |
-
->write("public function getTemplateName()\n", "{\n")
|
289 |
-
->indent()
|
290 |
-
->write('return ')
|
291 |
-
->repr($this->getAttribute('filename'))
|
292 |
-
->raw(";\n")
|
293 |
-
->outdent()
|
294 |
-
->write("}\n\n")
|
295 |
-
;
|
296 |
-
}
|
297 |
-
|
298 |
-
protected function compileIsTraitable(Twig_Compiler $compiler)
|
299 |
-
{
|
300 |
-
// A template can be used as a trait if:
|
301 |
-
// * it has no parent
|
302 |
-
// * it has no macros
|
303 |
-
// * it has no body
|
304 |
-
//
|
305 |
-
// Put another way, a template can be used as a trait if it
|
306 |
-
// only contains blocks and use statements.
|
307 |
-
$traitable = null === $this->getNode('parent') && 0 === count($this->getNode('macros'));
|
308 |
-
if ($traitable) {
|
309 |
-
if ($this->getNode('body') instanceof Twig_Node_Body) {
|
310 |
-
$nodes = $this->getNode('body')->getNode(0);
|
311 |
-
} else {
|
312 |
-
$nodes = $this->getNode('body');
|
313 |
-
}
|
314 |
-
|
315 |
-
if (!count($nodes)) {
|
316 |
-
$nodes = new Twig_Node(array($nodes));
|
317 |
-
}
|
318 |
-
|
319 |
-
foreach ($nodes as $node) {
|
320 |
-
if (!count($node)) {
|
321 |
-
continue;
|
322 |
-
}
|
323 |
-
|
324 |
-
if ($node instanceof Twig_Node_Text && ctype_space($node->getAttribute('data'))) {
|
325 |
-
continue;
|
326 |
-
}
|
327 |
-
|
328 |
-
if ($node instanceof Twig_Node_BlockReference) {
|
329 |
-
continue;
|
330 |
-
}
|
331 |
-
|
332 |
-
$traitable = false;
|
333 |
-
break;
|
334 |
-
}
|
335 |
-
}
|
336 |
-
|
337 |
-
if ($traitable) {
|
338 |
-
return;
|
339 |
-
}
|
340 |
-
|
341 |
-
$compiler
|
342 |
-
->write("public function isTraitable()\n", "{\n")
|
343 |
-
->indent()
|
344 |
-
->write(sprintf("return %s;\n", $traitable ? 'true' : 'false'))
|
345 |
-
->outdent()
|
346 |
-
->write("}\n\n")
|
347 |
-
;
|
348 |
-
}
|
349 |
-
|
350 |
-
protected function compileDebugInfo(Twig_Compiler $compiler)
|
351 |
-
{
|
352 |
-
$compiler
|
353 |
-
->write("public function getDebugInfo()\n", "{\n")
|
354 |
-
->indent()
|
355 |
-
->write(sprintf("return %s;\n", str_replace("\n", '', var_export(array_reverse($compiler->getDebugInfo(), true), true))))
|
356 |
-
->outdent()
|
357 |
-
->write("}\n")
|
358 |
-
;
|
359 |
-
}
|
360 |
-
|
361 |
-
protected function compileLoadTemplate(Twig_Compiler $compiler, $node, $var)
|
362 |
-
{
|
363 |
-
if ($node instanceof Twig_Node_Expression_Constant) {
|
364 |
-
$compiler
|
365 |
-
->write(sprintf("%s = \$this->env->loadTemplate(", $var))
|
366 |
-
->subcompile($node)
|
367 |
-
->raw(");\n")
|
368 |
-
;
|
369 |
-
} else {
|
370 |
-
$compiler
|
371 |
-
->write(sprintf("%s = ", $var))
|
372 |
-
->subcompile($node)
|
373 |
-
->raw(";\n")
|
374 |
-
->write(sprintf("if (!%s", $var))
|
375 |
-
->raw(" instanceof Twig_Template) {\n")
|
376 |
-
->indent()
|
377 |
-
->write(sprintf("%s = \$this->env->loadTemplate(%s);\n", $var, $var))
|
378 |
-
->outdent()
|
379 |
-
->write("}\n")
|
380 |
-
;
|
381 |
-
}
|
382 |
-
}
|
383 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2009 Fabien Potencier
|
7 |
+
* (c) 2009 Armin Ronacher
|
8 |
+
*
|
9 |
+
* For the full copyright and license information, please view the LICENSE
|
10 |
+
* file that was distributed with this source code.
|
11 |
+
*/
|
12 |
+
|
13 |
+
/**
|
14 |
+
* Represents a module node.
|
15 |
+
*
|
16 |
+
* @author Fabien Potencier <fabien@symfony.com>
|
17 |
+
*/
|
18 |
+
class Twig_Node_Module extends Twig_Node
|
19 |
+
{
|
20 |
+
public function __construct(Twig_NodeInterface $body, Twig_Node_Expression $parent = null, Twig_NodeInterface $blocks, Twig_NodeInterface $macros, Twig_NodeInterface $traits, $embeddedTemplates, $filename)
|
21 |
+
{
|
22 |
+
// embedded templates are set as attributes so that they are only visited once by the visitors
|
23 |
+
parent::__construct(array('parent' => $parent, 'body' => $body, 'blocks' => $blocks, 'macros' => $macros, 'traits' => $traits), array('filename' => $filename, 'index' => null, 'embedded_templates' => $embeddedTemplates), 1);
|
24 |
+
}
|
25 |
+
|
26 |
+
public function setIndex($index)
|
27 |
+
{
|
28 |
+
$this->setAttribute('index', $index);
|
29 |
+
}
|
30 |
+
|
31 |
+
/**
|
32 |
+
* Compiles the node to PHP.
|
33 |
+
*
|
34 |
+
* @param Twig_Compiler A Twig_Compiler instance
|
35 |
+
*/
|
36 |
+
public function compile(Twig_Compiler $compiler)
|
37 |
+
{
|
38 |
+
$this->compileTemplate($compiler);
|
39 |
+
|
40 |
+
foreach ($this->getAttribute('embedded_templates') as $template) {
|
41 |
+
$compiler->subcompile($template);
|
42 |
+
}
|
43 |
+
}
|
44 |
+
|
45 |
+
protected function compileTemplate(Twig_Compiler $compiler)
|
46 |
+
{
|
47 |
+
if (!$this->getAttribute('index')) {
|
48 |
+
$compiler->write('<?php');
|
49 |
+
}
|
50 |
+
|
51 |
+
$this->compileClassHeader($compiler);
|
52 |
+
|
53 |
+
if (count($this->getNode('blocks')) || count($this->getNode('traits')) || null === $this->getNode('parent') || $this->getNode('parent') instanceof Twig_Node_Expression_Constant) {
|
54 |
+
$this->compileConstructor($compiler);
|
55 |
+
}
|
56 |
+
|
57 |
+
$this->compileGetParent($compiler);
|
58 |
+
|
59 |
+
$this->compileDisplayHeader($compiler);
|
60 |
+
|
61 |
+
$this->compileDisplayBody($compiler);
|
62 |
+
|
63 |
+
$this->compileDisplayFooter($compiler);
|
64 |
+
|
65 |
+
$compiler->subcompile($this->getNode('blocks'));
|
66 |
+
|
67 |
+
$this->compileMacros($compiler);
|
68 |
+
|
69 |
+
$this->compileGetTemplateName($compiler);
|
70 |
+
|
71 |
+
$this->compileIsTraitable($compiler);
|
72 |
+
|
73 |
+
$this->compileDebugInfo($compiler);
|
74 |
+
|
75 |
+
$this->compileClassFooter($compiler);
|
76 |
+
}
|
77 |
+
|
78 |
+
protected function compileGetParent(Twig_Compiler $compiler)
|
79 |
+
{
|
80 |
+
if (null === $this->getNode('parent')) {
|
81 |
+
return;
|
82 |
+
}
|
83 |
+
|
84 |
+
$compiler
|
85 |
+
->write("protected function doGetParent(array \$context)\n", "{\n")
|
86 |
+
->indent()
|
87 |
+
->write("return ")
|
88 |
+
;
|
89 |
+
|
90 |
+
if ($this->getNode('parent') instanceof Twig_Node_Expression_Constant) {
|
91 |
+
$compiler->subcompile($this->getNode('parent'));
|
92 |
+
} else {
|
93 |
+
$compiler
|
94 |
+
->raw("\$this->env->resolveTemplate(")
|
95 |
+
->subcompile($this->getNode('parent'))
|
96 |
+
->raw(")")
|
97 |
+
;
|
98 |
+
}
|
99 |
+
|
100 |
+
$compiler
|
101 |
+
->raw(";\n")
|
102 |
+
->outdent()
|
103 |
+
->write("}\n\n")
|
104 |
+
;
|
105 |
+
}
|
106 |
+
|
107 |
+
protected function compileDisplayBody(Twig_Compiler $compiler)
|
108 |
+
{
|
109 |
+
$compiler->subcompile($this->getNode('body'));
|
110 |
+
|
111 |
+
if (null !== $this->getNode('parent')) {
|
112 |
+
if ($this->getNode('parent') instanceof Twig_Node_Expression_Constant) {
|
113 |
+
$compiler->write("\$this->parent");
|
114 |
+
} else {
|
115 |
+
$compiler->write("\$this->getParent(\$context)");
|
116 |
+
}
|
117 |
+
$compiler->raw("->display(\$context, array_merge(\$this->blocks, \$blocks));\n");
|
118 |
+
}
|
119 |
+
}
|
120 |
+
|
121 |
+
protected function compileClassHeader(Twig_Compiler $compiler)
|
122 |
+
{
|
123 |
+
$compiler
|
124 |
+
->write("\n\n")
|
125 |
+
// if the filename contains */, add a blank to avoid a PHP parse error
|
126 |
+
->write("/* ".str_replace('*/', '* /', $this->getAttribute('filename'))." */\n")
|
127 |
+
->write('class '.$compiler->getEnvironment()->getTemplateClass($this->getAttribute('filename'), $this->getAttribute('index')))
|
128 |
+
->raw(sprintf(" extends %s\n", $compiler->getEnvironment()->getBaseTemplateClass()))
|
129 |
+
->write("{\n")
|
130 |
+
->indent()
|
131 |
+
;
|
132 |
+
}
|
133 |
+
|
134 |
+
protected function compileConstructor(Twig_Compiler $compiler)
|
135 |
+
{
|
136 |
+
$compiler
|
137 |
+
->write("public function __construct(Twig_Environment \$env)\n", "{\n")
|
138 |
+
->indent()
|
139 |
+
->write("parent::__construct(\$env);\n\n")
|
140 |
+
;
|
141 |
+
|
142 |
+
// parent
|
143 |
+
if (null === $this->getNode('parent')) {
|
144 |
+
$compiler->write("\$this->parent = false;\n\n");
|
145 |
+
} elseif ($this->getNode('parent') instanceof Twig_Node_Expression_Constant) {
|
146 |
+
$compiler
|
147 |
+
->write("\$this->parent = \$this->env->loadTemplate(")
|
148 |
+
->subcompile($this->getNode('parent'))
|
149 |
+
->raw(");\n\n")
|
150 |
+
;
|
151 |
+
}
|
152 |
+
|
153 |
+
$countTraits = count($this->getNode('traits'));
|
154 |
+
if ($countTraits) {
|
155 |
+
// traits
|
156 |
+
foreach ($this->getNode('traits') as $i => $trait) {
|
157 |
+
$this->compileLoadTemplate($compiler, $trait->getNode('template'), sprintf('$_trait_%s', $i));
|
158 |
+
|
159 |
+
$compiler
|
160 |
+
->addDebugInfo($trait->getNode('template'))
|
161 |
+
->write(sprintf("if (!\$_trait_%s->isTraitable()) {\n", $i))
|
162 |
+
->indent()
|
163 |
+
->write("throw new Twig_Error_Runtime('Template \"'.")
|
164 |
+
->subcompile($trait->getNode('template'))
|
165 |
+
->raw(".'\" cannot be used as a trait.');\n")
|
166 |
+
->outdent()
|
167 |
+
->write("}\n")
|
168 |
+
->write(sprintf("\$_trait_%s_blocks = \$_trait_%s->getBlocks();\n\n", $i, $i))
|
169 |
+
;
|
170 |
+
|
171 |
+
foreach ($trait->getNode('targets') as $key => $value) {
|
172 |
+
$compiler
|
173 |
+
->write(sprintf("if (!isset(\$_trait_%s_blocks[", $i))
|
174 |
+
->string($key)
|
175 |
+
->raw("])) {\n")
|
176 |
+
->indent()
|
177 |
+
->write("throw new Twig_Error_Runtime(sprintf('Block ")
|
178 |
+
->string($key)
|
179 |
+
->raw(" is not defined in trait ")
|
180 |
+
->subcompile($trait->getNode('template'))
|
181 |
+
->raw(".'));\n")
|
182 |
+
->outdent()
|
183 |
+
->write("}\n\n")
|
184 |
+
|
185 |
+
->write(sprintf("\$_trait_%s_blocks[", $i))
|
186 |
+
->subcompile($value)
|
187 |
+
->raw(sprintf("] = \$_trait_%s_blocks[", $i))
|
188 |
+
->string($key)
|
189 |
+
->raw(sprintf("]; unset(\$_trait_%s_blocks[", $i))
|
190 |
+
->string($key)
|
191 |
+
->raw("]);\n\n")
|
192 |
+
;
|
193 |
+
}
|
194 |
+
}
|
195 |
+
|
196 |
+
if ($countTraits > 1) {
|
197 |
+
$compiler
|
198 |
+
->write("\$this->traits = array_merge(\n")
|
199 |
+
->indent()
|
200 |
+
;
|
201 |
+
|
202 |
+
for ($i = 0; $i < $countTraits; $i++) {
|
203 |
+
$compiler
|
204 |
+
->write(sprintf("\$_trait_%s_blocks".($i == $countTraits - 1 ? '' : ',')."\n", $i))
|
205 |
+
;
|
206 |
+
}
|
207 |
+
|
208 |
+
$compiler
|
209 |
+
->outdent()
|
210 |
+
->write(");\n\n")
|
211 |
+
;
|
212 |
+
} else {
|
213 |
+
$compiler
|
214 |
+
->write("\$this->traits = \$_trait_0_blocks;\n\n")
|
215 |
+
;
|
216 |
+
}
|
217 |
+
|
218 |
+
$compiler
|
219 |
+
->write("\$this->blocks = array_merge(\n")
|
220 |
+
->indent()
|
221 |
+
->write("\$this->traits,\n")
|
222 |
+
->write("array(\n")
|
223 |
+
;
|
224 |
+
} else {
|
225 |
+
$compiler
|
226 |
+
->write("\$this->blocks = array(\n")
|
227 |
+
;
|
228 |
+
}
|
229 |
+
|
230 |
+
// blocks
|
231 |
+
$compiler
|
232 |
+
->indent()
|
233 |
+
;
|
234 |
+
|
235 |
+
foreach ($this->getNode('blocks') as $name => $node) {
|
236 |
+
$compiler
|
237 |
+
->write(sprintf("'%s' => array(\$this, 'block_%s'),\n", $name, $name))
|
238 |
+
;
|
239 |
+
}
|
240 |
+
|
241 |
+
if ($countTraits) {
|
242 |
+
$compiler
|
243 |
+
->outdent()
|
244 |
+
->write(")\n")
|
245 |
+
;
|
246 |
+
}
|
247 |
+
|
248 |
+
$compiler
|
249 |
+
->outdent()
|
250 |
+
->write(");\n")
|
251 |
+
->outdent()
|
252 |
+
->write("}\n\n");
|
253 |
+
;
|
254 |
+
}
|
255 |
+
|
256 |
+
protected function compileDisplayHeader(Twig_Compiler $compiler)
|
257 |
+
{
|
258 |
+
$compiler
|
259 |
+
->write("protected function doDisplay(array \$context, array \$blocks = array())\n", "{\n")
|
260 |
+
->indent()
|
261 |
+
;
|
262 |
+
}
|
263 |
+
|
264 |
+
protected function compileDisplayFooter(Twig_Compiler $compiler)
|
265 |
+
{
|
266 |
+
$compiler
|
267 |
+
->outdent()
|
268 |
+
->write("}\n\n")
|
269 |
+
;
|
270 |
+
}
|
271 |
+
|
272 |
+
protected function compileClassFooter(Twig_Compiler $compiler)
|
273 |
+
{
|
274 |
+
$compiler
|
275 |
+
->outdent()
|
276 |
+
->write("}\n")
|
277 |
+
;
|
278 |
+
}
|
279 |
+
|
280 |
+
protected function compileMacros(Twig_Compiler $compiler)
|
281 |
+
{
|
282 |
+
$compiler->subcompile($this->getNode('macros'));
|
283 |
+
}
|
284 |
+
|
285 |
+
protected function compileGetTemplateName(Twig_Compiler $compiler)
|
286 |
+
{
|
287 |
+
$compiler
|
288 |
+
->write("public function getTemplateName()\n", "{\n")
|
289 |
+
->indent()
|
290 |
+
->write('return ')
|
291 |
+
->repr($this->getAttribute('filename'))
|
292 |
+
->raw(";\n")
|
293 |
+
->outdent()
|
294 |
+
->write("}\n\n")
|
295 |
+
;
|
296 |
+
}
|
297 |
+
|
298 |
+
protected function compileIsTraitable(Twig_Compiler $compiler)
|
299 |
+
{
|
300 |
+
// A template can be used as a trait if:
|
301 |
+
// * it has no parent
|
302 |
+
// * it has no macros
|
303 |
+
// * it has no body
|
304 |
+
//
|
305 |
+
// Put another way, a template can be used as a trait if it
|
306 |
+
// only contains blocks and use statements.
|
307 |
+
$traitable = null === $this->getNode('parent') && 0 === count($this->getNode('macros'));
|
308 |
+
if ($traitable) {
|
309 |
+
if ($this->getNode('body') instanceof Twig_Node_Body) {
|
310 |
+
$nodes = $this->getNode('body')->getNode(0);
|
311 |
+
} else {
|
312 |
+
$nodes = $this->getNode('body');
|
313 |
+
}
|
314 |
+
|
315 |
+
if (!count($nodes)) {
|
316 |
+
$nodes = new Twig_Node(array($nodes));
|
317 |
+
}
|
318 |
+
|
319 |
+
foreach ($nodes as $node) {
|
320 |
+
if (!count($node)) {
|
321 |
+
continue;
|
322 |
+
}
|
323 |
+
|
324 |
+
if ($node instanceof Twig_Node_Text && ctype_space($node->getAttribute('data'))) {
|
325 |
+
continue;
|
326 |
+
}
|
327 |
+
|
328 |
+
if ($node instanceof Twig_Node_BlockReference) {
|
329 |
+
continue;
|
330 |
+
}
|
331 |
+
|
332 |
+
$traitable = false;
|
333 |
+
break;
|
334 |
+
}
|
335 |
+
}
|
336 |
+
|
337 |
+
if ($traitable) {
|
338 |
+
return;
|
339 |
+
}
|
340 |
+
|
341 |
+
$compiler
|
342 |
+
->write("public function isTraitable()\n", "{\n")
|
343 |
+
->indent()
|
344 |
+
->write(sprintf("return %s;\n", $traitable ? 'true' : 'false'))
|
345 |
+
->outdent()
|
346 |
+
->write("}\n\n")
|
347 |
+
;
|
348 |
+
}
|
349 |
+
|
350 |
+
protected function compileDebugInfo(Twig_Compiler $compiler)
|
351 |
+
{
|
352 |
+
$compiler
|
353 |
+
->write("public function getDebugInfo()\n", "{\n")
|
354 |
+
->indent()
|
355 |
+
->write(sprintf("return %s;\n", str_replace("\n", '', var_export(array_reverse($compiler->getDebugInfo(), true), true))))
|
356 |
+
->outdent()
|
357 |
+
->write("}\n")
|
358 |
+
;
|
359 |
+
}
|
360 |
+
|
361 |
+
protected function compileLoadTemplate(Twig_Compiler $compiler, $node, $var)
|
362 |
+
{
|
363 |
+
if ($node instanceof Twig_Node_Expression_Constant) {
|
364 |
+
$compiler
|
365 |
+
->write(sprintf("%s = \$this->env->loadTemplate(", $var))
|
366 |
+
->subcompile($node)
|
367 |
+
->raw(");\n")
|
368 |
+
;
|
369 |
+
} else {
|
370 |
+
$compiler
|
371 |
+
->write(sprintf("%s = ", $var))
|
372 |
+
->subcompile($node)
|
373 |
+
->raw(";\n")
|
374 |
+
->write(sprintf("if (!%s", $var))
|
375 |
+
->raw(" instanceof Twig_Template) {\n")
|
376 |
+
->indent()
|
377 |
+
->write(sprintf("%s = \$this->env->loadTemplate(%s);\n", $var, $var))
|
378 |
+
->outdent()
|
379 |
+
->write("}\n")
|
380 |
+
;
|
381 |
+
}
|
382 |
+
}
|
383 |
+
}
|
classes/Twig/Node/Print.php
CHANGED
@@ -1,39 +1,39 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2009 Fabien Potencier
|
7 |
-
* (c) 2009 Armin Ronacher
|
8 |
-
*
|
9 |
-
* For the full copyright and license information, please view the LICENSE
|
10 |
-
* file that was distributed with this source code.
|
11 |
-
*/
|
12 |
-
|
13 |
-
/**
|
14 |
-
* Represents a node that outputs an expression.
|
15 |
-
*
|
16 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
17 |
-
*/
|
18 |
-
class Twig_Node_Print extends Twig_Node implements Twig_NodeOutputInterface
|
19 |
-
{
|
20 |
-
public function __construct(Twig_Node_Expression $expr, $lineno, $tag = null)
|
21 |
-
{
|
22 |
-
parent::__construct(array('expr' => $expr), array(), $lineno, $tag);
|
23 |
-
}
|
24 |
-
|
25 |
-
/**
|
26 |
-
* Compiles the node to PHP.
|
27 |
-
*
|
28 |
-
* @param Twig_Compiler A Twig_Compiler instance
|
29 |
-
*/
|
30 |
-
public function compile(Twig_Compiler $compiler)
|
31 |
-
{
|
32 |
-
$compiler
|
33 |
-
->addDebugInfo($this)
|
34 |
-
->write('echo ')
|
35 |
-
->subcompile($this->getNode('expr'))
|
36 |
-
->raw(";\n")
|
37 |
-
;
|
38 |
-
}
|
39 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2009 Fabien Potencier
|
7 |
+
* (c) 2009 Armin Ronacher
|
8 |
+
*
|
9 |
+
* For the full copyright and license information, please view the LICENSE
|
10 |
+
* file that was distributed with this source code.
|
11 |
+
*/
|
12 |
+
|
13 |
+
/**
|
14 |
+
* Represents a node that outputs an expression.
|
15 |
+
*
|
16 |
+
* @author Fabien Potencier <fabien@symfony.com>
|
17 |
+
*/
|
18 |
+
class Twig_Node_Print extends Twig_Node implements Twig_NodeOutputInterface
|
19 |
+
{
|
20 |
+
public function __construct(Twig_Node_Expression $expr, $lineno, $tag = null)
|
21 |
+
{
|
22 |
+
parent::__construct(array('expr' => $expr), array(), $lineno, $tag);
|
23 |
+
}
|
24 |
+
|
25 |
+
/**
|
26 |
+
* Compiles the node to PHP.
|
27 |
+
*
|
28 |
+
* @param Twig_Compiler A Twig_Compiler instance
|
29 |
+
*/
|
30 |
+
public function compile(Twig_Compiler $compiler)
|
31 |
+
{
|
32 |
+
$compiler
|
33 |
+
->addDebugInfo($this)
|
34 |
+
->write('echo ')
|
35 |
+
->subcompile($this->getNode('expr'))
|
36 |
+
->raw(";\n")
|
37 |
+
;
|
38 |
+
}
|
39 |
+
}
|
classes/Twig/Node/Sandbox.php
CHANGED
@@ -1,47 +1,47 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2010 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
/**
|
13 |
-
* Represents a sandbox node.
|
14 |
-
*
|
15 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
16 |
-
*/
|
17 |
-
class Twig_Node_Sandbox extends Twig_Node
|
18 |
-
{
|
19 |
-
public function __construct(Twig_NodeInterface $body, $lineno, $tag = null)
|
20 |
-
{
|
21 |
-
parent::__construct(array('body' => $body), array(), $lineno, $tag);
|
22 |
-
}
|
23 |
-
|
24 |
-
/**
|
25 |
-
* Compiles the node to PHP.
|
26 |
-
*
|
27 |
-
* @param Twig_Compiler A Twig_Compiler instance
|
28 |
-
*/
|
29 |
-
public function compile(Twig_Compiler $compiler)
|
30 |
-
{
|
31 |
-
$compiler
|
32 |
-
->addDebugInfo($this)
|
33 |
-
->write("\$sandbox = \$this->env->getExtension('sandbox');\n")
|
34 |
-
->write("if (!\$alreadySandboxed = \$sandbox->isSandboxed()) {\n")
|
35 |
-
->indent()
|
36 |
-
->write("\$sandbox->enableSandbox();\n")
|
37 |
-
->outdent()
|
38 |
-
->write("}\n")
|
39 |
-
->subcompile($this->getNode('body'))
|
40 |
-
->write("if (!\$alreadySandboxed) {\n")
|
41 |
-
->indent()
|
42 |
-
->write("\$sandbox->disableSandbox();\n")
|
43 |
-
->outdent()
|
44 |
-
->write("}\n")
|
45 |
-
;
|
46 |
-
}
|
47 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2010 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Represents a sandbox node.
|
14 |
+
*
|
15 |
+
* @author Fabien Potencier <fabien@symfony.com>
|
16 |
+
*/
|
17 |
+
class Twig_Node_Sandbox extends Twig_Node
|
18 |
+
{
|
19 |
+
public function __construct(Twig_NodeInterface $body, $lineno, $tag = null)
|
20 |
+
{
|
21 |
+
parent::__construct(array('body' => $body), array(), $lineno, $tag);
|
22 |
+
}
|
23 |
+
|
24 |
+
/**
|
25 |
+
* Compiles the node to PHP.
|
26 |
+
*
|
27 |
+
* @param Twig_Compiler A Twig_Compiler instance
|
28 |
+
*/
|
29 |
+
public function compile(Twig_Compiler $compiler)
|
30 |
+
{
|
31 |
+
$compiler
|
32 |
+
->addDebugInfo($this)
|
33 |
+
->write("\$sandbox = \$this->env->getExtension('sandbox');\n")
|
34 |
+
->write("if (!\$alreadySandboxed = \$sandbox->isSandboxed()) {\n")
|
35 |
+
->indent()
|
36 |
+
->write("\$sandbox->enableSandbox();\n")
|
37 |
+
->outdent()
|
38 |
+
->write("}\n")
|
39 |
+
->subcompile($this->getNode('body'))
|
40 |
+
->write("if (!\$alreadySandboxed) {\n")
|
41 |
+
->indent()
|
42 |
+
->write("\$sandbox->disableSandbox();\n")
|
43 |
+
->outdent()
|
44 |
+
->write("}\n")
|
45 |
+
;
|
46 |
+
}
|
47 |
+
}
|
classes/Twig/Node/SandboxedModule.php
CHANGED
@@ -1,60 +1,60 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2009 Fabien Potencier
|
7 |
-
* (c) 2009 Armin Ronacher
|
8 |
-
*
|
9 |
-
* For the full copyright and license information, please view the LICENSE
|
10 |
-
* file that was distributed with this source code.
|
11 |
-
*/
|
12 |
-
|
13 |
-
/**
|
14 |
-
* Represents a module node.
|
15 |
-
*
|
16 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
17 |
-
*/
|
18 |
-
class Twig_Node_SandboxedModule extends Twig_Node_Module
|
19 |
-
{
|
20 |
-
protected $usedFilters;
|
21 |
-
protected $usedTags;
|
22 |
-
protected $usedFunctions;
|
23 |
-
|
24 |
-
public function __construct(Twig_Node_Module $node, array $usedFilters, array $usedTags, array $usedFunctions)
|
25 |
-
{
|
26 |
-
parent::__construct($node->getNode('body'), $node->getNode('parent'), $node->getNode('blocks'), $node->getNode('macros'), $node->getNode('traits'), $node->getAttribute('embedded_templates'), $node->getAttribute('filename'));
|
27 |
-
|
28 |
-
$this->setAttribute('index', $node->getAttribute('index'));
|
29 |
-
|
30 |
-
$this->usedFilters = $usedFilters;
|
31 |
-
$this->usedTags = $usedTags;
|
32 |
-
$this->usedFunctions = $usedFunctions;
|
33 |
-
}
|
34 |
-
|
35 |
-
protected function compileDisplayBody(Twig_Compiler $compiler)
|
36 |
-
{
|
37 |
-
$compiler->write("\$this->checkSecurity();\n");
|
38 |
-
|
39 |
-
parent::compileDisplayBody($compiler);
|
40 |
-
}
|
41 |
-
|
42 |
-
protected function compileDisplayFooter(Twig_Compiler $compiler)
|
43 |
-
{
|
44 |
-
parent::compileDisplayFooter($compiler);
|
45 |
-
|
46 |
-
$compiler
|
47 |
-
->write("protected function checkSecurity()\n", "{\n")
|
48 |
-
->indent()
|
49 |
-
->write("\$this->env->getExtension('sandbox')->checkSecurity(\n")
|
50 |
-
->indent()
|
51 |
-
->write(!$this->usedTags ? "array(),\n" : "array('".implode('\', \'', $this->usedTags)."'),\n")
|
52 |
-
->write(!$this->usedFilters ? "array(),\n" : "array('".implode('\', \'', $this->usedFilters)."'),\n")
|
53 |
-
->write(!$this->usedFunctions ? "array()\n" : "array('".implode('\', \'', $this->usedFunctions)."')\n")
|
54 |
-
->outdent()
|
55 |
-
->write(");\n")
|
56 |
-
->outdent()
|
57 |
-
->write("}\n\n")
|
58 |
-
;
|
59 |
-
}
|
60 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2009 Fabien Potencier
|
7 |
+
* (c) 2009 Armin Ronacher
|
8 |
+
*
|
9 |
+
* For the full copyright and license information, please view the LICENSE
|
10 |
+
* file that was distributed with this source code.
|
11 |
+
*/
|
12 |
+
|
13 |
+
/**
|
14 |
+
* Represents a module node.
|
15 |
+
*
|
16 |
+
* @author Fabien Potencier <fabien@symfony.com>
|
17 |
+
*/
|
18 |
+
class Twig_Node_SandboxedModule extends Twig_Node_Module
|
19 |
+
{
|
20 |
+
protected $usedFilters;
|
21 |
+
protected $usedTags;
|
22 |
+
protected $usedFunctions;
|
23 |
+
|
24 |
+
public function __construct(Twig_Node_Module $node, array $usedFilters, array $usedTags, array $usedFunctions)
|
25 |
+
{
|
26 |
+
parent::__construct($node->getNode('body'), $node->getNode('parent'), $node->getNode('blocks'), $node->getNode('macros'), $node->getNode('traits'), $node->getAttribute('embedded_templates'), $node->getAttribute('filename'));
|
27 |
+
|
28 |
+
$this->setAttribute('index', $node->getAttribute('index'));
|
29 |
+
|
30 |
+
$this->usedFilters = $usedFilters;
|
31 |
+
$this->usedTags = $usedTags;
|
32 |
+
$this->usedFunctions = $usedFunctions;
|
33 |
+
}
|
34 |
+
|
35 |
+
protected function compileDisplayBody(Twig_Compiler $compiler)
|
36 |
+
{
|
37 |
+
$compiler->write("\$this->checkSecurity();\n");
|
38 |
+
|
39 |
+
parent::compileDisplayBody($compiler);
|
40 |
+
}
|
41 |
+
|
42 |
+
protected function compileDisplayFooter(Twig_Compiler $compiler)
|
43 |
+
{
|
44 |
+
parent::compileDisplayFooter($compiler);
|
45 |
+
|
46 |
+
$compiler
|
47 |
+
->write("protected function checkSecurity()\n", "{\n")
|
48 |
+
->indent()
|
49 |
+
->write("\$this->env->getExtension('sandbox')->checkSecurity(\n")
|
50 |
+
->indent()
|
51 |
+
->write(!$this->usedTags ? "array(),\n" : "array('".implode('\', \'', $this->usedTags)."'),\n")
|
52 |
+
->write(!$this->usedFilters ? "array(),\n" : "array('".implode('\', \'', $this->usedFilters)."'),\n")
|
53 |
+
->write(!$this->usedFunctions ? "array()\n" : "array('".implode('\', \'', $this->usedFunctions)."')\n")
|
54 |
+
->outdent()
|
55 |
+
->write(");\n")
|
56 |
+
->outdent()
|
57 |
+
->write("}\n\n")
|
58 |
+
;
|
59 |
+
}
|
60 |
+
}
|
classes/Twig/Node/SandboxedPrint.php
CHANGED
@@ -1,59 +1,59 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2010 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
/**
|
13 |
-
* Twig_Node_SandboxedPrint adds a check for the __toString() method
|
14 |
-
* when the variable is an object and the sandbox is activated.
|
15 |
-
*
|
16 |
-
* When there is a simple Print statement, like {{ article }},
|
17 |
-
* and if the sandbox is enabled, we need to check that the __toString()
|
18 |
-
* method is allowed if 'article' is an object.
|
19 |
-
*
|
20 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
21 |
-
*/
|
22 |
-
class Twig_Node_SandboxedPrint extends Twig_Node_Print
|
23 |
-
{
|
24 |
-
public function __construct(Twig_Node_Expression $expr, $lineno, $tag = null)
|
25 |
-
{
|
26 |
-
parent::__construct($expr, $lineno, $tag);
|
27 |
-
}
|
28 |
-
|
29 |
-
/**
|
30 |
-
* Compiles the node to PHP.
|
31 |
-
*
|
32 |
-
* @param Twig_Compiler A Twig_Compiler instance
|
33 |
-
*/
|
34 |
-
public function compile(Twig_Compiler $compiler)
|
35 |
-
{
|
36 |
-
$compiler
|
37 |
-
->addDebugInfo($this)
|
38 |
-
->write('echo $this->env->getExtension(\'sandbox\')->ensureToStringAllowed(')
|
39 |
-
->subcompile($this->getNode('expr'))
|
40 |
-
->raw(");\n")
|
41 |
-
;
|
42 |
-
}
|
43 |
-
|
44 |
-
/**
|
45 |
-
* Removes node filters.
|
46 |
-
*
|
47 |
-
* This is mostly needed when another visitor adds filters (like the escaper one).
|
48 |
-
*
|
49 |
-
* @param Twig_Node $node A Node
|
50 |
-
*/
|
51 |
-
protected function removeNodeFilter($node)
|
52 |
-
{
|
53 |
-
if ($node instanceof Twig_Node_Expression_Filter) {
|
54 |
-
return $this->removeNodeFilter($node->getNode('node'));
|
55 |
-
}
|
56 |
-
|
57 |
-
return $node;
|
58 |
-
}
|
59 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2010 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Twig_Node_SandboxedPrint adds a check for the __toString() method
|
14 |
+
* when the variable is an object and the sandbox is activated.
|
15 |
+
*
|
16 |
+
* When there is a simple Print statement, like {{ article }},
|
17 |
+
* and if the sandbox is enabled, we need to check that the __toString()
|
18 |
+
* method is allowed if 'article' is an object.
|
19 |
+
*
|
20 |
+
* @author Fabien Potencier <fabien@symfony.com>
|
21 |
+
*/
|
22 |
+
class Twig_Node_SandboxedPrint extends Twig_Node_Print
|
23 |
+
{
|
24 |
+
public function __construct(Twig_Node_Expression $expr, $lineno, $tag = null)
|
25 |
+
{
|
26 |
+
parent::__construct($expr, $lineno, $tag);
|
27 |
+
}
|
28 |
+
|
29 |
+
/**
|
30 |
+
* Compiles the node to PHP.
|
31 |
+
*
|
32 |
+
* @param Twig_Compiler A Twig_Compiler instance
|
33 |
+
*/
|
34 |
+
public function compile(Twig_Compiler $compiler)
|
35 |
+
{
|
36 |
+
$compiler
|
37 |
+
->addDebugInfo($this)
|
38 |
+
->write('echo $this->env->getExtension(\'sandbox\')->ensureToStringAllowed(')
|
39 |
+
->subcompile($this->getNode('expr'))
|
40 |
+
->raw(");\n")
|
41 |
+
;
|
42 |
+
}
|
43 |
+
|
44 |
+
/**
|
45 |
+
* Removes node filters.
|
46 |
+
*
|
47 |
+
* This is mostly needed when another visitor adds filters (like the escaper one).
|
48 |
+
*
|
49 |
+
* @param Twig_Node $node A Node
|
50 |
+
*/
|
51 |
+
protected function removeNodeFilter($node)
|
52 |
+
{
|
53 |
+
if ($node instanceof Twig_Node_Expression_Filter) {
|
54 |
+
return $this->removeNodeFilter($node->getNode('node'));
|
55 |
+
}
|
56 |
+
|
57 |
+
return $node;
|
58 |
+
}
|
59 |
+
}
|
classes/Twig/Node/Set.php
CHANGED
@@ -1,101 +1,101 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2010 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
/**
|
13 |
-
* Represents a set node.
|
14 |
-
*
|
15 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
16 |
-
*/
|
17 |
-
class Twig_Node_Set extends Twig_Node
|
18 |
-
{
|
19 |
-
public function __construct($capture, Twig_NodeInterface $names, Twig_NodeInterface $values, $lineno, $tag = null)
|
20 |
-
{
|
21 |
-
parent::__construct(array('names' => $names, 'values' => $values), array('capture' => $capture, 'safe' => false), $lineno, $tag);
|
22 |
-
|
23 |
-
/*
|
24 |
-
* Optimizes the node when capture is used for a large block of text.
|
25 |
-
*
|
26 |
-
* {% set foo %}foo{% endset %} is compiled to $context['foo'] = new Twig_Markup("foo");
|
27 |
-
*/
|
28 |
-
if ($this->getAttribute('capture')) {
|
29 |
-
$this->setAttribute('safe', true);
|
30 |
-
|
31 |
-
$values = $this->getNode('values');
|
32 |
-
if ($values instanceof Twig_Node_Text) {
|
33 |
-
$this->setNode('values', new Twig_Node_Expression_Constant($values->getAttribute('data'), $values->getLine()));
|
34 |
-
$this->setAttribute('capture', false);
|
35 |
-
}
|
36 |
-
}
|
37 |
-
}
|
38 |
-
|
39 |
-
/**
|
40 |
-
* Compiles the node to PHP.
|
41 |
-
*
|
42 |
-
* @param Twig_Compiler A Twig_Compiler instance
|
43 |
-
*/
|
44 |
-
public function compile(Twig_Compiler $compiler)
|
45 |
-
{
|
46 |
-
$compiler->addDebugInfo($this);
|
47 |
-
|
48 |
-
if (count($this->getNode('names')) > 1) {
|
49 |
-
$compiler->write('list(');
|
50 |
-
foreach ($this->getNode('names') as $idx => $node) {
|
51 |
-
if ($idx) {
|
52 |
-
$compiler->raw(', ');
|
53 |
-
}
|
54 |
-
|
55 |
-
$compiler->subcompile($node);
|
56 |
-
}
|
57 |
-
$compiler->raw(')');
|
58 |
-
} else {
|
59 |
-
if ($this->getAttribute('capture')) {
|
60 |
-
$compiler
|
61 |
-
->write("ob_start();\n")
|
62 |
-
->subcompile($this->getNode('values'))
|
63 |
-
;
|
64 |
-
}
|
65 |
-
|
66 |
-
$compiler->subcompile($this->getNode('names'), false);
|
67 |
-
|
68 |
-
if ($this->getAttribute('capture')) {
|
69 |
-
$compiler->raw(" = ('' === \$tmp = ob_get_clean()) ? '' : new Twig_Markup(\$tmp, \$this->env->getCharset())");
|
70 |
-
}
|
71 |
-
}
|
72 |
-
|
73 |
-
if (!$this->getAttribute('capture')) {
|
74 |
-
$compiler->raw(' = ');
|
75 |
-
|
76 |
-
if (count($this->getNode('names')) > 1) {
|
77 |
-
$compiler->write('array(');
|
78 |
-
foreach ($this->getNode('values') as $idx => $value) {
|
79 |
-
if ($idx) {
|
80 |
-
$compiler->raw(', ');
|
81 |
-
}
|
82 |
-
|
83 |
-
$compiler->subcompile($value);
|
84 |
-
}
|
85 |
-
$compiler->raw(')');
|
86 |
-
} else {
|
87 |
-
if ($this->getAttribute('safe')) {
|
88 |
-
$compiler
|
89 |
-
->raw("('' === \$tmp = ")
|
90 |
-
->subcompile($this->getNode('values'))
|
91 |
-
->raw(") ? '' : new Twig_Markup(\$tmp, \$this->env->getCharset())")
|
92 |
-
;
|
93 |
-
} else {
|
94 |
-
$compiler->subcompile($this->getNode('values'));
|
95 |
-
}
|
96 |
-
}
|
97 |
-
}
|
98 |
-
|
99 |
-
$compiler->raw(";\n");
|
100 |
-
}
|
101 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2010 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Represents a set node.
|
14 |
+
*
|
15 |
+
* @author Fabien Potencier <fabien@symfony.com>
|
16 |
+
*/
|
17 |
+
class Twig_Node_Set extends Twig_Node
|
18 |
+
{
|
19 |
+
public function __construct($capture, Twig_NodeInterface $names, Twig_NodeInterface $values, $lineno, $tag = null)
|
20 |
+
{
|
21 |
+
parent::__construct(array('names' => $names, 'values' => $values), array('capture' => $capture, 'safe' => false), $lineno, $tag);
|
22 |
+
|
23 |
+
/*
|
24 |
+
* Optimizes the node when capture is used for a large block of text.
|
25 |
+
*
|
26 |
+
* {% set foo %}foo{% endset %} is compiled to $context['foo'] = new Twig_Markup("foo");
|
27 |
+
*/
|
28 |
+
if ($this->getAttribute('capture')) {
|
29 |
+
$this->setAttribute('safe', true);
|
30 |
+
|
31 |
+
$values = $this->getNode('values');
|
32 |
+
if ($values instanceof Twig_Node_Text) {
|
33 |
+
$this->setNode('values', new Twig_Node_Expression_Constant($values->getAttribute('data'), $values->getLine()));
|
34 |
+
$this->setAttribute('capture', false);
|
35 |
+
}
|
36 |
+
}
|
37 |
+
}
|
38 |
+
|
39 |
+
/**
|
40 |
+
* Compiles the node to PHP.
|
41 |
+
*
|
42 |
+
* @param Twig_Compiler A Twig_Compiler instance
|
43 |
+
*/
|
44 |
+
public function compile(Twig_Compiler $compiler)
|
45 |
+
{
|
46 |
+
$compiler->addDebugInfo($this);
|
47 |
+
|
48 |
+
if (count($this->getNode('names')) > 1) {
|
49 |
+
$compiler->write('list(');
|
50 |
+
foreach ($this->getNode('names') as $idx => $node) {
|
51 |
+
if ($idx) {
|
52 |
+
$compiler->raw(', ');
|
53 |
+
}
|
54 |
+
|
55 |
+
$compiler->subcompile($node);
|
56 |
+
}
|
57 |
+
$compiler->raw(')');
|
58 |
+
} else {
|
59 |
+
if ($this->getAttribute('capture')) {
|
60 |
+
$compiler
|
61 |
+
->write("ob_start();\n")
|
62 |
+
->subcompile($this->getNode('values'))
|
63 |
+
;
|
64 |
+
}
|
65 |
+
|
66 |
+
$compiler->subcompile($this->getNode('names'), false);
|
67 |
+
|
68 |
+
if ($this->getAttribute('capture')) {
|
69 |
+
$compiler->raw(" = ('' === \$tmp = ob_get_clean()) ? '' : new Twig_Markup(\$tmp, \$this->env->getCharset())");
|
70 |
+
}
|
71 |
+
}
|
72 |
+
|
73 |
+
if (!$this->getAttribute('capture')) {
|
74 |
+
$compiler->raw(' = ');
|
75 |
+
|
76 |
+
if (count($this->getNode('names')) > 1) {
|
77 |
+
$compiler->write('array(');
|
78 |
+
foreach ($this->getNode('values') as $idx => $value) {
|
79 |
+
if ($idx) {
|
80 |
+
$compiler->raw(', ');
|
81 |
+
}
|
82 |
+
|
83 |
+
$compiler->subcompile($value);
|
84 |
+
}
|
85 |
+
$compiler->raw(')');
|
86 |
+
} else {
|
87 |
+
if ($this->getAttribute('safe')) {
|
88 |
+
$compiler
|
89 |
+
->raw("('' === \$tmp = ")
|
90 |
+
->subcompile($this->getNode('values'))
|
91 |
+
->raw(") ? '' : new Twig_Markup(\$tmp, \$this->env->getCharset())")
|
92 |
+
;
|
93 |
+
} else {
|
94 |
+
$compiler->subcompile($this->getNode('values'));
|
95 |
+
}
|
96 |
+
}
|
97 |
+
}
|
98 |
+
|
99 |
+
$compiler->raw(";\n");
|
100 |
+
}
|
101 |
+
}
|
classes/Twig/Node/SetTemp.php
CHANGED
@@ -1,35 +1,35 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2011 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
class Twig_Node_SetTemp extends Twig_Node
|
13 |
-
{
|
14 |
-
public function __construct($name, $lineno)
|
15 |
-
{
|
16 |
-
parent::__construct(array(), array('name' => $name), $lineno);
|
17 |
-
}
|
18 |
-
|
19 |
-
public function compile(Twig_Compiler $compiler)
|
20 |
-
{
|
21 |
-
$name = $this->getAttribute('name');
|
22 |
-
$compiler
|
23 |
-
->addDebugInfo($this)
|
24 |
-
->write('if (isset($context[')
|
25 |
-
->string($name)
|
26 |
-
->raw('])) { $_')
|
27 |
-
->raw($name)
|
28 |
-
->raw('_ = $context[')
|
29 |
-
->repr($name)
|
30 |
-
->raw(']; } else { $_')
|
31 |
-
->raw($name)
|
32 |
-
->raw("_ = null; }\n")
|
33 |
-
;
|
34 |
-
}
|
35 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2011 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
|
12 |
+
class Twig_Node_SetTemp extends Twig_Node
|
13 |
+
{
|
14 |
+
public function __construct($name, $lineno)
|
15 |
+
{
|
16 |
+
parent::__construct(array(), array('name' => $name), $lineno);
|
17 |
+
}
|
18 |
+
|
19 |
+
public function compile(Twig_Compiler $compiler)
|
20 |
+
{
|
21 |
+
$name = $this->getAttribute('name');
|
22 |
+
$compiler
|
23 |
+
->addDebugInfo($this)
|
24 |
+
->write('if (isset($context[')
|
25 |
+
->string($name)
|
26 |
+
->raw('])) { $_')
|
27 |
+
->raw($name)
|
28 |
+
->raw('_ = $context[')
|
29 |
+
->repr($name)
|
30 |
+
->raw(']; } else { $_')
|
31 |
+
->raw($name)
|
32 |
+
->raw("_ = null; }\n")
|
33 |
+
;
|
34 |
+
}
|
35 |
+
}
|
classes/Twig/Node/Spaceless.php
CHANGED
@@ -1,40 +1,40 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2010 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
/**
|
13 |
-
* Represents a spaceless node.
|
14 |
-
*
|
15 |
-
* It removes spaces between HTML tags.
|
16 |
-
*
|
17 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
18 |
-
*/
|
19 |
-
class Twig_Node_Spaceless extends Twig_Node
|
20 |
-
{
|
21 |
-
public function __construct(Twig_NodeInterface $body, $lineno, $tag = 'spaceless')
|
22 |
-
{
|
23 |
-
parent::__construct(array('body' => $body), array(), $lineno, $tag);
|
24 |
-
}
|
25 |
-
|
26 |
-
/**
|
27 |
-
* Compiles the node to PHP.
|
28 |
-
*
|
29 |
-
* @param Twig_Compiler A Twig_Compiler instance
|
30 |
-
*/
|
31 |
-
public function compile(Twig_Compiler $compiler)
|
32 |
-
{
|
33 |
-
$compiler
|
34 |
-
->addDebugInfo($this)
|
35 |
-
->write("ob_start();\n")
|
36 |
-
->subcompile($this->getNode('body'))
|
37 |
-
->write("echo trim(preg_replace('/>\s+</', '><', ob_get_clean()));\n")
|
38 |
-
;
|
39 |
-
}
|
40 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2010 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Represents a spaceless node.
|
14 |
+
*
|
15 |
+
* It removes spaces between HTML tags.
|
16 |
+
*
|
17 |
+
* @author Fabien Potencier <fabien@symfony.com>
|
18 |
+
*/
|
19 |
+
class Twig_Node_Spaceless extends Twig_Node
|
20 |
+
{
|
21 |
+
public function __construct(Twig_NodeInterface $body, $lineno, $tag = 'spaceless')
|
22 |
+
{
|
23 |
+
parent::__construct(array('body' => $body), array(), $lineno, $tag);
|
24 |
+
}
|
25 |
+
|
26 |
+
/**
|
27 |
+
* Compiles the node to PHP.
|
28 |
+
*
|
29 |
+
* @param Twig_Compiler A Twig_Compiler instance
|
30 |
+
*/
|
31 |
+
public function compile(Twig_Compiler $compiler)
|
32 |
+
{
|
33 |
+
$compiler
|
34 |
+
->addDebugInfo($this)
|
35 |
+
->write("ob_start();\n")
|
36 |
+
->subcompile($this->getNode('body'))
|
37 |
+
->write("echo trim(preg_replace('/>\s+</', '><', ob_get_clean()));\n")
|
38 |
+
;
|
39 |
+
}
|
40 |
+
}
|
classes/Twig/Node/Text.php
CHANGED
@@ -1,39 +1,39 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2009 Fabien Potencier
|
7 |
-
* (c) 2009 Armin Ronacher
|
8 |
-
*
|
9 |
-
* For the full copyright and license information, please view the LICENSE
|
10 |
-
* file that was distributed with this source code.
|
11 |
-
*/
|
12 |
-
|
13 |
-
/**
|
14 |
-
* Represents a text node.
|
15 |
-
*
|
16 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
17 |
-
*/
|
18 |
-
class Twig_Node_Text extends Twig_Node implements Twig_NodeOutputInterface
|
19 |
-
{
|
20 |
-
public function __construct($data, $lineno)
|
21 |
-
{
|
22 |
-
parent::__construct(array(), array('data' => $data), $lineno);
|
23 |
-
}
|
24 |
-
|
25 |
-
/**
|
26 |
-
* Compiles the node to PHP.
|
27 |
-
*
|
28 |
-
* @param Twig_Compiler A Twig_Compiler instance
|
29 |
-
*/
|
30 |
-
public function compile(Twig_Compiler $compiler)
|
31 |
-
{
|
32 |
-
$compiler
|
33 |
-
->addDebugInfo($this)
|
34 |
-
->write('echo ')
|
35 |
-
->string($this->getAttribute('data'))
|
36 |
-
->raw(";\n")
|
37 |
-
;
|
38 |
-
}
|
39 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2009 Fabien Potencier
|
7 |
+
* (c) 2009 Armin Ronacher
|
8 |
+
*
|
9 |
+
* For the full copyright and license information, please view the LICENSE
|
10 |
+
* file that was distributed with this source code.
|
11 |
+
*/
|
12 |
+
|
13 |
+
/**
|
14 |
+
* Represents a text node.
|
15 |
+
*
|
16 |
+
* @author Fabien Potencier <fabien@symfony.com>
|
17 |
+
*/
|
18 |
+
class Twig_Node_Text extends Twig_Node implements Twig_NodeOutputInterface
|
19 |
+
{
|
20 |
+
public function __construct($data, $lineno)
|
21 |
+
{
|
22 |
+
parent::__construct(array(), array('data' => $data), $lineno);
|
23 |
+
}
|
24 |
+
|
25 |
+
/**
|
26 |
+
* Compiles the node to PHP.
|
27 |
+
*
|
28 |
+
* @param Twig_Compiler A Twig_Compiler instance
|
29 |
+
*/
|
30 |
+
public function compile(Twig_Compiler $compiler)
|
31 |
+
{
|
32 |
+
$compiler
|
33 |
+
->addDebugInfo($this)
|
34 |
+
->write('echo ')
|
35 |
+
->string($this->getAttribute('data'))
|
36 |
+
->raw(";\n")
|
37 |
+
;
|
38 |
+
}
|
39 |
+
}
|
classes/Twig/NodeInterface.php
CHANGED
@@ -1,31 +1,31 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2010 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
/**
|
13 |
-
* Represents a node in the AST.
|
14 |
-
*
|
15 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
16 |
-
*
|
17 |
-
* @deprecated since 1.12 (to be removed in 3.0)
|
18 |
-
*/
|
19 |
-
interface Twig_NodeInterface extends Countable, IteratorAggregate
|
20 |
-
{
|
21 |
-
/**
|
22 |
-
* Compiles the node to PHP.
|
23 |
-
*
|
24 |
-
* @param Twig_Compiler A Twig_Compiler instance
|
25 |
-
*/
|
26 |
-
public function compile(Twig_Compiler $compiler);
|
27 |
-
|
28 |
-
public function getLine();
|
29 |
-
|
30 |
-
public function getNodeTag();
|
31 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2010 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Represents a node in the AST.
|
14 |
+
*
|
15 |
+
* @author Fabien Potencier <fabien@symfony.com>
|
16 |
+
*
|
17 |
+
* @deprecated since 1.12 (to be removed in 3.0)
|
18 |
+
*/
|
19 |
+
interface Twig_NodeInterface extends Countable, IteratorAggregate
|
20 |
+
{
|
21 |
+
/**
|
22 |
+
* Compiles the node to PHP.
|
23 |
+
*
|
24 |
+
* @param Twig_Compiler A Twig_Compiler instance
|
25 |
+
*/
|
26 |
+
public function compile(Twig_Compiler $compiler);
|
27 |
+
|
28 |
+
public function getLine();
|
29 |
+
|
30 |
+
public function getNodeTag();
|
31 |
+
}
|
classes/Twig/NodeOutputInterface.php
CHANGED
@@ -1,19 +1,19 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2010 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
/**
|
13 |
-
* Represents a displayable node in the AST.
|
14 |
-
*
|
15 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
16 |
-
*/
|
17 |
-
interface Twig_NodeOutputInterface
|
18 |
-
{
|
19 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2010 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Represents a displayable node in the AST.
|
14 |
+
*
|
15 |
+
* @author Fabien Potencier <fabien@symfony.com>
|
16 |
+
*/
|
17 |
+
interface Twig_NodeOutputInterface
|
18 |
+
{
|
19 |
+
}
|
classes/Twig/NodeTraverser.php
CHANGED
@@ -1,88 +1,88 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2009 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
/**
|
13 |
-
* Twig_NodeTraverser is a node traverser.
|
14 |
-
*
|
15 |
-
* It visits all nodes and their children and calls the given visitor for each.
|
16 |
-
*
|
17 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
18 |
-
*/
|
19 |
-
class Twig_NodeTraverser
|
20 |
-
{
|
21 |
-
protected $env;
|
22 |
-
protected $visitors;
|
23 |
-
|
24 |
-
/**
|
25 |
-
* Constructor.
|
26 |
-
*
|
27 |
-
* @param Twig_Environment $env A Twig_Environment instance
|
28 |
-
* @param Twig_NodeVisitorInterface[] $visitors An array of Twig_NodeVisitorInterface instances
|
29 |
-
*/
|
30 |
-
public function __construct(Twig_Environment $env, array $visitors = array())
|
31 |
-
{
|
32 |
-
$this->env = $env;
|
33 |
-
$this->visitors = array();
|
34 |
-
foreach ($visitors as $visitor) {
|
35 |
-
$this->addVisitor($visitor);
|
36 |
-
}
|
37 |
-
}
|
38 |
-
|
39 |
-
/**
|
40 |
-
* Adds a visitor.
|
41 |
-
*
|
42 |
-
* @param Twig_NodeVisitorInterface $visitor A Twig_NodeVisitorInterface instance
|
43 |
-
*/
|
44 |
-
public function addVisitor(Twig_NodeVisitorInterface $visitor)
|
45 |
-
{
|
46 |
-
if (!isset($this->visitors[$visitor->getPriority()])) {
|
47 |
-
$this->visitors[$visitor->getPriority()] = array();
|
48 |
-
}
|
49 |
-
|
50 |
-
$this->visitors[$visitor->getPriority()][] = $visitor;
|
51 |
-
}
|
52 |
-
|
53 |
-
/**
|
54 |
-
* Traverses a node and calls the registered visitors.
|
55 |
-
*
|
56 |
-
* @param Twig_NodeInterface $node A Twig_NodeInterface instance
|
57 |
-
*/
|
58 |
-
public function traverse(Twig_NodeInterface $node)
|
59 |
-
{
|
60 |
-
ksort($this->visitors);
|
61 |
-
foreach ($this->visitors as $visitors) {
|
62 |
-
foreach ($visitors as $visitor) {
|
63 |
-
$node = $this->traverseForVisitor($visitor, $node);
|
64 |
-
}
|
65 |
-
}
|
66 |
-
|
67 |
-
return $node;
|
68 |
-
}
|
69 |
-
|
70 |
-
protected function traverseForVisitor(Twig_NodeVisitorInterface $visitor, Twig_NodeInterface $node = null)
|
71 |
-
{
|
72 |
-
if (null === $node) {
|
73 |
-
return;
|
74 |
-
}
|
75 |
-
|
76 |
-
$node = $visitor->enterNode($node, $this->env);
|
77 |
-
|
78 |
-
foreach ($node as $k => $n) {
|
79 |
-
if (false !== $n = $this->traverseForVisitor($visitor, $n)) {
|
80 |
-
$node->setNode($k, $n);
|
81 |
-
} else {
|
82 |
-
$node->removeNode($k);
|
83 |
-
}
|
84 |
-
}
|
85 |
-
|
86 |
-
return $visitor->leaveNode($node, $this->env);
|
87 |
-
}
|
88 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2009 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Twig_NodeTraverser is a node traverser.
|
14 |
+
*
|
15 |
+
* It visits all nodes and their children and calls the given visitor for each.
|
16 |
+
*
|
17 |
+
* @author Fabien Potencier <fabien@symfony.com>
|
18 |
+
*/
|
19 |
+
class Twig_NodeTraverser
|
20 |
+
{
|
21 |
+
protected $env;
|
22 |
+
protected $visitors;
|
23 |
+
|
24 |
+
/**
|
25 |
+
* Constructor.
|
26 |
+
*
|
27 |
+
* @param Twig_Environment $env A Twig_Environment instance
|
28 |
+
* @param Twig_NodeVisitorInterface[] $visitors An array of Twig_NodeVisitorInterface instances
|
29 |
+
*/
|
30 |
+
public function __construct(Twig_Environment $env, array $visitors = array())
|
31 |
+
{
|
32 |
+
$this->env = $env;
|
33 |
+
$this->visitors = array();
|
34 |
+
foreach ($visitors as $visitor) {
|
35 |
+
$this->addVisitor($visitor);
|
36 |
+
}
|
37 |
+
}
|
38 |
+
|
39 |
+
/**
|
40 |
+
* Adds a visitor.
|
41 |
+
*
|
42 |
+
* @param Twig_NodeVisitorInterface $visitor A Twig_NodeVisitorInterface instance
|
43 |
+
*/
|
44 |
+
public function addVisitor(Twig_NodeVisitorInterface $visitor)
|
45 |
+
{
|
46 |
+
if (!isset($this->visitors[$visitor->getPriority()])) {
|
47 |
+
$this->visitors[$visitor->getPriority()] = array();
|
48 |
+
}
|
49 |
+
|
50 |
+
$this->visitors[$visitor->getPriority()][] = $visitor;
|
51 |
+
}
|
52 |
+
|
53 |
+
/**
|
54 |
+
* Traverses a node and calls the registered visitors.
|
55 |
+
*
|
56 |
+
* @param Twig_NodeInterface $node A Twig_NodeInterface instance
|
57 |
+
*/
|
58 |
+
public function traverse(Twig_NodeInterface $node)
|
59 |
+
{
|
60 |
+
ksort($this->visitors);
|
61 |
+
foreach ($this->visitors as $visitors) {
|
62 |
+
foreach ($visitors as $visitor) {
|
63 |
+
$node = $this->traverseForVisitor($visitor, $node);
|
64 |
+
}
|
65 |
+
}
|
66 |
+
|
67 |
+
return $node;
|
68 |
+
}
|
69 |
+
|
70 |
+
protected function traverseForVisitor(Twig_NodeVisitorInterface $visitor, Twig_NodeInterface $node = null)
|
71 |
+
{
|
72 |
+
if (null === $node) {
|
73 |
+
return;
|
74 |
+
}
|
75 |
+
|
76 |
+
$node = $visitor->enterNode($node, $this->env);
|
77 |
+
|
78 |
+
foreach ($node as $k => $n) {
|
79 |
+
if (false !== $n = $this->traverseForVisitor($visitor, $n)) {
|
80 |
+
$node->setNode($k, $n);
|
81 |
+
} else {
|
82 |
+
$node->removeNode($k);
|
83 |
+
}
|
84 |
+
}
|
85 |
+
|
86 |
+
return $visitor->leaveNode($node, $this->env);
|
87 |
+
}
|
88 |
+
}
|
classes/Twig/NodeVisitor/Escaper.php
CHANGED
@@ -1,167 +1,167 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2009 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
/**
|
13 |
-
* Twig_NodeVisitor_Escaper implements output escaping.
|
14 |
-
*
|
15 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
16 |
-
*/
|
17 |
-
class Twig_NodeVisitor_Escaper implements Twig_NodeVisitorInterface
|
18 |
-
{
|
19 |
-
protected $statusStack = array();
|
20 |
-
protected $blocks = array();
|
21 |
-
protected $safeAnalysis;
|
22 |
-
protected $traverser;
|
23 |
-
protected $defaultStrategy = false;
|
24 |
-
protected $safeVars = array();
|
25 |
-
|
26 |
-
public function __construct()
|
27 |
-
{
|
28 |
-
$this->safeAnalysis = new Twig_NodeVisitor_SafeAnalysis();
|
29 |
-
}
|
30 |
-
|
31 |
-
/**
|
32 |
-
* Called before child nodes are visited.
|
33 |
-
*
|
34 |
-
* @param Twig_NodeInterface $node The node to visit
|
35 |
-
* @param Twig_Environment $env The Twig environment instance
|
36 |
-
*
|
37 |
-
* @return Twig_NodeInterface The modified node
|
38 |
-
*/
|
39 |
-
public function enterNode(Twig_NodeInterface $node, Twig_Environment $env)
|
40 |
-
{
|
41 |
-
if ($node instanceof Twig_Node_Module) {
|
42 |
-
if ($env->hasExtension('escaper') && $defaultStrategy = $env->getExtension('escaper')->getDefaultStrategy($node->getAttribute('filename'))) {
|
43 |
-
$this->defaultStrategy = $defaultStrategy;
|
44 |
-
}
|
45 |
-
$this->safeVars = array();
|
46 |
-
} elseif ($node instanceof Twig_Node_AutoEscape) {
|
47 |
-
$this->statusStack[] = $node->getAttribute('value');
|
48 |
-
} elseif ($node instanceof Twig_Node_Block) {
|
49 |
-
$this->statusStack[] = isset($this->blocks[$node->getAttribute('name')]) ? $this->blocks[$node->getAttribute('name')] : $this->needEscaping($env);
|
50 |
-
} elseif ($node instanceof Twig_Node_Import) {
|
51 |
-
$this->safeVars[] = $node->getNode('var')->getAttribute('name');
|
52 |
-
}
|
53 |
-
|
54 |
-
return $node;
|
55 |
-
}
|
56 |
-
|
57 |
-
/**
|
58 |
-
* Called after child nodes are visited.
|
59 |
-
*
|
60 |
-
* @param Twig_NodeInterface $node The node to visit
|
61 |
-
* @param Twig_Environment $env The Twig environment instance
|
62 |
-
*
|
63 |
-
* @return Twig_NodeInterface The modified node
|
64 |
-
*/
|
65 |
-
public function leaveNode(Twig_NodeInterface $node, Twig_Environment $env)
|
66 |
-
{
|
67 |
-
if ($node instanceof Twig_Node_Module) {
|
68 |
-
$this->defaultStrategy = false;
|
69 |
-
$this->safeVars = array();
|
70 |
-
} elseif ($node instanceof Twig_Node_Expression_Filter) {
|
71 |
-
return $this->preEscapeFilterNode($node, $env);
|
72 |
-
} elseif ($node instanceof Twig_Node_Print) {
|
73 |
-
return $this->escapePrintNode($node, $env, $this->needEscaping($env));
|
74 |
-
}
|
75 |
-
|
76 |
-
if ($node instanceof Twig_Node_AutoEscape || $node instanceof Twig_Node_Block) {
|
77 |
-
array_pop($this->statusStack);
|
78 |
-
} elseif ($node instanceof Twig_Node_BlockReference) {
|
79 |
-
$this->blocks[$node->getAttribute('name')] = $this->needEscaping($env);
|
80 |
-
}
|
81 |
-
|
82 |
-
return $node;
|
83 |
-
}
|
84 |
-
|
85 |
-
protected function escapePrintNode(Twig_Node_Print $node, Twig_Environment $env, $type)
|
86 |
-
{
|
87 |
-
if (false === $type) {
|
88 |
-
return $node;
|
89 |
-
}
|
90 |
-
|
91 |
-
$expression = $node->getNode('expr');
|
92 |
-
|
93 |
-
if ($this->isSafeFor($type, $expression, $env)) {
|
94 |
-
return $node;
|
95 |
-
}
|
96 |
-
|
97 |
-
$class = get_class($node);
|
98 |
-
|
99 |
-
return new $class(
|
100 |
-
$this->getEscaperFilter($type, $expression),
|
101 |
-
$node->getLine()
|
102 |
-
);
|
103 |
-
}
|
104 |
-
|
105 |
-
protected function preEscapeFilterNode(Twig_Node_Expression_Filter $filter, Twig_Environment $env)
|
106 |
-
{
|
107 |
-
$name = $filter->getNode('filter')->getAttribute('value');
|
108 |
-
|
109 |
-
$type = $env->getFilter($name)->getPreEscape();
|
110 |
-
if (null === $type) {
|
111 |
-
return $filter;
|
112 |
-
}
|
113 |
-
|
114 |
-
$node = $filter->getNode('node');
|
115 |
-
if ($this->isSafeFor($type, $node, $env)) {
|
116 |
-
return $filter;
|
117 |
-
}
|
118 |
-
|
119 |
-
$filter->setNode('node', $this->getEscaperFilter($type, $node));
|
120 |
-
|
121 |
-
return $filter;
|
122 |
-
}
|
123 |
-
|
124 |
-
protected function isSafeFor($type, Twig_NodeInterface $expression, $env)
|
125 |
-
{
|
126 |
-
$safe = $this->safeAnalysis->getSafe($expression);
|
127 |
-
|
128 |
-
if (null === $safe) {
|
129 |
-
if (null === $this->traverser) {
|
130 |
-
$this->traverser = new Twig_NodeTraverser($env, array($this->safeAnalysis));
|
131 |
-
}
|
132 |
-
|
133 |
-
$this->safeAnalysis->setSafeVars($this->safeVars);
|
134 |
-
|
135 |
-
$this->traverser->traverse($expression);
|
136 |
-
$safe = $this->safeAnalysis->getSafe($expression);
|
137 |
-
}
|
138 |
-
|
139 |
-
return in_array($type, $safe) || in_array('all', $safe);
|
140 |
-
}
|
141 |
-
|
142 |
-
protected function needEscaping(Twig_Environment $env)
|
143 |
-
{
|
144 |
-
if (count($this->statusStack)) {
|
145 |
-
return $this->statusStack[count($this->statusStack) - 1];
|
146 |
-
}
|
147 |
-
|
148 |
-
return $this->defaultStrategy ? $this->defaultStrategy : false;
|
149 |
-
}
|
150 |
-
|
151 |
-
protected function getEscaperFilter($type, Twig_NodeInterface $node)
|
152 |
-
{
|
153 |
-
$line = $node->getLine();
|
154 |
-
$name = new Twig_Node_Expression_Constant('escape', $line);
|
155 |
-
$args = new Twig_Node(array(new Twig_Node_Expression_Constant((string) $type, $line), new Twig_Node_Expression_Constant(null, $line), new Twig_Node_Expression_Constant(true, $line)));
|
156 |
-
|
157 |
-
return new Twig_Node_Expression_Filter($node, $name, $args, $line);
|
158 |
-
}
|
159 |
-
|
160 |
-
/**
|
161 |
-
* {@inheritdoc}
|
162 |
-
*/
|
163 |
-
public function getPriority()
|
164 |
-
{
|
165 |
-
return 0;
|
166 |
-
}
|
167 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2009 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Twig_NodeVisitor_Escaper implements output escaping.
|
14 |
+
*
|
15 |
+
* @author Fabien Potencier <fabien@symfony.com>
|
16 |
+
*/
|
17 |
+
class Twig_NodeVisitor_Escaper implements Twig_NodeVisitorInterface
|
18 |
+
{
|
19 |
+
protected $statusStack = array();
|
20 |
+
protected $blocks = array();
|
21 |
+
protected $safeAnalysis;
|
22 |
+
protected $traverser;
|
23 |
+
protected $defaultStrategy = false;
|
24 |
+
protected $safeVars = array();
|
25 |
+
|
26 |
+
public function __construct()
|
27 |
+
{
|
28 |
+
$this->safeAnalysis = new Twig_NodeVisitor_SafeAnalysis();
|
29 |
+
}
|
30 |
+
|
31 |
+
/**
|
32 |
+
* Called before child nodes are visited.
|
33 |
+
*
|
34 |
+
* @param Twig_NodeInterface $node The node to visit
|
35 |
+
* @param Twig_Environment $env The Twig environment instance
|
36 |
+
*
|
37 |
+
* @return Twig_NodeInterface The modified node
|
38 |
+
*/
|
39 |
+
public function enterNode(Twig_NodeInterface $node, Twig_Environment $env)
|
40 |
+
{
|
41 |
+
if ($node instanceof Twig_Node_Module) {
|
42 |
+
if ($env->hasExtension('escaper') && $defaultStrategy = $env->getExtension('escaper')->getDefaultStrategy($node->getAttribute('filename'))) {
|
43 |
+
$this->defaultStrategy = $defaultStrategy;
|
44 |
+
}
|
45 |
+
$this->safeVars = array();
|
46 |
+
} elseif ($node instanceof Twig_Node_AutoEscape) {
|
47 |
+
$this->statusStack[] = $node->getAttribute('value');
|
48 |
+
} elseif ($node instanceof Twig_Node_Block) {
|
49 |
+
$this->statusStack[] = isset($this->blocks[$node->getAttribute('name')]) ? $this->blocks[$node->getAttribute('name')] : $this->needEscaping($env);
|
50 |
+
} elseif ($node instanceof Twig_Node_Import) {
|
51 |
+
$this->safeVars[] = $node->getNode('var')->getAttribute('name');
|
52 |
+
}
|
53 |
+
|
54 |
+
return $node;
|
55 |
+
}
|
56 |
+
|
57 |
+
/**
|
58 |
+
* Called after child nodes are visited.
|
59 |
+
*
|
60 |
+
* @param Twig_NodeInterface $node The node to visit
|
61 |
+
* @param Twig_Environment $env The Twig environment instance
|
62 |
+
*
|
63 |
+
* @return Twig_NodeInterface The modified node
|
64 |
+
*/
|
65 |
+
public function leaveNode(Twig_NodeInterface $node, Twig_Environment $env)
|
66 |
+
{
|
67 |
+
if ($node instanceof Twig_Node_Module) {
|
68 |
+
$this->defaultStrategy = false;
|
69 |
+
$this->safeVars = array();
|
70 |
+
} elseif ($node instanceof Twig_Node_Expression_Filter) {
|
71 |
+
return $this->preEscapeFilterNode($node, $env);
|
72 |
+
} elseif ($node instanceof Twig_Node_Print) {
|
73 |
+
return $this->escapePrintNode($node, $env, $this->needEscaping($env));
|
74 |
+
}
|
75 |
+
|
76 |
+
if ($node instanceof Twig_Node_AutoEscape || $node instanceof Twig_Node_Block) {
|
77 |
+
array_pop($this->statusStack);
|
78 |
+
} elseif ($node instanceof Twig_Node_BlockReference) {
|
79 |
+
$this->blocks[$node->getAttribute('name')] = $this->needEscaping($env);
|
80 |
+
}
|
81 |
+
|
82 |
+
return $node;
|
83 |
+
}
|
84 |
+
|
85 |
+
protected function escapePrintNode(Twig_Node_Print $node, Twig_Environment $env, $type)
|
86 |
+
{
|
87 |
+
if (false === $type) {
|
88 |
+
return $node;
|
89 |
+
}
|
90 |
+
|
91 |
+
$expression = $node->getNode('expr');
|
92 |
+
|
93 |
+
if ($this->isSafeFor($type, $expression, $env)) {
|
94 |
+
return $node;
|
95 |
+
}
|
96 |
+
|
97 |
+
$class = get_class($node);
|
98 |
+
|
99 |
+
return new $class(
|
100 |
+
$this->getEscaperFilter($type, $expression),
|
101 |
+
$node->getLine()
|
102 |
+
);
|
103 |
+
}
|
104 |
+
|
105 |
+
protected function preEscapeFilterNode(Twig_Node_Expression_Filter $filter, Twig_Environment $env)
|
106 |
+
{
|
107 |
+
$name = $filter->getNode('filter')->getAttribute('value');
|
108 |
+
|
109 |
+
$type = $env->getFilter($name)->getPreEscape();
|
110 |
+
if (null === $type) {
|
111 |
+
return $filter;
|
112 |
+
}
|
113 |
+
|
114 |
+
$node = $filter->getNode('node');
|
115 |
+
if ($this->isSafeFor($type, $node, $env)) {
|
116 |
+
return $filter;
|
117 |
+
}
|
118 |
+
|
119 |
+
$filter->setNode('node', $this->getEscaperFilter($type, $node));
|
120 |
+
|
121 |
+
return $filter;
|
122 |
+
}
|
123 |
+
|
124 |
+
protected function isSafeFor($type, Twig_NodeInterface $expression, $env)
|
125 |
+
{
|
126 |
+
$safe = $this->safeAnalysis->getSafe($expression);
|
127 |
+
|
128 |
+
if (null === $safe) {
|
129 |
+
if (null === $this->traverser) {
|
130 |
+
$this->traverser = new Twig_NodeTraverser($env, array($this->safeAnalysis));
|
131 |
+
}
|
132 |
+
|
133 |
+
$this->safeAnalysis->setSafeVars($this->safeVars);
|
134 |
+
|
135 |
+
$this->traverser->traverse($expression);
|
136 |
+
$safe = $this->safeAnalysis->getSafe($expression);
|
137 |
+
}
|
138 |
+
|
139 |
+
return in_array($type, $safe) || in_array('all', $safe);
|
140 |
+
}
|
141 |
+
|
142 |
+
protected function needEscaping(Twig_Environment $env)
|
143 |
+
{
|
144 |
+
if (count($this->statusStack)) {
|
145 |
+
return $this->statusStack[count($this->statusStack) - 1];
|
146 |
+
}
|
147 |
+
|
148 |
+
return $this->defaultStrategy ? $this->defaultStrategy : false;
|
149 |
+
}
|
150 |
+
|
151 |
+
protected function getEscaperFilter($type, Twig_NodeInterface $node)
|
152 |
+
{
|
153 |
+
$line = $node->getLine();
|
154 |
+
$name = new Twig_Node_Expression_Constant('escape', $line);
|
155 |
+
$args = new Twig_Node(array(new Twig_Node_Expression_Constant((string) $type, $line), new Twig_Node_Expression_Constant(null, $line), new Twig_Node_Expression_Constant(true, $line)));
|
156 |
+
|
157 |
+
return new Twig_Node_Expression_Filter($node, $name, $args, $line);
|
158 |
+
}
|
159 |
+
|
160 |
+
/**
|
161 |
+
* {@inheritdoc}
|
162 |
+
*/
|
163 |
+
public function getPriority()
|
164 |
+
{
|
165 |
+
return 0;
|
166 |
+
}
|
167 |
+
}
|
classes/Twig/NodeVisitor/Optimizer.php
CHANGED
@@ -1,246 +1,246 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2010 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
/**
|
13 |
-
* Twig_NodeVisitor_Optimizer tries to optimizes the AST.
|
14 |
-
*
|
15 |
-
* This visitor is always the last registered one.
|
16 |
-
*
|
17 |
-
* You can configure which optimizations you want to activate via the
|
18 |
-
* optimizer mode.
|
19 |
-
*
|
20 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
21 |
-
*/
|
22 |
-
class Twig_NodeVisitor_Optimizer implements Twig_NodeVisitorInterface
|
23 |
-
{
|
24 |
-
const OPTIMIZE_ALL = -1;
|
25 |
-
const OPTIMIZE_NONE = 0;
|
26 |
-
const OPTIMIZE_FOR = 2;
|
27 |
-
const OPTIMIZE_RAW_FILTER = 4;
|
28 |
-
const OPTIMIZE_VAR_ACCESS = 8;
|
29 |
-
|
30 |
-
protected $loops = array();
|
31 |
-
protected $optimizers;
|
32 |
-
protected $prependedNodes = array();
|
33 |
-
protected $inABody = false;
|
34 |
-
|
35 |
-
/**
|
36 |
-
* Constructor.
|
37 |
-
*
|
38 |
-
* @param int $optimizers The optimizer mode
|
39 |
-
*/
|
40 |
-
public function __construct($optimizers = -1)
|
41 |
-
{
|
42 |
-
if (!is_int($optimizers) || $optimizers > (self::OPTIMIZE_FOR | self::OPTIMIZE_RAW_FILTER | self::OPTIMIZE_VAR_ACCESS)) {
|
43 |
-
throw new InvalidArgumentException(sprintf('Optimizer mode "%s" is not valid.', $optimizers));
|
44 |
-
}
|
45 |
-
|
46 |
-
$this->optimizers = $optimizers;
|
47 |
-
}
|
48 |
-
|
49 |
-
/**
|
50 |
-
* {@inheritdoc}
|
51 |
-
*/
|
52 |
-
public function enterNode(Twig_NodeInterface $node, Twig_Environment $env)
|
53 |
-
{
|
54 |
-
if (self::OPTIMIZE_FOR === (self::OPTIMIZE_FOR & $this->optimizers)) {
|
55 |
-
$this->enterOptimizeFor($node, $env);
|
56 |
-
}
|
57 |
-
|
58 |
-
if (!version_compare(phpversion(), '5.4.0RC1', '>=') && self::OPTIMIZE_VAR_ACCESS === (self::OPTIMIZE_VAR_ACCESS & $this->optimizers) && !$env->isStrictVariables() && !$env->hasExtension('sandbox')) {
|
59 |
-
if ($this->inABody) {
|
60 |
-
if (!$node instanceof Twig_Node_Expression) {
|
61 |
-
if (get_class($node) !== 'Twig_Node') {
|
62 |
-
array_unshift($this->prependedNodes, array());
|
63 |
-
}
|
64 |
-
} else {
|
65 |
-
$node = $this->optimizeVariables($node, $env);
|
66 |
-
}
|
67 |
-
} elseif ($node instanceof Twig_Node_Body) {
|
68 |
-
$this->inABody = true;
|
69 |
-
}
|
70 |
-
}
|
71 |
-
|
72 |
-
return $node;
|
73 |
-
}
|
74 |
-
|
75 |
-
/**
|
76 |
-
* {@inheritdoc}
|
77 |
-
*/
|
78 |
-
public function leaveNode(Twig_NodeInterface $node, Twig_Environment $env)
|
79 |
-
{
|
80 |
-
$expression = $node instanceof Twig_Node_Expression;
|
81 |
-
|
82 |
-
if (self::OPTIMIZE_FOR === (self::OPTIMIZE_FOR & $this->optimizers)) {
|
83 |
-
$this->leaveOptimizeFor($node, $env);
|
84 |
-
}
|
85 |
-
|
86 |
-
if (self::OPTIMIZE_RAW_FILTER === (self::OPTIMIZE_RAW_FILTER & $this->optimizers)) {
|
87 |
-
$node = $this->optimizeRawFilter($node, $env);
|
88 |
-
}
|
89 |
-
|
90 |
-
$node = $this->optimizePrintNode($node, $env);
|
91 |
-
|
92 |
-
if (self::OPTIMIZE_VAR_ACCESS === (self::OPTIMIZE_VAR_ACCESS & $this->optimizers) && !$env->isStrictVariables() && !$env->hasExtension('sandbox')) {
|
93 |
-
if ($node instanceof Twig_Node_Body) {
|
94 |
-
$this->inABody = false;
|
95 |
-
} elseif ($this->inABody) {
|
96 |
-
if (!$expression && get_class($node) !== 'Twig_Node' && $prependedNodes = array_shift($this->prependedNodes)) {
|
97 |
-
$nodes = array();
|
98 |
-
foreach (array_unique($prependedNodes) as $name) {
|
99 |
-
$nodes[] = new Twig_Node_SetTemp($name, $node->getLine());
|
100 |
-
}
|
101 |
-
|
102 |
-
$nodes[] = $node;
|
103 |
-
$node = new Twig_Node($nodes);
|
104 |
-
}
|
105 |
-
}
|
106 |
-
}
|
107 |
-
|
108 |
-
return $node;
|
109 |
-
}
|
110 |
-
|
111 |
-
protected function optimizeVariables(Twig_NodeInterface $node, Twig_Environment $env)
|
112 |
-
{
|
113 |
-
if ('Twig_Node_Expression_Name' === get_class($node) && $node->isSimple()) {
|
114 |
-
$this->prependedNodes[0][] = $node->getAttribute('name');
|
115 |
-
|
116 |
-
return new Twig_Node_Expression_TempName($node->getAttribute('name'), $node->getLine());
|
117 |
-
}
|
118 |
-
|
119 |
-
return $node;
|
120 |
-
}
|
121 |
-
|
122 |
-
/**
|
123 |
-
* Optimizes print nodes.
|
124 |
-
*
|
125 |
-
* It replaces:
|
126 |
-
*
|
127 |
-
* * "echo $this->render(Parent)Block()" with "$this->display(Parent)Block()"
|
128 |
-
*
|
129 |
-
* @param Twig_NodeInterface $node A Node
|
130 |
-
* @param Twig_Environment $env The current Twig environment
|
131 |
-
*/
|
132 |
-
protected function optimizePrintNode(Twig_NodeInterface $node, Twig_Environment $env)
|
133 |
-
{
|
134 |
-
if (!$node instanceof Twig_Node_Print) {
|
135 |
-
return $node;
|
136 |
-
}
|
137 |
-
|
138 |
-
if (
|
139 |
-
$node->getNode('expr') instanceof Twig_Node_Expression_BlockReference ||
|
140 |
-
$node->getNode('expr') instanceof Twig_Node_Expression_Parent
|
141 |
-
) {
|
142 |
-
$node->getNode('expr')->setAttribute('output', true);
|
143 |
-
|
144 |
-
return $node->getNode('expr');
|
145 |
-
}
|
146 |
-
|
147 |
-
return $node;
|
148 |
-
}
|
149 |
-
|
150 |
-
/**
|
151 |
-
* Removes "raw" filters.
|
152 |
-
*
|
153 |
-
* @param Twig_NodeInterface $node A Node
|
154 |
-
* @param Twig_Environment $env The current Twig environment
|
155 |
-
*/
|
156 |
-
protected function optimizeRawFilter(Twig_NodeInterface $node, Twig_Environment $env)
|
157 |
-
{
|
158 |
-
if ($node instanceof Twig_Node_Expression_Filter && 'raw' == $node->getNode('filter')->getAttribute('value')) {
|
159 |
-
return $node->getNode('node');
|
160 |
-
}
|
161 |
-
|
162 |
-
return $node;
|
163 |
-
}
|
164 |
-
|
165 |
-
/**
|
166 |
-
* Optimizes "for" tag by removing the "loop" variable creation whenever possible.
|
167 |
-
*
|
168 |
-
* @param Twig_NodeInterface $node A Node
|
169 |
-
* @param Twig_Environment $env The current Twig environment
|
170 |
-
*/
|
171 |
-
protected function enterOptimizeFor(Twig_NodeInterface $node, Twig_Environment $env)
|
172 |
-
{
|
173 |
-
if ($node instanceof Twig_Node_For) {
|
174 |
-
// disable the loop variable by default
|
175 |
-
$node->setAttribute('with_loop', false);
|
176 |
-
array_unshift($this->loops, $node);
|
177 |
-
} elseif (!$this->loops) {
|
178 |
-
// we are outside a loop
|
179 |
-
return;
|
180 |
-
}
|
181 |
-
|
182 |
-
// when do we need to add the loop variable back?
|
183 |
-
|
184 |
-
// the loop variable is referenced for the current loop
|
185 |
-
elseif ($node instanceof Twig_Node_Expression_Name && 'loop' === $node->getAttribute('name')) {
|
186 |
-
$this->addLoopToCurrent();
|
187 |
-
}
|
188 |
-
|
189 |
-
// block reference
|
190 |
-
elseif ($node instanceof Twig_Node_BlockReference || $node instanceof Twig_Node_Expression_BlockReference) {
|
191 |
-
$this->addLoopToCurrent();
|
192 |
-
}
|
193 |
-
|
194 |
-
// include without the only attribute
|
195 |
-
elseif ($node instanceof Twig_Node_Include && !$node->getAttribute('only')) {
|
196 |
-
$this->addLoopToAll();
|
197 |
-
}
|
198 |
-
|
199 |
-
// the loop variable is referenced via an attribute
|
200 |
-
elseif ($node instanceof Twig_Node_Expression_GetAttr
|
201 |
-
&& (!$node->getNode('attribute') instanceof Twig_Node_Expression_Constant
|
202 |
-
|| 'parent' === $node->getNode('attribute')->getAttribute('value')
|
203 |
-
)
|
204 |
-
&& (true === $this->loops[0]->getAttribute('with_loop')
|
205 |
-
|| ($node->getNode('node') instanceof Twig_Node_Expression_Name
|
206 |
-
&& 'loop' === $node->getNode('node')->getAttribute('name')
|
207 |
-
)
|
208 |
-
)
|
209 |
-
) {
|
210 |
-
$this->addLoopToAll();
|
211 |
-
}
|
212 |
-
}
|
213 |
-
|
214 |
-
/**
|
215 |
-
* Optimizes "for" tag by removing the "loop" variable creation whenever possible.
|
216 |
-
*
|
217 |
-
* @param Twig_NodeInterface $node A Node
|
218 |
-
* @param Twig_Environment $env The current Twig environment
|
219 |
-
*/
|
220 |
-
protected function leaveOptimizeFor(Twig_NodeInterface $node, Twig_Environment $env)
|
221 |
-
{
|
222 |
-
if ($node instanceof Twig_Node_For) {
|
223 |
-
array_shift($this->loops);
|
224 |
-
}
|
225 |
-
}
|
226 |
-
|
227 |
-
protected function addLoopToCurrent()
|
228 |
-
{
|
229 |
-
$this->loops[0]->setAttribute('with_loop', true);
|
230 |
-
}
|
231 |
-
|
232 |
-
protected function addLoopToAll()
|
233 |
-
{
|
234 |
-
foreach ($this->loops as $loop) {
|
235 |
-
$loop->setAttribute('with_loop', true);
|
236 |
-
}
|
237 |
-
}
|
238 |
-
|
239 |
-
/**
|
240 |
-
* {@inheritdoc}
|
241 |
-
*/
|
242 |
-
public function getPriority()
|
243 |
-
{
|
244 |
-
return 255;
|
245 |
-
}
|
246 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2010 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Twig_NodeVisitor_Optimizer tries to optimizes the AST.
|
14 |
+
*
|
15 |
+
* This visitor is always the last registered one.
|
16 |
+
*
|
17 |
+
* You can configure which optimizations you want to activate via the
|
18 |
+
* optimizer mode.
|
19 |
+
*
|
20 |
+
* @author Fabien Potencier <fabien@symfony.com>
|
21 |
+
*/
|
22 |
+
class Twig_NodeVisitor_Optimizer implements Twig_NodeVisitorInterface
|
23 |
+
{
|
24 |
+
const OPTIMIZE_ALL = -1;
|
25 |
+
const OPTIMIZE_NONE = 0;
|
26 |
+
const OPTIMIZE_FOR = 2;
|
27 |
+
const OPTIMIZE_RAW_FILTER = 4;
|
28 |
+
const OPTIMIZE_VAR_ACCESS = 8;
|
29 |
+
|
30 |
+
protected $loops = array();
|
31 |
+
protected $optimizers;
|
32 |
+
protected $prependedNodes = array();
|
33 |
+
protected $inABody = false;
|
34 |
+
|
35 |
+
/**
|
36 |
+
* Constructor.
|
37 |
+
*
|
38 |
+
* @param int $optimizers The optimizer mode
|
39 |
+
*/
|
40 |
+
public function __construct($optimizers = -1)
|
41 |
+
{
|
42 |
+
if (!is_int($optimizers) || $optimizers > (self::OPTIMIZE_FOR | self::OPTIMIZE_RAW_FILTER | self::OPTIMIZE_VAR_ACCESS)) {
|
43 |
+
throw new InvalidArgumentException(sprintf('Optimizer mode "%s" is not valid.', $optimizers));
|
44 |
+
}
|
45 |
+
|
46 |
+
$this->optimizers = $optimizers;
|
47 |
+
}
|
48 |
+
|
49 |
+
/**
|
50 |
+
* {@inheritdoc}
|
51 |
+
*/
|
52 |
+
public function enterNode(Twig_NodeInterface $node, Twig_Environment $env)
|
53 |
+
{
|
54 |
+
if (self::OPTIMIZE_FOR === (self::OPTIMIZE_FOR & $this->optimizers)) {
|
55 |
+
$this->enterOptimizeFor($node, $env);
|
56 |
+
}
|
57 |
+
|
58 |
+
if (!version_compare(phpversion(), '5.4.0RC1', '>=') && self::OPTIMIZE_VAR_ACCESS === (self::OPTIMIZE_VAR_ACCESS & $this->optimizers) && !$env->isStrictVariables() && !$env->hasExtension('sandbox')) {
|
59 |
+
if ($this->inABody) {
|
60 |
+
if (!$node instanceof Twig_Node_Expression) {
|
61 |
+
if (get_class($node) !== 'Twig_Node') {
|
62 |
+
array_unshift($this->prependedNodes, array());
|
63 |
+
}
|
64 |
+
} else {
|
65 |
+
$node = $this->optimizeVariables($node, $env);
|
66 |
+
}
|
67 |
+
} elseif ($node instanceof Twig_Node_Body) {
|
68 |
+
$this->inABody = true;
|
69 |
+
}
|
70 |
+
}
|
71 |
+
|
72 |
+
return $node;
|
73 |
+
}
|
74 |
+
|
75 |
+
/**
|
76 |
+
* {@inheritdoc}
|
77 |
+
*/
|
78 |
+
public function leaveNode(Twig_NodeInterface $node, Twig_Environment $env)
|
79 |
+
{
|
80 |
+
$expression = $node instanceof Twig_Node_Expression;
|
81 |
+
|
82 |
+
if (self::OPTIMIZE_FOR === (self::OPTIMIZE_FOR & $this->optimizers)) {
|
83 |
+
$this->leaveOptimizeFor($node, $env);
|
84 |
+
}
|
85 |
+
|
86 |
+
if (self::OPTIMIZE_RAW_FILTER === (self::OPTIMIZE_RAW_FILTER & $this->optimizers)) {
|
87 |
+
$node = $this->optimizeRawFilter($node, $env);
|
88 |
+
}
|
89 |
+
|
90 |
+
$node = $this->optimizePrintNode($node, $env);
|
91 |
+
|
92 |
+
if (self::OPTIMIZE_VAR_ACCESS === (self::OPTIMIZE_VAR_ACCESS & $this->optimizers) && !$env->isStrictVariables() && !$env->hasExtension('sandbox')) {
|
93 |
+
if ($node instanceof Twig_Node_Body) {
|
94 |
+
$this->inABody = false;
|
95 |
+
} elseif ($this->inABody) {
|
96 |
+
if (!$expression && get_class($node) !== 'Twig_Node' && $prependedNodes = array_shift($this->prependedNodes)) {
|
97 |
+
$nodes = array();
|
98 |
+
foreach (array_unique($prependedNodes) as $name) {
|
99 |
+
$nodes[] = new Twig_Node_SetTemp($name, $node->getLine());
|
100 |
+
}
|
101 |
+
|
102 |
+
$nodes[] = $node;
|
103 |
+
$node = new Twig_Node($nodes);
|
104 |
+
}
|
105 |
+
}
|
106 |
+
}
|
107 |
+
|
108 |
+
return $node;
|
109 |
+
}
|
110 |
+
|
111 |
+
protected function optimizeVariables(Twig_NodeInterface $node, Twig_Environment $env)
|
112 |
+
{
|
113 |
+
if ('Twig_Node_Expression_Name' === get_class($node) && $node->isSimple()) {
|
114 |
+
$this->prependedNodes[0][] = $node->getAttribute('name');
|
115 |
+
|
116 |
+
return new Twig_Node_Expression_TempName($node->getAttribute('name'), $node->getLine());
|
117 |
+
}
|
118 |
+
|
119 |
+
return $node;
|
120 |
+
}
|
121 |
+
|
122 |
+
/**
|
123 |
+
* Optimizes print nodes.
|
124 |
+
*
|
125 |
+
* It replaces:
|
126 |
+
*
|
127 |
+
* * "echo $this->render(Parent)Block()" with "$this->display(Parent)Block()"
|
128 |
+
*
|
129 |
+
* @param Twig_NodeInterface $node A Node
|
130 |
+
* @param Twig_Environment $env The current Twig environment
|
131 |
+
*/
|
132 |
+
protected function optimizePrintNode(Twig_NodeInterface $node, Twig_Environment $env)
|
133 |
+
{
|
134 |
+
if (!$node instanceof Twig_Node_Print) {
|
135 |
+
return $node;
|
136 |
+
}
|
137 |
+
|
138 |
+
if (
|
139 |
+
$node->getNode('expr') instanceof Twig_Node_Expression_BlockReference ||
|
140 |
+
$node->getNode('expr') instanceof Twig_Node_Expression_Parent
|
141 |
+
) {
|
142 |
+
$node->getNode('expr')->setAttribute('output', true);
|
143 |
+
|
144 |
+
return $node->getNode('expr');
|
145 |
+
}
|
146 |
+
|
147 |
+
return $node;
|
148 |
+
}
|
149 |
+
|
150 |
+
/**
|
151 |
+
* Removes "raw" filters.
|
152 |
+
*
|
153 |
+
* @param Twig_NodeInterface $node A Node
|
154 |
+
* @param Twig_Environment $env The current Twig environment
|
155 |
+
*/
|
156 |
+
protected function optimizeRawFilter(Twig_NodeInterface $node, Twig_Environment $env)
|
157 |
+
{
|
158 |
+
if ($node instanceof Twig_Node_Expression_Filter && 'raw' == $node->getNode('filter')->getAttribute('value')) {
|
159 |
+
return $node->getNode('node');
|
160 |
+
}
|
161 |
+
|
162 |
+
return $node;
|
163 |
+
}
|
164 |
+
|
165 |
+
/**
|
166 |
+
* Optimizes "for" tag by removing the "loop" variable creation whenever possible.
|
167 |
+
*
|
168 |
+
* @param Twig_NodeInterface $node A Node
|
169 |
+
* @param Twig_Environment $env The current Twig environment
|
170 |
+
*/
|
171 |
+
protected function enterOptimizeFor(Twig_NodeInterface $node, Twig_Environment $env)
|
172 |
+
{
|
173 |
+
if ($node instanceof Twig_Node_For) {
|
174 |
+
// disable the loop variable by default
|
175 |
+
$node->setAttribute('with_loop', false);
|
176 |
+
array_unshift($this->loops, $node);
|
177 |
+
} elseif (!$this->loops) {
|
178 |
+
// we are outside a loop
|
179 |
+
return;
|
180 |
+
}
|
181 |
+
|
182 |
+
// when do we need to add the loop variable back?
|
183 |
+
|
184 |
+
// the loop variable is referenced for the current loop
|
185 |
+
elseif ($node instanceof Twig_Node_Expression_Name && 'loop' === $node->getAttribute('name')) {
|
186 |
+
$this->addLoopToCurrent();
|
187 |
+
}
|
188 |
+
|
189 |
+
// block reference
|
190 |
+
elseif ($node instanceof Twig_Node_BlockReference || $node instanceof Twig_Node_Expression_BlockReference) {
|
191 |
+
$this->addLoopToCurrent();
|
192 |
+
}
|
193 |
+
|
194 |
+
// include without the only attribute
|
195 |
+
elseif ($node instanceof Twig_Node_Include && !$node->getAttribute('only')) {
|
196 |
+
$this->addLoopToAll();
|
197 |
+
}
|
198 |
+
|
199 |
+
// the loop variable is referenced via an attribute
|
200 |
+
elseif ($node instanceof Twig_Node_Expression_GetAttr
|
201 |
+
&& (!$node->getNode('attribute') instanceof Twig_Node_Expression_Constant
|
202 |
+
|| 'parent' === $node->getNode('attribute')->getAttribute('value')
|
203 |
+
)
|
204 |
+
&& (true === $this->loops[0]->getAttribute('with_loop')
|
205 |
+
|| ($node->getNode('node') instanceof Twig_Node_Expression_Name
|
206 |
+
&& 'loop' === $node->getNode('node')->getAttribute('name')
|
207 |
+
)
|
208 |
+
)
|
209 |
+
) {
|
210 |
+
$this->addLoopToAll();
|
211 |
+
}
|
212 |
+
}
|
213 |
+
|
214 |
+
/**
|
215 |
+
* Optimizes "for" tag by removing the "loop" variable creation whenever possible.
|
216 |
+
*
|
217 |
+
* @param Twig_NodeInterface $node A Node
|
218 |
+
* @param Twig_Environment $env The current Twig environment
|
219 |
+
*/
|
220 |
+
protected function leaveOptimizeFor(Twig_NodeInterface $node, Twig_Environment $env)
|
221 |
+
{
|
222 |
+
if ($node instanceof Twig_Node_For) {
|
223 |
+
array_shift($this->loops);
|
224 |
+
}
|
225 |
+
}
|
226 |
+
|
227 |
+
protected function addLoopToCurrent()
|
228 |
+
{
|
229 |
+
$this->loops[0]->setAttribute('with_loop', true);
|
230 |
+
}
|
231 |
+
|
232 |
+
protected function addLoopToAll()
|
233 |
+
{
|
234 |
+
foreach ($this->loops as $loop) {
|
235 |
+
$loop->setAttribute('with_loop', true);
|
236 |
+
}
|
237 |
+
}
|
238 |
+
|
239 |
+
/**
|
240 |
+
* {@inheritdoc}
|
241 |
+
*/
|
242 |
+
public function getPriority()
|
243 |
+
{
|
244 |
+
return 255;
|
245 |
+
}
|
246 |
+
}
|
classes/Twig/NodeVisitor/SafeAnalysis.php
CHANGED
@@ -1,139 +1,139 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
class Twig_NodeVisitor_SafeAnalysis implements Twig_NodeVisitorInterface
|
4 |
-
{
|
5 |
-
protected $data = array();
|
6 |
-
protected $safeVars = array();
|
7 |
-
|
8 |
-
public function setSafeVars($safeVars)
|
9 |
-
{
|
10 |
-
$this->safeVars = $safeVars;
|
11 |
-
}
|
12 |
-
|
13 |
-
public function getSafe(Twig_NodeInterface $node)
|
14 |
-
{
|
15 |
-
$hash = spl_object_hash($node);
|
16 |
-
if (!isset($this->data[$hash])) {
|
17 |
-
return;
|
18 |
-
}
|
19 |
-
|
20 |
-
foreach ($this->data[$hash] as $bucket) {
|
21 |
-
if ($bucket['key'] !== $node) {
|
22 |
-
continue;
|
23 |
-
}
|
24 |
-
|
25 |
-
if (in_array('html_attr', $bucket['value'])) {
|
26 |
-
$bucket['value'][] = 'html';
|
27 |
-
}
|
28 |
-
|
29 |
-
return $bucket['value'];
|
30 |
-
}
|
31 |
-
}
|
32 |
-
|
33 |
-
protected function setSafe(Twig_NodeInterface $node, array $safe)
|
34 |
-
{
|
35 |
-
$hash = spl_object_hash($node);
|
36 |
-
if (isset($this->data[$hash])) {
|
37 |
-
foreach ($this->data[$hash] as &$bucket) {
|
38 |
-
if ($bucket['key'] === $node) {
|
39 |
-
$bucket['value'] = $safe;
|
40 |
-
|
41 |
-
return;
|
42 |
-
}
|
43 |
-
}
|
44 |
-
}
|
45 |
-
$this->data[$hash][] = array(
|
46 |
-
'key' => $node,
|
47 |
-
'value' => $safe,
|
48 |
-
);
|
49 |
-
}
|
50 |
-
|
51 |
-
public function enterNode(Twig_NodeInterface $node, Twig_Environment $env)
|
52 |
-
{
|
53 |
-
return $node;
|
54 |
-
}
|
55 |
-
|
56 |
-
public function leaveNode(Twig_NodeInterface $node, Twig_Environment $env)
|
57 |
-
{
|
58 |
-
if ($node instanceof Twig_Node_Expression_Constant) {
|
59 |
-
// constants are marked safe for all
|
60 |
-
$this->setSafe($node, array('all'));
|
61 |
-
} elseif ($node instanceof Twig_Node_Expression_BlockReference) {
|
62 |
-
// blocks are safe by definition
|
63 |
-
$this->setSafe($node, array('all'));
|
64 |
-
} elseif ($node instanceof Twig_Node_Expression_Parent) {
|
65 |
-
// parent block is safe by definition
|
66 |
-
$this->setSafe($node, array('all'));
|
67 |
-
} elseif ($node instanceof Twig_Node_Expression_Conditional) {
|
68 |
-
// intersect safeness of both operands
|
69 |
-
$safe = $this->intersectSafe($this->getSafe($node->getNode('expr2')), $this->getSafe($node->getNode('expr3')));
|
70 |
-
$this->setSafe($node, $safe);
|
71 |
-
} elseif ($node instanceof Twig_Node_Expression_Filter) {
|
72 |
-
// filter expression is safe when the filter is safe
|
73 |
-
$name = $node->getNode('filter')->getAttribute('value');
|
74 |
-
$args = $node->getNode('arguments');
|
75 |
-
if (false !== $filter = $env->getFilter($name)) {
|
76 |
-
$safe = $filter->getSafe($args);
|
77 |
-
if (null === $safe) {
|
78 |
-
$safe = $this->intersectSafe($this->getSafe($node->getNode('node')), $filter->getPreservesSafety());
|
79 |
-
}
|
80 |
-
$this->setSafe($node, $safe);
|
81 |
-
} else {
|
82 |
-
$this->setSafe($node, array());
|
83 |
-
}
|
84 |
-
} elseif ($node instanceof Twig_Node_Expression_Function) {
|
85 |
-
// function expression is safe when the function is safe
|
86 |
-
$name = $node->getAttribute('name');
|
87 |
-
$args = $node->getNode('arguments');
|
88 |
-
$function = $env->getFunction($name);
|
89 |
-
if (false !== $function) {
|
90 |
-
$this->setSafe($node, $function->getSafe($args));
|
91 |
-
} else {
|
92 |
-
$this->setSafe($node, array());
|
93 |
-
}
|
94 |
-
} elseif ($node instanceof Twig_Node_Expression_MethodCall) {
|
95 |
-
if ($node->getAttribute('safe')) {
|
96 |
-
$this->setSafe($node, array('all'));
|
97 |
-
} else {
|
98 |
-
$this->setSafe($node, array());
|
99 |
-
}
|
100 |
-
} elseif ($node instanceof Twig_Node_Expression_GetAttr && $node->getNode('node') instanceof Twig_Node_Expression_Name) {
|
101 |
-
$name = $node->getNode('node')->getAttribute('name');
|
102 |
-
// attributes on template instances are safe
|
103 |
-
if ('_self' == $name || in_array($name, $this->safeVars)) {
|
104 |
-
$this->setSafe($node, array('all'));
|
105 |
-
} else {
|
106 |
-
$this->setSafe($node, array());
|
107 |
-
}
|
108 |
-
} else {
|
109 |
-
$this->setSafe($node, array());
|
110 |
-
}
|
111 |
-
|
112 |
-
return $node;
|
113 |
-
}
|
114 |
-
|
115 |
-
protected function intersectSafe(array $a = null, array $b = null)
|
116 |
-
{
|
117 |
-
if (null === $a || null === $b) {
|
118 |
-
return array();
|
119 |
-
}
|
120 |
-
|
121 |
-
if (in_array('all', $a)) {
|
122 |
-
return $b;
|
123 |
-
}
|
124 |
-
|
125 |
-
if (in_array('all', $b)) {
|
126 |
-
return $a;
|
127 |
-
}
|
128 |
-
|
129 |
-
return array_intersect($a, $b);
|
130 |
-
}
|
131 |
-
|
132 |
-
/**
|
133 |
-
* {@inheritdoc}
|
134 |
-
*/
|
135 |
-
public function getPriority()
|
136 |
-
{
|
137 |
-
return 0;
|
138 |
-
}
|
139 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Twig_NodeVisitor_SafeAnalysis implements Twig_NodeVisitorInterface
|
4 |
+
{
|
5 |
+
protected $data = array();
|
6 |
+
protected $safeVars = array();
|
7 |
+
|
8 |
+
public function setSafeVars($safeVars)
|
9 |
+
{
|
10 |
+
$this->safeVars = $safeVars;
|
11 |
+
}
|
12 |
+
|
13 |
+
public function getSafe(Twig_NodeInterface $node)
|
14 |
+
{
|
15 |
+
$hash = spl_object_hash($node);
|
16 |
+
if (!isset($this->data[$hash])) {
|
17 |
+
return;
|
18 |
+
}
|
19 |
+
|
20 |
+
foreach ($this->data[$hash] as $bucket) {
|
21 |
+
if ($bucket['key'] !== $node) {
|
22 |
+
continue;
|
23 |
+
}
|
24 |
+
|
25 |
+
if (in_array('html_attr', $bucket['value'])) {
|
26 |
+
$bucket['value'][] = 'html';
|
27 |
+
}
|
28 |
+
|
29 |
+
return $bucket['value'];
|
30 |
+
}
|
31 |
+
}
|
32 |
+
|
33 |
+
protected function setSafe(Twig_NodeInterface $node, array $safe)
|
34 |
+
{
|
35 |
+
$hash = spl_object_hash($node);
|
36 |
+
if (isset($this->data[$hash])) {
|
37 |
+
foreach ($this->data[$hash] as &$bucket) {
|
38 |
+
if ($bucket['key'] === $node) {
|
39 |
+
$bucket['value'] = $safe;
|
40 |
+
|
41 |
+
return;
|
42 |
+
}
|
43 |
+
}
|
44 |
+
}
|
45 |
+
$this->data[$hash][] = array(
|
46 |
+
'key' => $node,
|
47 |
+
'value' => $safe,
|
48 |
+
);
|
49 |
+
}
|
50 |
+
|
51 |
+
public function enterNode(Twig_NodeInterface $node, Twig_Environment $env)
|
52 |
+
{
|
53 |
+
return $node;
|
54 |
+
}
|
55 |
+
|
56 |
+
public function leaveNode(Twig_NodeInterface $node, Twig_Environment $env)
|
57 |
+
{
|
58 |
+
if ($node instanceof Twig_Node_Expression_Constant) {
|
59 |
+
// constants are marked safe for all
|
60 |
+
$this->setSafe($node, array('all'));
|
61 |
+
} elseif ($node instanceof Twig_Node_Expression_BlockReference) {
|
62 |
+
// blocks are safe by definition
|
63 |
+
$this->setSafe($node, array('all'));
|
64 |
+
} elseif ($node instanceof Twig_Node_Expression_Parent) {
|
65 |
+
// parent block is safe by definition
|
66 |
+
$this->setSafe($node, array('all'));
|
67 |
+
} elseif ($node instanceof Twig_Node_Expression_Conditional) {
|
68 |
+
// intersect safeness of both operands
|
69 |
+
$safe = $this->intersectSafe($this->getSafe($node->getNode('expr2')), $this->getSafe($node->getNode('expr3')));
|
70 |
+
$this->setSafe($node, $safe);
|
71 |
+
} elseif ($node instanceof Twig_Node_Expression_Filter) {
|
72 |
+
// filter expression is safe when the filter is safe
|
73 |
+
$name = $node->getNode('filter')->getAttribute('value');
|
74 |
+
$args = $node->getNode('arguments');
|
75 |
+
if (false !== $filter = $env->getFilter($name)) {
|
76 |
+
$safe = $filter->getSafe($args);
|
77 |
+
if (null === $safe) {
|
78 |
+
$safe = $this->intersectSafe($this->getSafe($node->getNode('node')), $filter->getPreservesSafety());
|
79 |
+
}
|
80 |
+
$this->setSafe($node, $safe);
|
81 |
+
} else {
|
82 |
+
$this->setSafe($node, array());
|
83 |
+
}
|
84 |
+
} elseif ($node instanceof Twig_Node_Expression_Function) {
|
85 |
+
// function expression is safe when the function is safe
|
86 |
+
$name = $node->getAttribute('name');
|
87 |
+
$args = $node->getNode('arguments');
|
88 |
+
$function = $env->getFunction($name);
|
89 |
+
if (false !== $function) {
|
90 |
+
$this->setSafe($node, $function->getSafe($args));
|
91 |
+
} else {
|
92 |
+
$this->setSafe($node, array());
|
93 |
+
}
|
94 |
+
} elseif ($node instanceof Twig_Node_Expression_MethodCall) {
|
95 |
+
if ($node->getAttribute('safe')) {
|
96 |
+
$this->setSafe($node, array('all'));
|
97 |
+
} else {
|
98 |
+
$this->setSafe($node, array());
|
99 |
+
}
|
100 |
+
} elseif ($node instanceof Twig_Node_Expression_GetAttr && $node->getNode('node') instanceof Twig_Node_Expression_Name) {
|
101 |
+
$name = $node->getNode('node')->getAttribute('name');
|
102 |
+
// attributes on template instances are safe
|
103 |
+
if ('_self' == $name || in_array($name, $this->safeVars)) {
|
104 |
+
$this->setSafe($node, array('all'));
|
105 |
+
} else {
|
106 |
+
$this->setSafe($node, array());
|
107 |
+
}
|
108 |
+
} else {
|
109 |
+
$this->setSafe($node, array());
|
110 |
+
}
|
111 |
+
|
112 |
+
return $node;
|
113 |
+
}
|
114 |
+
|
115 |
+
protected function intersectSafe(array $a = null, array $b = null)
|
116 |
+
{
|
117 |
+
if (null === $a || null === $b) {
|
118 |
+
return array();
|
119 |
+
}
|
120 |
+
|
121 |
+
if (in_array('all', $a)) {
|
122 |
+
return $b;
|
123 |
+
}
|
124 |
+
|
125 |
+
if (in_array('all', $b)) {
|
126 |
+
return $a;
|
127 |
+
}
|
128 |
+
|
129 |
+
return array_intersect($a, $b);
|
130 |
+
}
|
131 |
+
|
132 |
+
/**
|
133 |
+
* {@inheritdoc}
|
134 |
+
*/
|
135 |
+
public function getPriority()
|
136 |
+
{
|
137 |
+
return 0;
|
138 |
+
}
|
139 |
+
}
|
classes/Twig/NodeVisitor/Sandbox.php
CHANGED
@@ -1,92 +1,92 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2009 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
/**
|
13 |
-
* Twig_NodeVisitor_Sandbox implements sandboxing.
|
14 |
-
*
|
15 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
16 |
-
*/
|
17 |
-
class Twig_NodeVisitor_Sandbox implements Twig_NodeVisitorInterface
|
18 |
-
{
|
19 |
-
protected $inAModule = false;
|
20 |
-
protected $tags;
|
21 |
-
protected $filters;
|
22 |
-
protected $functions;
|
23 |
-
|
24 |
-
/**
|
25 |
-
* Called before child nodes are visited.
|
26 |
-
*
|
27 |
-
* @param Twig_NodeInterface $node The node to visit
|
28 |
-
* @param Twig_Environment $env The Twig environment instance
|
29 |
-
*
|
30 |
-
* @return Twig_NodeInterface The modified node
|
31 |
-
*/
|
32 |
-
public function enterNode(Twig_NodeInterface $node, Twig_Environment $env)
|
33 |
-
{
|
34 |
-
if ($node instanceof Twig_Node_Module) {
|
35 |
-
$this->inAModule = true;
|
36 |
-
$this->tags = array();
|
37 |
-
$this->filters = array();
|
38 |
-
$this->functions = array();
|
39 |
-
|
40 |
-
return $node;
|
41 |
-
} elseif ($this->inAModule) {
|
42 |
-
// look for tags
|
43 |
-
if ($node->getNodeTag()) {
|
44 |
-
$this->tags[] = $node->getNodeTag();
|
45 |
-
}
|
46 |
-
|
47 |
-
// look for filters
|
48 |
-
if ($node instanceof Twig_Node_Expression_Filter) {
|
49 |
-
$this->filters[] = $node->getNode('filter')->getAttribute('value');
|
50 |
-
}
|
51 |
-
|
52 |
-
// look for functions
|
53 |
-
if ($node instanceof Twig_Node_Expression_Function) {
|
54 |
-
$this->functions[] = $node->getAttribute('name');
|
55 |
-
}
|
56 |
-
|
57 |
-
// wrap print to check __toString() calls
|
58 |
-
if ($node instanceof Twig_Node_Print) {
|
59 |
-
return new Twig_Node_SandboxedPrint($node->getNode('expr'), $node->getLine(), $node->getNodeTag());
|
60 |
-
}
|
61 |
-
}
|
62 |
-
|
63 |
-
return $node;
|
64 |
-
}
|
65 |
-
|
66 |
-
/**
|
67 |
-
* Called after child nodes are visited.
|
68 |
-
*
|
69 |
-
* @param Twig_NodeInterface $node The node to visit
|
70 |
-
* @param Twig_Environment $env The Twig environment instance
|
71 |
-
*
|
72 |
-
* @return Twig_NodeInterface The modified node
|
73 |
-
*/
|
74 |
-
public function leaveNode(Twig_NodeInterface $node, Twig_Environment $env)
|
75 |
-
{
|
76 |
-
if ($node instanceof Twig_Node_Module) {
|
77 |
-
$this->inAModule = false;
|
78 |
-
|
79 |
-
return new Twig_Node_SandboxedModule($node, array_unique($this->filters), array_unique($this->tags), array_unique($this->functions));
|
80 |
-
}
|
81 |
-
|
82 |
-
return $node;
|
83 |
-
}
|
84 |
-
|
85 |
-
/**
|
86 |
-
* {@inheritdoc}
|
87 |
-
*/
|
88 |
-
public function getPriority()
|
89 |
-
{
|
90 |
-
return 0;
|
91 |
-
}
|
92 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2009 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Twig_NodeVisitor_Sandbox implements sandboxing.
|
14 |
+
*
|
15 |
+
* @author Fabien Potencier <fabien@symfony.com>
|
16 |
+
*/
|
17 |
+
class Twig_NodeVisitor_Sandbox implements Twig_NodeVisitorInterface
|
18 |
+
{
|
19 |
+
protected $inAModule = false;
|
20 |
+
protected $tags;
|
21 |
+
protected $filters;
|
22 |
+
protected $functions;
|
23 |
+
|
24 |
+
/**
|
25 |
+
* Called before child nodes are visited.
|
26 |
+
*
|
27 |
+
* @param Twig_NodeInterface $node The node to visit
|
28 |
+
* @param Twig_Environment $env The Twig environment instance
|
29 |
+
*
|
30 |
+
* @return Twig_NodeInterface The modified node
|
31 |
+
*/
|
32 |
+
public function enterNode(Twig_NodeInterface $node, Twig_Environment $env)
|
33 |
+
{
|
34 |
+
if ($node instanceof Twig_Node_Module) {
|
35 |
+
$this->inAModule = true;
|
36 |
+
$this->tags = array();
|
37 |
+
$this->filters = array();
|
38 |
+
$this->functions = array();
|
39 |
+
|
40 |
+
return $node;
|
41 |
+
} elseif ($this->inAModule) {
|
42 |
+
// look for tags
|
43 |
+
if ($node->getNodeTag()) {
|
44 |
+
$this->tags[] = $node->getNodeTag();
|
45 |
+
}
|
46 |
+
|
47 |
+
// look for filters
|
48 |
+
if ($node instanceof Twig_Node_Expression_Filter) {
|
49 |
+
$this->filters[] = $node->getNode('filter')->getAttribute('value');
|
50 |
+
}
|
51 |
+
|
52 |
+
// look for functions
|
53 |
+
if ($node instanceof Twig_Node_Expression_Function) {
|
54 |
+
$this->functions[] = $node->getAttribute('name');
|
55 |
+
}
|
56 |
+
|
57 |
+
// wrap print to check __toString() calls
|
58 |
+
if ($node instanceof Twig_Node_Print) {
|
59 |
+
return new Twig_Node_SandboxedPrint($node->getNode('expr'), $node->getLine(), $node->getNodeTag());
|
60 |
+
}
|
61 |
+
}
|
62 |
+
|
63 |
+
return $node;
|
64 |
+
}
|
65 |
+
|
66 |
+
/**
|
67 |
+
* Called after child nodes are visited.
|
68 |
+
*
|
69 |
+
* @param Twig_NodeInterface $node The node to visit
|
70 |
+
* @param Twig_Environment $env The Twig environment instance
|
71 |
+
*
|
72 |
+
* @return Twig_NodeInterface The modified node
|
73 |
+
*/
|
74 |
+
public function leaveNode(Twig_NodeInterface $node, Twig_Environment $env)
|
75 |
+
{
|
76 |
+
if ($node instanceof Twig_Node_Module) {
|
77 |
+
$this->inAModule = false;
|
78 |
+
|
79 |
+
return new Twig_Node_SandboxedModule($node, array_unique($this->filters), array_unique($this->tags), array_unique($this->functions));
|
80 |
+
}
|
81 |
+
|
82 |
+
return $node;
|
83 |
+
}
|
84 |
+
|
85 |
+
/**
|
86 |
+
* {@inheritdoc}
|
87 |
+
*/
|
88 |
+
public function getPriority()
|
89 |
+
{
|
90 |
+
return 0;
|
91 |
+
}
|
92 |
+
}
|
classes/Twig/NodeVisitorInterface.php
CHANGED
@@ -1,47 +1,47 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2009 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
/**
|
13 |
-
* Twig_NodeVisitorInterface is the interface the all node visitor classes must implement.
|
14 |
-
*
|
15 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
16 |
-
*/
|
17 |
-
interface Twig_NodeVisitorInterface
|
18 |
-
{
|
19 |
-
/**
|
20 |
-
* Called before child nodes are visited.
|
21 |
-
*
|
22 |
-
* @param Twig_NodeInterface $node The node to visit
|
23 |
-
* @param Twig_Environment $env The Twig environment instance
|
24 |
-
*
|
25 |
-
* @return Twig_NodeInterface The modified node
|
26 |
-
*/
|
27 |
-
public function enterNode(Twig_NodeInterface $node, Twig_Environment $env);
|
28 |
-
|
29 |
-
/**
|
30 |
-
* Called after child nodes are visited.
|
31 |
-
*
|
32 |
-
* @param Twig_NodeInterface $node The node to visit
|
33 |
-
* @param Twig_Environment $env The Twig environment instance
|
34 |
-
*
|
35 |
-
* @return Twig_NodeInterface|false The modified node or false if the node must be removed
|
36 |
-
*/
|
37 |
-
public function leaveNode(Twig_NodeInterface $node, Twig_Environment $env);
|
38 |
-
|
39 |
-
/**
|
40 |
-
* Returns the priority for this visitor.
|
41 |
-
*
|
42 |
-
* Priority should be between -10 and 10 (0 is the default).
|
43 |
-
*
|
44 |
-
* @return int The priority level
|
45 |
-
*/
|
46 |
-
public function getPriority();
|
47 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2009 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Twig_NodeVisitorInterface is the interface the all node visitor classes must implement.
|
14 |
+
*
|
15 |
+
* @author Fabien Potencier <fabien@symfony.com>
|
16 |
+
*/
|
17 |
+
interface Twig_NodeVisitorInterface
|
18 |
+
{
|
19 |
+
/**
|
20 |
+
* Called before child nodes are visited.
|
21 |
+
*
|
22 |
+
* @param Twig_NodeInterface $node The node to visit
|
23 |
+
* @param Twig_Environment $env The Twig environment instance
|
24 |
+
*
|
25 |
+
* @return Twig_NodeInterface The modified node
|
26 |
+
*/
|
27 |
+
public function enterNode(Twig_NodeInterface $node, Twig_Environment $env);
|
28 |
+
|
29 |
+
/**
|
30 |
+
* Called after child nodes are visited.
|
31 |
+
*
|
32 |
+
* @param Twig_NodeInterface $node The node to visit
|
33 |
+
* @param Twig_Environment $env The Twig environment instance
|
34 |
+
*
|
35 |
+
* @return Twig_NodeInterface|false The modified node or false if the node must be removed
|
36 |
+
*/
|
37 |
+
public function leaveNode(Twig_NodeInterface $node, Twig_Environment $env);
|
38 |
+
|
39 |
+
/**
|
40 |
+
* Returns the priority for this visitor.
|
41 |
+
*
|
42 |
+
* Priority should be between -10 and 10 (0 is the default).
|
43 |
+
*
|
44 |
+
* @return int The priority level
|
45 |
+
*/
|
46 |
+
public function getPriority();
|
47 |
+
}
|
classes/Twig/Parser.php
CHANGED
@@ -1,390 +1,390 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2009 Fabien Potencier
|
7 |
-
* (c) 2009 Armin Ronacher
|
8 |
-
*
|
9 |
-
* For the full copyright and license information, please view the LICENSE
|
10 |
-
* file that was distributed with this source code.
|
11 |
-
*/
|
12 |
-
|
13 |
-
/**
|
14 |
-
* Default parser implementation.
|
15 |
-
*
|
16 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
17 |
-
*/
|
18 |
-
class Twig_Parser implements Twig_ParserInterface
|
19 |
-
{
|
20 |
-
protected $stack = array();
|
21 |
-
protected $stream;
|
22 |
-
protected $parent;
|
23 |
-
protected $handlers;
|
24 |
-
protected $visitors;
|
25 |
-
protected $expressionParser;
|
26 |
-
protected $blocks;
|
27 |
-
protected $blockStack;
|
28 |
-
protected $macros;
|
29 |
-
protected $env;
|
30 |
-
protected $reservedMacroNames;
|
31 |
-
protected $importedSymbols;
|
32 |
-
protected $traits;
|
33 |
-
protected $embeddedTemplates = array();
|
34 |
-
|
35 |
-
/**
|
36 |
-
* Constructor.
|
37 |
-
*
|
38 |
-
* @param Twig_Environment $env A Twig_Environment instance
|
39 |
-
*/
|
40 |
-
public function __construct(Twig_Environment $env)
|
41 |
-
{
|
42 |
-
$this->env = $env;
|
43 |
-
}
|
44 |
-
|
45 |
-
public function getEnvironment()
|
46 |
-
{
|
47 |
-
return $this->env;
|
48 |
-
}
|
49 |
-
|
50 |
-
public function getVarName()
|
51 |
-
{
|
52 |
-
return sprintf('__internal_%s', hash('sha256', uniqid(mt_rand(), true), false));
|
53 |
-
}
|
54 |
-
|
55 |
-
public function getFilename()
|
56 |
-
{
|
57 |
-
return $this->stream->getFilename();
|
58 |
-
}
|
59 |
-
|
60 |
-
/**
|
61 |
-
* {@inheritdoc}
|
62 |
-
*/
|
63 |
-
public function parse(Twig_TokenStream $stream, $test = null, $dropNeedle = false)
|
64 |
-
{
|
65 |
-
// push all variables into the stack to keep the current state of the parser
|
66 |
-
$vars = get_object_vars($this);
|
67 |
-
unset($vars['stack'], $vars['env'], $vars['handlers'], $vars['visitors'], $vars['expressionParser']);
|
68 |
-
$this->stack[] = $vars;
|
69 |
-
|
70 |
-
// tag handlers
|
71 |
-
if (null === $this->handlers) {
|
72 |
-
$this->handlers = $this->env->getTokenParsers();
|
73 |
-
$this->handlers->setParser($this);
|
74 |
-
}
|
75 |
-
|
76 |
-
// node visitors
|
77 |
-
if (null === $this->visitors) {
|
78 |
-
$this->visitors = $this->env->getNodeVisitors();
|
79 |
-
}
|
80 |
-
|
81 |
-
if (null === $this->expressionParser) {
|
82 |
-
$this->expressionParser = new Twig_ExpressionParser($this, $this->env->getUnaryOperators(), $this->env->getBinaryOperators());
|
83 |
-
}
|
84 |
-
|
85 |
-
$this->stream = $stream;
|
86 |
-
$this->parent = null;
|
87 |
-
$this->blocks = array();
|
88 |
-
$this->macros = array();
|
89 |
-
$this->traits = array();
|
90 |
-
$this->blockStack = array();
|
91 |
-
$this->importedSymbols = array(array());
|
92 |
-
$this->embeddedTemplates = array();
|
93 |
-
|
94 |
-
try {
|
95 |
-
$body = $this->subparse($test, $dropNeedle);
|
96 |
-
|
97 |
-
if (null !== $this->parent) {
|
98 |
-
if (null === $body = $this->filterBodyNodes($body)) {
|
99 |
-
$body = new Twig_Node();
|
100 |
-
}
|
101 |
-
}
|
102 |
-
} catch (Twig_Error_Syntax $e) {
|
103 |
-
if (!$e->getTemplateFile()) {
|
104 |
-
$e->setTemplateFile($this->getFilename());
|
105 |
-
}
|
106 |
-
|
107 |
-
if (!$e->getTemplateLine()) {
|
108 |
-
$e->setTemplateLine($this->stream->getCurrent()->getLine());
|
109 |
-
}
|
110 |
-
|
111 |
-
throw $e;
|
112 |
-
}
|
113 |
-
|
114 |
-
$node = new Twig_Node_Module(new Twig_Node_Body(array($body)), $this->parent, new Twig_Node($this->blocks), new Twig_Node($this->macros), new Twig_Node($this->traits), $this->embeddedTemplates, $this->getFilename());
|
115 |
-
|
116 |
-
$traverser = new Twig_NodeTraverser($this->env, $this->visitors);
|
117 |
-
|
118 |
-
$node = $traverser->traverse($node);
|
119 |
-
|
120 |
-
// restore previous stack so previous parse() call can resume working
|
121 |
-
foreach (array_pop($this->stack) as $key => $val) {
|
122 |
-
$this->$key = $val;
|
123 |
-
}
|
124 |
-
|
125 |
-
return $node;
|
126 |
-
}
|
127 |
-
|
128 |
-
public function subparse($test, $dropNeedle = false)
|
129 |
-
{
|
130 |
-
$lineno = $this->getCurrentToken()->getLine();
|
131 |
-
$rv = array();
|
132 |
-
while (!$this->stream->isEOF()) {
|
133 |
-
switch ($this->getCurrentToken()->getType()) {
|
134 |
-
case Twig_Token::TEXT_TYPE:
|
135 |
-
$token = $this->stream->next();
|
136 |
-
$rv[] = new Twig_Node_Text($token->getValue(), $token->getLine());
|
137 |
-
break;
|
138 |
-
|
139 |
-
case Twig_Token::VAR_START_TYPE:
|
140 |
-
$token = $this->stream->next();
|
141 |
-
$expr = $this->expressionParser->parseExpression();
|
142 |
-
$this->stream->expect(Twig_Token::VAR_END_TYPE);
|
143 |
-
$rv[] = new Twig_Node_Print($expr, $token->getLine());
|
144 |
-
break;
|
145 |
-
|
146 |
-
case Twig_Token::BLOCK_START_TYPE:
|
147 |
-
$this->stream->next();
|
148 |
-
$token = $this->getCurrentToken();
|
149 |
-
|
150 |
-
if ($token->getType() !== Twig_Token::NAME_TYPE) {
|
151 |
-
throw new Twig_Error_Syntax('A block must start with a tag name', $token->getLine(), $this->getFilename());
|
152 |
-
}
|
153 |
-
|
154 |
-
if (null !== $test && call_user_func($test, $token)) {
|
155 |
-
if ($dropNeedle) {
|
156 |
-
$this->stream->next();
|
157 |
-
}
|
158 |
-
|
159 |
-
if (1 === count($rv)) {
|
160 |
-
return $rv[0];
|
161 |
-
}
|
162 |
-
|
163 |
-
return new Twig_Node($rv, array(), $lineno);
|
164 |
-
}
|
165 |
-
|
166 |
-
$subparser = $this->handlers->getTokenParser($token->getValue());
|
167 |
-
if (null === $subparser) {
|
168 |
-
if (null !== $test) {
|
169 |
-
$error = sprintf('Unexpected tag name "%s"', $token->getValue());
|
170 |
-
if (is_array($test) && isset($test[0]) && $test[0] instanceof Twig_TokenParserInterface) {
|
171 |
-
$error .= sprintf(' (expecting closing tag for the "%s" tag defined near line %s)', $test[0]->getTag(), $lineno);
|
172 |
-
}
|
173 |
-
|
174 |
-
throw new Twig_Error_Syntax($error, $token->getLine(), $this->getFilename());
|
175 |
-
}
|
176 |
-
|
177 |
-
$message = sprintf('Unknown tag name "%s"', $token->getValue());
|
178 |
-
if ($alternatives = $this->env->computeAlternatives($token->getValue(), array_keys($this->env->getTags()))) {
|
179 |
-
$message = sprintf('%s. Did you mean "%s"', $message, implode('", "', $alternatives));
|
180 |
-
}
|
181 |
-
|
182 |
-
throw new Twig_Error_Syntax($message, $token->getLine(), $this->getFilename());
|
183 |
-
}
|
184 |
-
|
185 |
-
$this->stream->next();
|
186 |
-
|
187 |
-
$node = $subparser->parse($token);
|
188 |
-
if (null !== $node) {
|
189 |
-
$rv[] = $node;
|
190 |
-
}
|
191 |
-
break;
|
192 |
-
|
193 |
-
default:
|
194 |
-
throw new Twig_Error_Syntax('Lexer or parser ended up in unsupported state.', 0, $this->getFilename());
|
195 |
-
}
|
196 |
-
}
|
197 |
-
|
198 |
-
if (1 === count($rv)) {
|
199 |
-
return $rv[0];
|
200 |
-
}
|
201 |
-
|
202 |
-
return new Twig_Node($rv, array(), $lineno);
|
203 |
-
}
|
204 |
-
|
205 |
-
public function addHandler($name, $class)
|
206 |
-
{
|
207 |
-
$this->handlers[$name] = $class;
|
208 |
-
}
|
209 |
-
|
210 |
-
public function addNodeVisitor(Twig_NodeVisitorInterface $visitor)
|
211 |
-
{
|
212 |
-
$this->visitors[] = $visitor;
|
213 |
-
}
|
214 |
-
|
215 |
-
public function getBlockStack()
|
216 |
-
{
|
217 |
-
return $this->blockStack;
|
218 |
-
}
|
219 |
-
|
220 |
-
public function peekBlockStack()
|
221 |
-
{
|
222 |
-
return $this->blockStack[count($this->blockStack) - 1];
|
223 |
-
}
|
224 |
-
|
225 |
-
public function popBlockStack()
|
226 |
-
{
|
227 |
-
array_pop($this->blockStack);
|
228 |
-
}
|
229 |
-
|
230 |
-
public function pushBlockStack($name)
|
231 |
-
{
|
232 |
-
$this->blockStack[] = $name;
|
233 |
-
}
|
234 |
-
|
235 |
-
public function hasBlock($name)
|
236 |
-
{
|
237 |
-
return isset($this->blocks[$name]);
|
238 |
-
}
|
239 |
-
|
240 |
-
public function getBlock($name)
|
241 |
-
{
|
242 |
-
return $this->blocks[$name];
|
243 |
-
}
|
244 |
-
|
245 |
-
public function setBlock($name, Twig_Node_Block $value)
|
246 |
-
{
|
247 |
-
$this->blocks[$name] = new Twig_Node_Body(array($value), array(), $value->getLine());
|
248 |
-
}
|
249 |
-
|
250 |
-
public function hasMacro($name)
|
251 |
-
{
|
252 |
-
return isset($this->macros[$name]);
|
253 |
-
}
|
254 |
-
|
255 |
-
public function setMacro($name, Twig_Node_Macro $node)
|
256 |
-
{
|
257 |
-
if (null === $this->reservedMacroNames) {
|
258 |
-
$this->reservedMacroNames = array();
|
259 |
-
$r = new ReflectionClass($this->env->getBaseTemplateClass());
|
260 |
-
foreach ($r->getMethods() as $method) {
|
261 |
-
$this->reservedMacroNames[] = $method->getName();
|
262 |
-
}
|
263 |
-
}
|
264 |
-
|
265 |
-
if (in_array($name, $this->reservedMacroNames)) {
|
266 |
-
throw new Twig_Error_Syntax(sprintf('"%s" cannot be used as a macro name as it is a reserved keyword', $name), $node->getLine(), $this->getFilename());
|
267 |
-
}
|
268 |
-
|
269 |
-
$this->macros[$name] = $node;
|
270 |
-
}
|
271 |
-
|
272 |
-
public function addTrait($trait)
|
273 |
-
{
|
274 |
-
$this->traits[] = $trait;
|
275 |
-
}
|
276 |
-
|
277 |
-
public function hasTraits()
|
278 |
-
{
|
279 |
-
return count($this->traits) > 0;
|
280 |
-
}
|
281 |
-
|
282 |
-
public function embedTemplate(Twig_Node_Module $template)
|
283 |
-
{
|
284 |
-
$template->setIndex(mt_rand());
|
285 |
-
|
286 |
-
$this->embeddedTemplates[] = $template;
|
287 |
-
}
|
288 |
-
|
289 |
-
public function addImportedSymbol($type, $alias, $name = null, Twig_Node_Expression $node = null)
|
290 |
-
{
|
291 |
-
$this->importedSymbols[0][$type][$alias] = array('name' => $name, 'node' => $node);
|
292 |
-
}
|
293 |
-
|
294 |
-
public function getImportedSymbol($type, $alias)
|
295 |
-
{
|
296 |
-
foreach ($this->importedSymbols as $functions) {
|
297 |
-
if (isset($functions[$type][$alias])) {
|
298 |
-
return $functions[$type][$alias];
|
299 |
-
}
|
300 |
-
}
|
301 |
-
}
|
302 |
-
|
303 |
-
public function isMainScope()
|
304 |
-
{
|
305 |
-
return 1 === count($this->importedSymbols);
|
306 |
-
}
|
307 |
-
|
308 |
-
public function pushLocalScope()
|
309 |
-
{
|
310 |
-
array_unshift($this->importedSymbols, array());
|
311 |
-
}
|
312 |
-
|
313 |
-
public function popLocalScope()
|
314 |
-
{
|
315 |
-
array_shift($this->importedSymbols);
|
316 |
-
}
|
317 |
-
|
318 |
-
/**
|
319 |
-
* Gets the expression parser.
|
320 |
-
*
|
321 |
-
* @return Twig_ExpressionParser The expression parser
|
322 |
-
*/
|
323 |
-
public function getExpressionParser()
|
324 |
-
{
|
325 |
-
return $this->expressionParser;
|
326 |
-
}
|
327 |
-
|
328 |
-
public function getParent()
|
329 |
-
{
|
330 |
-
return $this->parent;
|
331 |
-
}
|
332 |
-
|
333 |
-
public function setParent($parent)
|
334 |
-
{
|
335 |
-
$this->parent = $parent;
|
336 |
-
}
|
337 |
-
|
338 |
-
/**
|
339 |
-
* Gets the token stream.
|
340 |
-
*
|
341 |
-
* @return Twig_TokenStream The token stream
|
342 |
-
*/
|
343 |
-
public function getStream()
|
344 |
-
{
|
345 |
-
return $this->stream;
|
346 |
-
}
|
347 |
-
|
348 |
-
/**
|
349 |
-
* Gets the current token.
|
350 |
-
*
|
351 |
-
* @return Twig_Token The current token
|
352 |
-
*/
|
353 |
-
public function getCurrentToken()
|
354 |
-
{
|
355 |
-
return $this->stream->getCurrent();
|
356 |
-
}
|
357 |
-
|
358 |
-
protected function filterBodyNodes(Twig_NodeInterface $node)
|
359 |
-
{
|
360 |
-
// check that the body does not contain non-empty output nodes
|
361 |
-
if (
|
362 |
-
($node instanceof Twig_Node_Text && !ctype_space($node->getAttribute('data')))
|
363 |
-
||
|
364 |
-
(!$node instanceof Twig_Node_Text && !$node instanceof Twig_Node_BlockReference && $node instanceof Twig_NodeOutputInterface)
|
365 |
-
) {
|
366 |
-
if (false !== strpos((string) $node, chr(0xEF).chr(0xBB).chr(0xBF))) {
|
367 |
-
throw new Twig_Error_Syntax('A template that extends another one cannot have a body but a byte order mark (BOM) has been detected; it must be removed.', $node->getLine(), $this->getFilename());
|
368 |
-
}
|
369 |
-
|
370 |
-
throw new Twig_Error_Syntax('A template that extends another one cannot have a body.', $node->getLine(), $this->getFilename());
|
371 |
-
}
|
372 |
-
|
373 |
-
// bypass "set" nodes as they "capture" the output
|
374 |
-
if ($node instanceof Twig_Node_Set) {
|
375 |
-
return $node;
|
376 |
-
}
|
377 |
-
|
378 |
-
if ($node instanceof Twig_NodeOutputInterface) {
|
379 |
-
return;
|
380 |
-
}
|
381 |
-
|
382 |
-
foreach ($node as $k => $n) {
|
383 |
-
if (null !== $n && null === $this->filterBodyNodes($n)) {
|
384 |
-
$node->removeNode($k);
|
385 |
-
}
|
386 |
-
}
|
387 |
-
|
388 |
-
return $node;
|
389 |
-
}
|
390 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2009 Fabien Potencier
|
7 |
+
* (c) 2009 Armin Ronacher
|
8 |
+
*
|
9 |
+
* For the full copyright and license information, please view the LICENSE
|
10 |
+
* file that was distributed with this source code.
|
11 |
+
*/
|
12 |
+
|
13 |
+
/**
|
14 |
+
* Default parser implementation.
|
15 |
+
*
|
16 |
+
* @author Fabien Potencier <fabien@symfony.com>
|
17 |
+
*/
|
18 |
+
class Twig_Parser implements Twig_ParserInterface
|
19 |
+
{
|
20 |
+
protected $stack = array();
|
21 |
+
protected $stream;
|
22 |
+
protected $parent;
|
23 |
+
protected $handlers;
|
24 |
+
protected $visitors;
|
25 |
+
protected $expressionParser;
|
26 |
+
protected $blocks;
|
27 |
+
protected $blockStack;
|
28 |
+
protected $macros;
|
29 |
+
protected $env;
|
30 |
+
protected $reservedMacroNames;
|
31 |
+
protected $importedSymbols;
|
32 |
+
protected $traits;
|
33 |
+
protected $embeddedTemplates = array();
|
34 |
+
|
35 |
+
/**
|
36 |
+
* Constructor.
|
37 |
+
*
|
38 |
+
* @param Twig_Environment $env A Twig_Environment instance
|
39 |
+
*/
|
40 |
+
public function __construct(Twig_Environment $env)
|
41 |
+
{
|
42 |
+
$this->env = $env;
|
43 |
+
}
|
44 |
+
|
45 |
+
public function getEnvironment()
|
46 |
+
{
|
47 |
+
return $this->env;
|
48 |
+
}
|
49 |
+
|
50 |
+
public function getVarName()
|
51 |
+
{
|
52 |
+
return sprintf('__internal_%s', hash('sha256', uniqid(mt_rand(), true), false));
|
53 |
+
}
|
54 |
+
|
55 |
+
public function getFilename()
|
56 |
+
{
|
57 |
+
return $this->stream->getFilename();
|
58 |
+
}
|
59 |
+
|
60 |
+
/**
|
61 |
+
* {@inheritdoc}
|
62 |
+
*/
|
63 |
+
public function parse(Twig_TokenStream $stream, $test = null, $dropNeedle = false)
|
64 |
+
{
|
65 |
+
// push all variables into the stack to keep the current state of the parser
|
66 |
+
$vars = get_object_vars($this);
|
67 |
+
unset($vars['stack'], $vars['env'], $vars['handlers'], $vars['visitors'], $vars['expressionParser']);
|
68 |
+
$this->stack[] = $vars;
|
69 |
+
|
70 |
+
// tag handlers
|
71 |
+
if (null === $this->handlers) {
|
72 |
+
$this->handlers = $this->env->getTokenParsers();
|
73 |
+
$this->handlers->setParser($this);
|
74 |
+
}
|
75 |
+
|
76 |
+
// node visitors
|
77 |
+
if (null === $this->visitors) {
|
78 |
+
$this->visitors = $this->env->getNodeVisitors();
|
79 |
+
}
|
80 |
+
|
81 |
+
if (null === $this->expressionParser) {
|
82 |
+
$this->expressionParser = new Twig_ExpressionParser($this, $this->env->getUnaryOperators(), $this->env->getBinaryOperators());
|
83 |
+
}
|
84 |
+
|
85 |
+
$this->stream = $stream;
|
86 |
+
$this->parent = null;
|
87 |
+
$this->blocks = array();
|
88 |
+
$this->macros = array();
|
89 |
+
$this->traits = array();
|
90 |
+
$this->blockStack = array();
|
91 |
+
$this->importedSymbols = array(array());
|
92 |
+
$this->embeddedTemplates = array();
|
93 |
+
|
94 |
+
try {
|
95 |
+
$body = $this->subparse($test, $dropNeedle);
|
96 |
+
|
97 |
+
if (null !== $this->parent) {
|
98 |
+
if (null === $body = $this->filterBodyNodes($body)) {
|
99 |
+
$body = new Twig_Node();
|
100 |
+
}
|
101 |
+
}
|
102 |
+
} catch (Twig_Error_Syntax $e) {
|
103 |
+
if (!$e->getTemplateFile()) {
|
104 |
+
$e->setTemplateFile($this->getFilename());
|
105 |
+
}
|
106 |
+
|
107 |
+
if (!$e->getTemplateLine()) {
|
108 |
+
$e->setTemplateLine($this->stream->getCurrent()->getLine());
|
109 |
+
}
|
110 |
+
|
111 |
+
throw $e;
|
112 |
+
}
|
113 |
+
|
114 |
+
$node = new Twig_Node_Module(new Twig_Node_Body(array($body)), $this->parent, new Twig_Node($this->blocks), new Twig_Node($this->macros), new Twig_Node($this->traits), $this->embeddedTemplates, $this->getFilename());
|
115 |
+
|
116 |
+
$traverser = new Twig_NodeTraverser($this->env, $this->visitors);
|
117 |
+
|
118 |
+
$node = $traverser->traverse($node);
|
119 |
+
|
120 |
+
// restore previous stack so previous parse() call can resume working
|
121 |
+
foreach (array_pop($this->stack) as $key => $val) {
|
122 |
+
$this->$key = $val;
|
123 |
+
}
|
124 |
+
|
125 |
+
return $node;
|
126 |
+
}
|
127 |
+
|
128 |
+
public function subparse($test, $dropNeedle = false)
|
129 |
+
{
|
130 |
+
$lineno = $this->getCurrentToken()->getLine();
|
131 |
+
$rv = array();
|
132 |
+
while (!$this->stream->isEOF()) {
|
133 |
+
switch ($this->getCurrentToken()->getType()) {
|
134 |
+
case Twig_Token::TEXT_TYPE:
|
135 |
+
$token = $this->stream->next();
|
136 |
+
$rv[] = new Twig_Node_Text($token->getValue(), $token->getLine());
|
137 |
+
break;
|
138 |
+
|
139 |
+
case Twig_Token::VAR_START_TYPE:
|
140 |
+
$token = $this->stream->next();
|
141 |
+
$expr = $this->expressionParser->parseExpression();
|
142 |
+
$this->stream->expect(Twig_Token::VAR_END_TYPE);
|
143 |
+
$rv[] = new Twig_Node_Print($expr, $token->getLine());
|
144 |
+
break;
|
145 |
+
|
146 |
+
case Twig_Token::BLOCK_START_TYPE:
|
147 |
+
$this->stream->next();
|
148 |
+
$token = $this->getCurrentToken();
|
149 |
+
|
150 |
+
if ($token->getType() !== Twig_Token::NAME_TYPE) {
|
151 |
+
throw new Twig_Error_Syntax('A block must start with a tag name', $token->getLine(), $this->getFilename());
|
152 |
+
}
|
153 |
+
|
154 |
+
if (null !== $test && call_user_func($test, $token)) {
|
155 |
+
if ($dropNeedle) {
|
156 |
+
$this->stream->next();
|
157 |
+
}
|
158 |
+
|
159 |
+
if (1 === count($rv)) {
|
160 |
+
return $rv[0];
|
161 |
+
}
|
162 |
+
|
163 |
+
return new Twig_Node($rv, array(), $lineno);
|
164 |
+
}
|
165 |
+
|
166 |
+
$subparser = $this->handlers->getTokenParser($token->getValue());
|
167 |
+
if (null === $subparser) {
|
168 |
+
if (null !== $test) {
|
169 |
+
$error = sprintf('Unexpected tag name "%s"', $token->getValue());
|
170 |
+
if (is_array($test) && isset($test[0]) && $test[0] instanceof Twig_TokenParserInterface) {
|
171 |
+
$error .= sprintf(' (expecting closing tag for the "%s" tag defined near line %s)', $test[0]->getTag(), $lineno);
|
172 |
+
}
|
173 |
+
|
174 |
+
throw new Twig_Error_Syntax($error, $token->getLine(), $this->getFilename());
|
175 |
+
}
|
176 |
+
|
177 |
+
$message = sprintf('Unknown tag name "%s"', $token->getValue());
|
178 |
+
if ($alternatives = $this->env->computeAlternatives($token->getValue(), array_keys($this->env->getTags()))) {
|
179 |
+
$message = sprintf('%s. Did you mean "%s"', $message, implode('", "', $alternatives));
|
180 |
+
}
|
181 |
+
|
182 |
+
throw new Twig_Error_Syntax($message, $token->getLine(), $this->getFilename());
|
183 |
+
}
|
184 |
+
|
185 |
+
$this->stream->next();
|
186 |
+
|
187 |
+
$node = $subparser->parse($token);
|
188 |
+
if (null !== $node) {
|
189 |
+
$rv[] = $node;
|
190 |
+
}
|
191 |
+
break;
|
192 |
+
|
193 |
+
default:
|
194 |
+
throw new Twig_Error_Syntax('Lexer or parser ended up in unsupported state.', 0, $this->getFilename());
|
195 |
+
}
|
196 |
+
}
|
197 |
+
|
198 |
+
if (1 === count($rv)) {
|
199 |
+
return $rv[0];
|
200 |
+
}
|
201 |
+
|
202 |
+
return new Twig_Node($rv, array(), $lineno);
|
203 |
+
}
|
204 |
+
|
205 |
+
public function addHandler($name, $class)
|
206 |
+
{
|
207 |
+
$this->handlers[$name] = $class;
|
208 |
+
}
|
209 |
+
|
210 |
+
public function addNodeVisitor(Twig_NodeVisitorInterface $visitor)
|
211 |
+
{
|
212 |
+
$this->visitors[] = $visitor;
|
213 |
+
}
|
214 |
+
|
215 |
+
public function getBlockStack()
|
216 |
+
{
|
217 |
+
return $this->blockStack;
|
218 |
+
}
|
219 |
+
|
220 |
+
public function peekBlockStack()
|
221 |
+
{
|
222 |
+
return $this->blockStack[count($this->blockStack) - 1];
|
223 |
+
}
|
224 |
+
|
225 |
+
public function popBlockStack()
|
226 |
+
{
|
227 |
+
array_pop($this->blockStack);
|
228 |
+
}
|
229 |
+
|
230 |
+
public function pushBlockStack($name)
|
231 |
+
{
|
232 |
+
$this->blockStack[] = $name;
|
233 |
+
}
|
234 |
+
|
235 |
+
public function hasBlock($name)
|
236 |
+
{
|
237 |
+
return isset($this->blocks[$name]);
|
238 |
+
}
|
239 |
+
|
240 |
+
public function getBlock($name)
|
241 |
+
{
|
242 |
+
return $this->blocks[$name];
|
243 |
+
}
|
244 |
+
|
245 |
+
public function setBlock($name, Twig_Node_Block $value)
|
246 |
+
{
|
247 |
+
$this->blocks[$name] = new Twig_Node_Body(array($value), array(), $value->getLine());
|
248 |
+
}
|
249 |
+
|
250 |
+
public function hasMacro($name)
|
251 |
+
{
|
252 |
+
return isset($this->macros[$name]);
|
253 |
+
}
|
254 |
+
|
255 |
+
public function setMacro($name, Twig_Node_Macro $node)
|
256 |
+
{
|
257 |
+
if (null === $this->reservedMacroNames) {
|
258 |
+
$this->reservedMacroNames = array();
|
259 |
+
$r = new ReflectionClass($this->env->getBaseTemplateClass());
|
260 |
+
foreach ($r->getMethods() as $method) {
|
261 |
+
$this->reservedMacroNames[] = $method->getName();
|
262 |
+
}
|
263 |
+
}
|
264 |
+
|
265 |
+
if (in_array($name, $this->reservedMacroNames)) {
|
266 |
+
throw new Twig_Error_Syntax(sprintf('"%s" cannot be used as a macro name as it is a reserved keyword', $name), $node->getLine(), $this->getFilename());
|
267 |
+
}
|
268 |
+
|
269 |
+
$this->macros[$name] = $node;
|
270 |
+
}
|
271 |
+
|
272 |
+
public function addTrait($trait)
|
273 |
+
{
|
274 |
+
$this->traits[] = $trait;
|
275 |
+
}
|
276 |
+
|
277 |
+
public function hasTraits()
|
278 |
+
{
|
279 |
+
return count($this->traits) > 0;
|
280 |
+
}
|
281 |
+
|
282 |
+
public function embedTemplate(Twig_Node_Module $template)
|
283 |
+
{
|
284 |
+
$template->setIndex(mt_rand());
|
285 |
+
|
286 |
+
$this->embeddedTemplates[] = $template;
|
287 |
+
}
|
288 |
+
|
289 |
+
public function addImportedSymbol($type, $alias, $name = null, Twig_Node_Expression $node = null)
|
290 |
+
{
|
291 |
+
$this->importedSymbols[0][$type][$alias] = array('name' => $name, 'node' => $node);
|
292 |
+
}
|
293 |
+
|
294 |
+
public function getImportedSymbol($type, $alias)
|
295 |
+
{
|
296 |
+
foreach ($this->importedSymbols as $functions) {
|
297 |
+
if (isset($functions[$type][$alias])) {
|
298 |
+
return $functions[$type][$alias];
|
299 |
+
}
|
300 |
+
}
|
301 |
+
}
|
302 |
+
|
303 |
+
public function isMainScope()
|
304 |
+
{
|
305 |
+
return 1 === count($this->importedSymbols);
|
306 |
+
}
|
307 |
+
|
308 |
+
public function pushLocalScope()
|
309 |
+
{
|
310 |
+
array_unshift($this->importedSymbols, array());
|
311 |
+
}
|
312 |
+
|
313 |
+
public function popLocalScope()
|
314 |
+
{
|
315 |
+
array_shift($this->importedSymbols);
|
316 |
+
}
|
317 |
+
|
318 |
+
/**
|
319 |
+
* Gets the expression parser.
|
320 |
+
*
|
321 |
+
* @return Twig_ExpressionParser The expression parser
|
322 |
+
*/
|
323 |
+
public function getExpressionParser()
|
324 |
+
{
|
325 |
+
return $this->expressionParser;
|
326 |
+
}
|
327 |
+
|
328 |
+
public function getParent()
|
329 |
+
{
|
330 |
+
return $this->parent;
|
331 |
+
}
|
332 |
+
|
333 |
+
public function setParent($parent)
|
334 |
+
{
|
335 |
+
$this->parent = $parent;
|
336 |
+
}
|
337 |
+
|
338 |
+
/**
|
339 |
+
* Gets the token stream.
|
340 |
+
*
|
341 |
+
* @return Twig_TokenStream The token stream
|
342 |
+
*/
|
343 |
+
public function getStream()
|
344 |
+
{
|
345 |
+
return $this->stream;
|
346 |
+
}
|
347 |
+
|
348 |
+
/**
|
349 |
+
* Gets the current token.
|
350 |
+
*
|
351 |
+
* @return Twig_Token The current token
|
352 |
+
*/
|
353 |
+
public function getCurrentToken()
|
354 |
+
{
|
355 |
+
return $this->stream->getCurrent();
|
356 |
+
}
|
357 |
+
|
358 |
+
protected function filterBodyNodes(Twig_NodeInterface $node)
|
359 |
+
{
|
360 |
+
// check that the body does not contain non-empty output nodes
|
361 |
+
if (
|
362 |
+
($node instanceof Twig_Node_Text && !ctype_space($node->getAttribute('data')))
|
363 |
+
||
|
364 |
+
(!$node instanceof Twig_Node_Text && !$node instanceof Twig_Node_BlockReference && $node instanceof Twig_NodeOutputInterface)
|
365 |
+
) {
|
366 |
+
if (false !== strpos((string) $node, chr(0xEF).chr(0xBB).chr(0xBF))) {
|
367 |
+
throw new Twig_Error_Syntax('A template that extends another one cannot have a body but a byte order mark (BOM) has been detected; it must be removed.', $node->getLine(), $this->getFilename());
|
368 |
+
}
|
369 |
+
|
370 |
+
throw new Twig_Error_Syntax('A template that extends another one cannot have a body.', $node->getLine(), $this->getFilename());
|
371 |
+
}
|
372 |
+
|
373 |
+
// bypass "set" nodes as they "capture" the output
|
374 |
+
if ($node instanceof Twig_Node_Set) {
|
375 |
+
return $node;
|
376 |
+
}
|
377 |
+
|
378 |
+
if ($node instanceof Twig_NodeOutputInterface) {
|
379 |
+
return;
|
380 |
+
}
|
381 |
+
|
382 |
+
foreach ($node as $k => $n) {
|
383 |
+
if (null !== $n && null === $this->filterBodyNodes($n)) {
|
384 |
+
$node->removeNode($k);
|
385 |
+
}
|
386 |
+
}
|
387 |
+
|
388 |
+
return $node;
|
389 |
+
}
|
390 |
+
}
|
classes/Twig/ParserInterface.php
CHANGED
@@ -1,31 +1,31 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2009 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
/**
|
13 |
-
* Interface implemented by parser classes.
|
14 |
-
*
|
15 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
16 |
-
*
|
17 |
-
* @deprecated since 1.12 (to be removed in 3.0)
|
18 |
-
*/
|
19 |
-
interface Twig_ParserInterface
|
20 |
-
{
|
21 |
-
/**
|
22 |
-
* Converts a token stream to a node tree.
|
23 |
-
*
|
24 |
-
* @param Twig_TokenStream $stream A token stream instance
|
25 |
-
*
|
26 |
-
* @return Twig_Node_Module A node tree
|
27 |
-
*
|
28 |
-
* @throws Twig_Error_Syntax When the token stream is syntactically or semantically wrong
|
29 |
-
*/
|
30 |
-
public function parse(Twig_TokenStream $stream);
|
31 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2009 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Interface implemented by parser classes.
|
14 |
+
*
|
15 |
+
* @author Fabien Potencier <fabien@symfony.com>
|
16 |
+
*
|
17 |
+
* @deprecated since 1.12 (to be removed in 3.0)
|
18 |
+
*/
|
19 |
+
interface Twig_ParserInterface
|
20 |
+
{
|
21 |
+
/**
|
22 |
+
* Converts a token stream to a node tree.
|
23 |
+
*
|
24 |
+
* @param Twig_TokenStream $stream A token stream instance
|
25 |
+
*
|
26 |
+
* @return Twig_Node_Module A node tree
|
27 |
+
*
|
28 |
+
* @throws Twig_Error_Syntax When the token stream is syntactically or semantically wrong
|
29 |
+
*/
|
30 |
+
public function parse(Twig_TokenStream $stream);
|
31 |
+
}
|
classes/Twig/Sandbox/SecurityError.php
CHANGED
@@ -1,19 +1,19 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2009 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
/**
|
13 |
-
* Exception thrown when a security error occurs at runtime.
|
14 |
-
*
|
15 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
16 |
-
*/
|
17 |
-
class Twig_Sandbox_SecurityError extends Twig_Error
|
18 |
-
{
|
19 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2009 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Exception thrown when a security error occurs at runtime.
|
14 |
+
*
|
15 |
+
* @author Fabien Potencier <fabien@symfony.com>
|
16 |
+
*/
|
17 |
+
class Twig_Sandbox_SecurityError extends Twig_Error
|
18 |
+
{
|
19 |
+
}
|
classes/Twig/Sandbox/SecurityPolicy.php
CHANGED
@@ -1,119 +1,119 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2009 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
/**
|
13 |
-
* Represents a security policy which need to be enforced when sandbox mode is enabled.
|
14 |
-
*
|
15 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
16 |
-
*/
|
17 |
-
class Twig_Sandbox_SecurityPolicy implements Twig_Sandbox_SecurityPolicyInterface
|
18 |
-
{
|
19 |
-
protected $allowedTags;
|
20 |
-
protected $allowedFilters;
|
21 |
-
protected $allowedMethods;
|
22 |
-
protected $allowedProperties;
|
23 |
-
protected $allowedFunctions;
|
24 |
-
|
25 |
-
public function __construct(array $allowedTags = array(), array $allowedFilters = array(), array $allowedMethods = array(), array $allowedProperties = array(), array $allowedFunctions = array())
|
26 |
-
{
|
27 |
-
$this->allowedTags = $allowedTags;
|
28 |
-
$this->allowedFilters = $allowedFilters;
|
29 |
-
$this->setAllowedMethods($allowedMethods);
|
30 |
-
$this->allowedProperties = $allowedProperties;
|
31 |
-
$this->allowedFunctions = $allowedFunctions;
|
32 |
-
}
|
33 |
-
|
34 |
-
public function setAllowedTags(array $tags)
|
35 |
-
{
|
36 |
-
$this->allowedTags = $tags;
|
37 |
-
}
|
38 |
-
|
39 |
-
public function setAllowedFilters(array $filters)
|
40 |
-
{
|
41 |
-
$this->allowedFilters = $filters;
|
42 |
-
}
|
43 |
-
|
44 |
-
public function setAllowedMethods(array $methods)
|
45 |
-
{
|
46 |
-
$this->allowedMethods = array();
|
47 |
-
foreach ($methods as $class => $m) {
|
48 |
-
$this->allowedMethods[$class] = array_map('strtolower', is_array($m) ? $m : array($m));
|
49 |
-
}
|
50 |
-
}
|
51 |
-
|
52 |
-
public function setAllowedProperties(array $properties)
|
53 |
-
{
|
54 |
-
$this->allowedProperties = $properties;
|
55 |
-
}
|
56 |
-
|
57 |
-
public function setAllowedFunctions(array $functions)
|
58 |
-
{
|
59 |
-
$this->allowedFunctions = $functions;
|
60 |
-
}
|
61 |
-
|
62 |
-
public function checkSecurity($tags, $filters, $functions)
|
63 |
-
{
|
64 |
-
foreach ($tags as $tag) {
|
65 |
-
if (!in_array($tag, $this->allowedTags)) {
|
66 |
-
throw new Twig_Sandbox_SecurityError(sprintf('Tag "%s" is not allowed.', $tag));
|
67 |
-
}
|
68 |
-
}
|
69 |
-
|
70 |
-
foreach ($filters as $filter) {
|
71 |
-
if (!in_array($filter, $this->allowedFilters)) {
|
72 |
-
throw new Twig_Sandbox_SecurityError(sprintf('Filter "%s" is not allowed.', $filter));
|
73 |
-
}
|
74 |
-
}
|
75 |
-
|
76 |
-
foreach ($functions as $function) {
|
77 |
-
if (!in_array($function, $this->allowedFunctions)) {
|
78 |
-
throw new Twig_Sandbox_SecurityError(sprintf('Function "%s" is not allowed.', $function));
|
79 |
-
}
|
80 |
-
}
|
81 |
-
}
|
82 |
-
|
83 |
-
public function checkMethodAllowed($obj, $method)
|
84 |
-
{
|
85 |
-
if ($obj instanceof Twig_TemplateInterface || $obj instanceof Twig_Markup) {
|
86 |
-
return true;
|
87 |
-
}
|
88 |
-
|
89 |
-
$allowed = false;
|
90 |
-
$method = strtolower($method);
|
91 |
-
foreach ($this->allowedMethods as $class => $methods) {
|
92 |
-
if ($obj instanceof $class) {
|
93 |
-
$allowed = in_array($method, $methods);
|
94 |
-
|
95 |
-
break;
|
96 |
-
}
|
97 |
-
}
|
98 |
-
|
99 |
-
if (!$allowed) {
|
100 |
-
throw new Twig_Sandbox_SecurityError(sprintf('Calling "%s" method on a "%s" object is not allowed.', $method, get_class($obj)));
|
101 |
-
}
|
102 |
-
}
|
103 |
-
|
104 |
-
public function checkPropertyAllowed($obj, $property)
|
105 |
-
{
|
106 |
-
$allowed = false;
|
107 |
-
foreach ($this->allowedProperties as $class => $properties) {
|
108 |
-
if ($obj instanceof $class) {
|
109 |
-
$allowed = in_array($property, is_array($properties) ? $properties : array($properties));
|
110 |
-
|
111 |
-
break;
|
112 |
-
}
|
113 |
-
}
|
114 |
-
|
115 |
-
if (!$allowed) {
|
116 |
-
throw new Twig_Sandbox_SecurityError(sprintf('Calling "%s" property on a "%s" object is not allowed.', $property, get_class($obj)));
|
117 |
-
}
|
118 |
-
}
|
119 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2009 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Represents a security policy which need to be enforced when sandbox mode is enabled.
|
14 |
+
*
|
15 |
+
* @author Fabien Potencier <fabien@symfony.com>
|
16 |
+
*/
|
17 |
+
class Twig_Sandbox_SecurityPolicy implements Twig_Sandbox_SecurityPolicyInterface
|
18 |
+
{
|
19 |
+
protected $allowedTags;
|
20 |
+
protected $allowedFilters;
|
21 |
+
protected $allowedMethods;
|
22 |
+
protected $allowedProperties;
|
23 |
+
protected $allowedFunctions;
|
24 |
+
|
25 |
+
public function __construct(array $allowedTags = array(), array $allowedFilters = array(), array $allowedMethods = array(), array $allowedProperties = array(), array $allowedFunctions = array())
|
26 |
+
{
|
27 |
+
$this->allowedTags = $allowedTags;
|
28 |
+
$this->allowedFilters = $allowedFilters;
|
29 |
+
$this->setAllowedMethods($allowedMethods);
|
30 |
+
$this->allowedProperties = $allowedProperties;
|
31 |
+
$this->allowedFunctions = $allowedFunctions;
|
32 |
+
}
|
33 |
+
|
34 |
+
public function setAllowedTags(array $tags)
|
35 |
+
{
|
36 |
+
$this->allowedTags = $tags;
|
37 |
+
}
|
38 |
+
|
39 |
+
public function setAllowedFilters(array $filters)
|
40 |
+
{
|
41 |
+
$this->allowedFilters = $filters;
|
42 |
+
}
|
43 |
+
|
44 |
+
public function setAllowedMethods(array $methods)
|
45 |
+
{
|
46 |
+
$this->allowedMethods = array();
|
47 |
+
foreach ($methods as $class => $m) {
|
48 |
+
$this->allowedMethods[$class] = array_map('strtolower', is_array($m) ? $m : array($m));
|
49 |
+
}
|
50 |
+
}
|
51 |
+
|
52 |
+
public function setAllowedProperties(array $properties)
|
53 |
+
{
|
54 |
+
$this->allowedProperties = $properties;
|
55 |
+
}
|
56 |
+
|
57 |
+
public function setAllowedFunctions(array $functions)
|
58 |
+
{
|
59 |
+
$this->allowedFunctions = $functions;
|
60 |
+
}
|
61 |
+
|
62 |
+
public function checkSecurity($tags, $filters, $functions)
|
63 |
+
{
|
64 |
+
foreach ($tags as $tag) {
|
65 |
+
if (!in_array($tag, $this->allowedTags)) {
|
66 |
+
throw new Twig_Sandbox_SecurityError(sprintf('Tag "%s" is not allowed.', $tag));
|
67 |
+
}
|
68 |
+
}
|
69 |
+
|
70 |
+
foreach ($filters as $filter) {
|
71 |
+
if (!in_array($filter, $this->allowedFilters)) {
|
72 |
+
throw new Twig_Sandbox_SecurityError(sprintf('Filter "%s" is not allowed.', $filter));
|
73 |
+
}
|
74 |
+
}
|
75 |
+
|
76 |
+
foreach ($functions as $function) {
|
77 |
+
if (!in_array($function, $this->allowedFunctions)) {
|
78 |
+
throw new Twig_Sandbox_SecurityError(sprintf('Function "%s" is not allowed.', $function));
|
79 |
+
}
|
80 |
+
}
|
81 |
+
}
|
82 |
+
|
83 |
+
public function checkMethodAllowed($obj, $method)
|
84 |
+
{
|
85 |
+
if ($obj instanceof Twig_TemplateInterface || $obj instanceof Twig_Markup) {
|
86 |
+
return true;
|
87 |
+
}
|
88 |
+
|
89 |
+
$allowed = false;
|
90 |
+
$method = strtolower($method);
|
91 |
+
foreach ($this->allowedMethods as $class => $methods) {
|
92 |
+
if ($obj instanceof $class) {
|
93 |
+
$allowed = in_array($method, $methods);
|
94 |
+
|
95 |
+
break;
|
96 |
+
}
|
97 |
+
}
|
98 |
+
|
99 |
+
if (!$allowed) {
|
100 |
+
throw new Twig_Sandbox_SecurityError(sprintf('Calling "%s" method on a "%s" object is not allowed.', $method, get_class($obj)));
|
101 |
+
}
|
102 |
+
}
|
103 |
+
|
104 |
+
public function checkPropertyAllowed($obj, $property)
|
105 |
+
{
|
106 |
+
$allowed = false;
|
107 |
+
foreach ($this->allowedProperties as $class => $properties) {
|
108 |
+
if ($obj instanceof $class) {
|
109 |
+
$allowed = in_array($property, is_array($properties) ? $properties : array($properties));
|
110 |
+
|
111 |
+
break;
|
112 |
+
}
|
113 |
+
}
|
114 |
+
|
115 |
+
if (!$allowed) {
|
116 |
+
throw new Twig_Sandbox_SecurityError(sprintf('Calling "%s" property on a "%s" object is not allowed.', $property, get_class($obj)));
|
117 |
+
}
|
118 |
+
}
|
119 |
+
}
|
classes/Twig/Sandbox/SecurityPolicyInterface.php
CHANGED
@@ -1,24 +1,24 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2009 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
/**
|
13 |
-
* Interfaces that all security policy classes must implements.
|
14 |
-
*
|
15 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
16 |
-
*/
|
17 |
-
interface Twig_Sandbox_SecurityPolicyInterface
|
18 |
-
{
|
19 |
-
public function checkSecurity($tags, $filters, $functions);
|
20 |
-
|
21 |
-
public function checkMethodAllowed($obj, $method);
|
22 |
-
|
23 |
-
public function checkPropertyAllowed($obj, $method);
|
24 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2009 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Interfaces that all security policy classes must implements.
|
14 |
+
*
|
15 |
+
* @author Fabien Potencier <fabien@symfony.com>
|
16 |
+
*/
|
17 |
+
interface Twig_Sandbox_SecurityPolicyInterface
|
18 |
+
{
|
19 |
+
public function checkSecurity($tags, $filters, $functions);
|
20 |
+
|
21 |
+
public function checkMethodAllowed($obj, $method);
|
22 |
+
|
23 |
+
public function checkPropertyAllowed($obj, $method);
|
24 |
+
}
|
classes/Twig/SimpleFilter.php
CHANGED
@@ -1,94 +1,94 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2009-2012 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
/**
|
13 |
-
* Represents a template filter.
|
14 |
-
*
|
15 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
16 |
-
*/
|
17 |
-
class Twig_SimpleFilter
|
18 |
-
{
|
19 |
-
protected $name;
|
20 |
-
protected $callable;
|
21 |
-
protected $options;
|
22 |
-
protected $arguments = array();
|
23 |
-
|
24 |
-
public function __construct($name, $callable, array $options = array())
|
25 |
-
{
|
26 |
-
$this->name = $name;
|
27 |
-
$this->callable = $callable;
|
28 |
-
$this->options = array_merge(array(
|
29 |
-
'needs_environment' => false,
|
30 |
-
'needs_context' => false,
|
31 |
-
'is_safe' => null,
|
32 |
-
'is_safe_callback' => null,
|
33 |
-
'pre_escape' => null,
|
34 |
-
'preserves_safety' => null,
|
35 |
-
'node_class' => 'Twig_Node_Expression_Filter',
|
36 |
-
), $options);
|
37 |
-
}
|
38 |
-
|
39 |
-
public function getName()
|
40 |
-
{
|
41 |
-
return $this->name;
|
42 |
-
}
|
43 |
-
|
44 |
-
public function getCallable()
|
45 |
-
{
|
46 |
-
return $this->callable;
|
47 |
-
}
|
48 |
-
|
49 |
-
public function getNodeClass()
|
50 |
-
{
|
51 |
-
return $this->options['node_class'];
|
52 |
-
}
|
53 |
-
|
54 |
-
public function setArguments($arguments)
|
55 |
-
{
|
56 |
-
$this->arguments = $arguments;
|
57 |
-
}
|
58 |
-
|
59 |
-
public function getArguments()
|
60 |
-
{
|
61 |
-
return $this->arguments;
|
62 |
-
}
|
63 |
-
|
64 |
-
public function needsEnvironment()
|
65 |
-
{
|
66 |
-
return $this->options['needs_environment'];
|
67 |
-
}
|
68 |
-
|
69 |
-
public function needsContext()
|
70 |
-
{
|
71 |
-
return $this->options['needs_context'];
|
72 |
-
}
|
73 |
-
|
74 |
-
public function getSafe(Twig_Node $filterArgs)
|
75 |
-
{
|
76 |
-
if (null !== $this->options['is_safe']) {
|
77 |
-
return $this->options['is_safe'];
|
78 |
-
}
|
79 |
-
|
80 |
-
if (null !== $this->options['is_safe_callback']) {
|
81 |
-
return call_user_func($this->options['is_safe_callback'], $filterArgs);
|
82 |
-
}
|
83 |
-
}
|
84 |
-
|
85 |
-
public function getPreservesSafety()
|
86 |
-
{
|
87 |
-
return $this->options['preserves_safety'];
|
88 |
-
}
|
89 |
-
|
90 |
-
public function getPreEscape()
|
91 |
-
{
|
92 |
-
return $this->options['pre_escape'];
|
93 |
-
}
|
94 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2009-2012 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Represents a template filter.
|
14 |
+
*
|
15 |
+
* @author Fabien Potencier <fabien@symfony.com>
|
16 |
+
*/
|
17 |
+
class Twig_SimpleFilter
|
18 |
+
{
|
19 |
+
protected $name;
|
20 |
+
protected $callable;
|
21 |
+
protected $options;
|
22 |
+
protected $arguments = array();
|
23 |
+
|
24 |
+
public function __construct($name, $callable, array $options = array())
|
25 |
+
{
|
26 |
+
$this->name = $name;
|
27 |
+
$this->callable = $callable;
|
28 |
+
$this->options = array_merge(array(
|
29 |
+
'needs_environment' => false,
|
30 |
+
'needs_context' => false,
|
31 |
+
'is_safe' => null,
|
32 |
+
'is_safe_callback' => null,
|
33 |
+
'pre_escape' => null,
|
34 |
+
'preserves_safety' => null,
|
35 |
+
'node_class' => 'Twig_Node_Expression_Filter',
|
36 |
+
), $options);
|
37 |
+
}
|
38 |
+
|
39 |
+
public function getName()
|
40 |
+
{
|
41 |
+
return $this->name;
|
42 |
+
}
|
43 |
+
|
44 |
+
public function getCallable()
|
45 |
+
{
|
46 |
+
return $this->callable;
|
47 |
+
}
|
48 |
+
|
49 |
+
public function getNodeClass()
|
50 |
+
{
|
51 |
+
return $this->options['node_class'];
|
52 |
+
}
|
53 |
+
|
54 |
+
public function setArguments($arguments)
|
55 |
+
{
|
56 |
+
$this->arguments = $arguments;
|
57 |
+
}
|
58 |
+
|
59 |
+
public function getArguments()
|
60 |
+
{
|
61 |
+
return $this->arguments;
|
62 |
+
}
|
63 |
+
|
64 |
+
public function needsEnvironment()
|
65 |
+
{
|
66 |
+
return $this->options['needs_environment'];
|
67 |
+
}
|
68 |
+
|
69 |
+
public function needsContext()
|
70 |
+
{
|
71 |
+
return $this->options['needs_context'];
|
72 |
+
}
|
73 |
+
|
74 |
+
public function getSafe(Twig_Node $filterArgs)
|
75 |
+
{
|
76 |
+
if (null !== $this->options['is_safe']) {
|
77 |
+
return $this->options['is_safe'];
|
78 |
+
}
|
79 |
+
|
80 |
+
if (null !== $this->options['is_safe_callback']) {
|
81 |
+
return call_user_func($this->options['is_safe_callback'], $filterArgs);
|
82 |
+
}
|
83 |
+
}
|
84 |
+
|
85 |
+
public function getPreservesSafety()
|
86 |
+
{
|
87 |
+
return $this->options['preserves_safety'];
|
88 |
+
}
|
89 |
+
|
90 |
+
public function getPreEscape()
|
91 |
+
{
|
92 |
+
return $this->options['pre_escape'];
|
93 |
+
}
|
94 |
+
}
|
classes/Twig/SimpleFunction.php
CHANGED
@@ -1,84 +1,84 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2010-2012 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
/**
|
13 |
-
* Represents a template function.
|
14 |
-
*
|
15 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
16 |
-
*/
|
17 |
-
class Twig_SimpleFunction
|
18 |
-
{
|
19 |
-
protected $name;
|
20 |
-
protected $callable;
|
21 |
-
protected $options;
|
22 |
-
protected $arguments = array();
|
23 |
-
|
24 |
-
public function __construct($name, $callable, array $options = array())
|
25 |
-
{
|
26 |
-
$this->name = $name;
|
27 |
-
$this->callable = $callable;
|
28 |
-
$this->options = array_merge(array(
|
29 |
-
'needs_environment' => false,
|
30 |
-
'needs_context' => false,
|
31 |
-
'is_safe' => null,
|
32 |
-
'is_safe_callback' => null,
|
33 |
-
'node_class' => 'Twig_Node_Expression_Function',
|
34 |
-
), $options);
|
35 |
-
}
|
36 |
-
|
37 |
-
public function getName()
|
38 |
-
{
|
39 |
-
return $this->name;
|
40 |
-
}
|
41 |
-
|
42 |
-
public function getCallable()
|
43 |
-
{
|
44 |
-
return $this->callable;
|
45 |
-
}
|
46 |
-
|
47 |
-
public function getNodeClass()
|
48 |
-
{
|
49 |
-
return $this->options['node_class'];
|
50 |
-
}
|
51 |
-
|
52 |
-
public function setArguments($arguments)
|
53 |
-
{
|
54 |
-
$this->arguments = $arguments;
|
55 |
-
}
|
56 |
-
|
57 |
-
public function getArguments()
|
58 |
-
{
|
59 |
-
return $this->arguments;
|
60 |
-
}
|
61 |
-
|
62 |
-
public function needsEnvironment()
|
63 |
-
{
|
64 |
-
return $this->options['needs_environment'];
|
65 |
-
}
|
66 |
-
|
67 |
-
public function needsContext()
|
68 |
-
{
|
69 |
-
return $this->options['needs_context'];
|
70 |
-
}
|
71 |
-
|
72 |
-
public function getSafe(Twig_Node $functionArgs)
|
73 |
-
{
|
74 |
-
if (null !== $this->options['is_safe']) {
|
75 |
-
return $this->options['is_safe'];
|
76 |
-
}
|
77 |
-
|
78 |
-
if (null !== $this->options['is_safe_callback']) {
|
79 |
-
return call_user_func($this->options['is_safe_callback'], $functionArgs);
|
80 |
-
}
|
81 |
-
|
82 |
-
return array();
|
83 |
-
}
|
84 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2010-2012 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Represents a template function.
|
14 |
+
*
|
15 |
+
* @author Fabien Potencier <fabien@symfony.com>
|
16 |
+
*/
|
17 |
+
class Twig_SimpleFunction
|
18 |
+
{
|
19 |
+
protected $name;
|
20 |
+
protected $callable;
|
21 |
+
protected $options;
|
22 |
+
protected $arguments = array();
|
23 |
+
|
24 |
+
public function __construct($name, $callable, array $options = array())
|
25 |
+
{
|
26 |
+
$this->name = $name;
|
27 |
+
$this->callable = $callable;
|
28 |
+
$this->options = array_merge(array(
|
29 |
+
'needs_environment' => false,
|
30 |
+
'needs_context' => false,
|
31 |
+
'is_safe' => null,
|
32 |
+
'is_safe_callback' => null,
|
33 |
+
'node_class' => 'Twig_Node_Expression_Function',
|
34 |
+
), $options);
|
35 |
+
}
|
36 |
+
|
37 |
+
public function getName()
|
38 |
+
{
|
39 |
+
return $this->name;
|
40 |
+
}
|
41 |
+
|
42 |
+
public function getCallable()
|
43 |
+
{
|
44 |
+
return $this->callable;
|
45 |
+
}
|
46 |
+
|
47 |
+
public function getNodeClass()
|
48 |
+
{
|
49 |
+
return $this->options['node_class'];
|
50 |
+
}
|
51 |
+
|
52 |
+
public function setArguments($arguments)
|
53 |
+
{
|
54 |
+
$this->arguments = $arguments;
|
55 |
+
}
|
56 |
+
|
57 |
+
public function getArguments()
|
58 |
+
{
|
59 |
+
return $this->arguments;
|
60 |
+
}
|
61 |
+
|
62 |
+
public function needsEnvironment()
|
63 |
+
{
|
64 |
+
return $this->options['needs_environment'];
|
65 |
+
}
|
66 |
+
|
67 |
+
public function needsContext()
|
68 |
+
{
|
69 |
+
return $this->options['needs_context'];
|
70 |
+
}
|
71 |
+
|
72 |
+
public function getSafe(Twig_Node $functionArgs)
|
73 |
+
{
|
74 |
+
if (null !== $this->options['is_safe']) {
|
75 |
+
return $this->options['is_safe'];
|
76 |
+
}
|
77 |
+
|
78 |
+
if (null !== $this->options['is_safe_callback']) {
|
79 |
+
return call_user_func($this->options['is_safe_callback'], $functionArgs);
|
80 |
+
}
|
81 |
+
|
82 |
+
return array();
|
83 |
+
}
|
84 |
+
}
|
classes/Twig/SimpleTest.php
CHANGED
@@ -1,46 +1,46 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2010-2012 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
/**
|
13 |
-
* Represents a template test.
|
14 |
-
*
|
15 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
16 |
-
*/
|
17 |
-
class Twig_SimpleTest
|
18 |
-
{
|
19 |
-
protected $name;
|
20 |
-
protected $callable;
|
21 |
-
protected $options;
|
22 |
-
|
23 |
-
public function __construct($name, $callable, array $options = array())
|
24 |
-
{
|
25 |
-
$this->name = $name;
|
26 |
-
$this->callable = $callable;
|
27 |
-
$this->options = array_merge(array(
|
28 |
-
'node_class' => 'Twig_Node_Expression_Test',
|
29 |
-
), $options);
|
30 |
-
}
|
31 |
-
|
32 |
-
public function getName()
|
33 |
-
{
|
34 |
-
return $this->name;
|
35 |
-
}
|
36 |
-
|
37 |
-
public function getCallable()
|
38 |
-
{
|
39 |
-
return $this->callable;
|
40 |
-
}
|
41 |
-
|
42 |
-
public function getNodeClass()
|
43 |
-
{
|
44 |
-
return $this->options['node_class'];
|
45 |
-
}
|
46 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2010-2012 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Represents a template test.
|
14 |
+
*
|
15 |
+
* @author Fabien Potencier <fabien@symfony.com>
|
16 |
+
*/
|
17 |
+
class Twig_SimpleTest
|
18 |
+
{
|
19 |
+
protected $name;
|
20 |
+
protected $callable;
|
21 |
+
protected $options;
|
22 |
+
|
23 |
+
public function __construct($name, $callable, array $options = array())
|
24 |
+
{
|
25 |
+
$this->name = $name;
|
26 |
+
$this->callable = $callable;
|
27 |
+
$this->options = array_merge(array(
|
28 |
+
'node_class' => 'Twig_Node_Expression_Test',
|
29 |
+
), $options);
|
30 |
+
}
|
31 |
+
|
32 |
+
public function getName()
|
33 |
+
{
|
34 |
+
return $this->name;
|
35 |
+
}
|
36 |
+
|
37 |
+
public function getCallable()
|
38 |
+
{
|
39 |
+
return $this->callable;
|
40 |
+
}
|
41 |
+
|
42 |
+
public function getNodeClass()
|
43 |
+
{
|
44 |
+
return $this->options['node_class'];
|
45 |
+
}
|
46 |
+
}
|
classes/Twig/Template.php
CHANGED
@@ -1,485 +1,485 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2009 Fabien Potencier
|
7 |
-
* (c) 2009 Armin Ronacher
|
8 |
-
*
|
9 |
-
* For the full copyright and license information, please view the LICENSE
|
10 |
-
* file that was distributed with this source code.
|
11 |
-
*/
|
12 |
-
|
13 |
-
/**
|
14 |
-
* Default base class for compiled templates.
|
15 |
-
*
|
16 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
17 |
-
*/
|
18 |
-
abstract class Twig_Template implements Twig_TemplateInterface
|
19 |
-
{
|
20 |
-
protected static $cache = array();
|
21 |
-
|
22 |
-
protected $parent;
|
23 |
-
protected $parents;
|
24 |
-
protected $env;
|
25 |
-
protected $blocks;
|
26 |
-
protected $traits;
|
27 |
-
|
28 |
-
/**
|
29 |
-
* Constructor.
|
30 |
-
*
|
31 |
-
* @param Twig_Environment $env A Twig_Environment instance
|
32 |
-
*/
|
33 |
-
public function __construct(Twig_Environment $env)
|
34 |
-
{
|
35 |
-
$this->env = $env;
|
36 |
-
$this->blocks = array();
|
37 |
-
$this->traits = array();
|
38 |
-
}
|
39 |
-
|
40 |
-
/**
|
41 |
-
* Returns the template name.
|
42 |
-
*
|
43 |
-
* @return string The template name
|
44 |
-
*/
|
45 |
-
abstract public function getTemplateName();
|
46 |
-
|
47 |
-
/**
|
48 |
-
* {@inheritdoc}
|
49 |
-
*/
|
50 |
-
public function getEnvironment()
|
51 |
-
{
|
52 |
-
return $this->env;
|
53 |
-
}
|
54 |
-
|
55 |
-
/**
|
56 |
-
* Returns the parent template.
|
57 |
-
*
|
58 |
-
* This method is for internal use only and should never be called
|
59 |
-
* directly.
|
60 |
-
*
|
61 |
-
* @return Twig_TemplateInterface|false The parent template or false if there is no parent
|
62 |
-
*/
|
63 |
-
public function getParent(array $context)
|
64 |
-
{
|
65 |
-
if (null !== $this->parent) {
|
66 |
-
return $this->parent;
|
67 |
-
}
|
68 |
-
|
69 |
-
$parent = $this->doGetParent($context);
|
70 |
-
if (false === $parent) {
|
71 |
-
return false;
|
72 |
-
} elseif ($parent instanceof Twig_Template) {
|
73 |
-
$name = $parent->getTemplateName();
|
74 |
-
$this->parents[$name] = $parent;
|
75 |
-
$parent = $name;
|
76 |
-
} elseif (!isset($this->parents[$parent])) {
|
77 |
-
$this->parents[$parent] = $this->env->loadTemplate($parent);
|
78 |
-
}
|
79 |
-
|
80 |
-
return $this->parents[$parent];
|
81 |
-
}
|
82 |
-
|
83 |
-
protected function doGetParent(array $context)
|
84 |
-
{
|
85 |
-
return false;
|
86 |
-
}
|
87 |
-
|
88 |
-
public function isTraitable()
|
89 |
-
{
|
90 |
-
return true;
|
91 |
-
}
|
92 |
-
|
93 |
-
/**
|
94 |
-
* Displays a parent block.
|
95 |
-
*
|
96 |
-
* This method is for internal use only and should never be called
|
97 |
-
* directly.
|
98 |
-
*
|
99 |
-
* @param string $name The block name to display from the parent
|
100 |
-
* @param array $context The context
|
101 |
-
* @param array $blocks The current set of blocks
|
102 |
-
*/
|
103 |
-
public function displayParentBlock($name, array $context, array $blocks = array())
|
104 |
-
{
|
105 |
-
$name = (string) $name;
|
106 |
-
|
107 |
-
if (isset($this->traits[$name])) {
|
108 |
-
$this->traits[$name][0]->displayBlock($name, $context, $blocks, false);
|
109 |
-
} elseif (false !== $parent = $this->getParent($context)) {
|
110 |
-
$parent->displayBlock($name, $context, $blocks, false);
|
111 |
-
} else {
|
112 |
-
throw new Twig_Error_Runtime(sprintf('The template has no parent and no traits defining the "%s" block', $name), -1, $this->getTemplateName());
|
113 |
-
}
|
114 |
-
}
|
115 |
-
|
116 |
-
/**
|
117 |
-
* Displays a block.
|
118 |
-
*
|
119 |
-
* This method is for internal use only and should never be called
|
120 |
-
* directly.
|
121 |
-
*
|
122 |
-
* @param string $name The block name to display
|
123 |
-
* @param array $context The context
|
124 |
-
* @param array $blocks The current set of blocks
|
125 |
-
* @param bool $useBlocks Whether to use the current set of blocks
|
126 |
-
*/
|
127 |
-
public function displayBlock($name, array $context, array $blocks = array(), $useBlocks = true)
|
128 |
-
{
|
129 |
-
$name = (string) $name;
|
130 |
-
|
131 |
-
if ($useBlocks && isset($blocks[$name])) {
|
132 |
-
$template = $blocks[$name][0];
|
133 |
-
$block = $blocks[$name][1];
|
134 |
-
} elseif (isset($this->blocks[$name])) {
|
135 |
-
$template = $this->blocks[$name][0];
|
136 |
-
$block = $this->blocks[$name][1];
|
137 |
-
} else {
|
138 |
-
$template = null;
|
139 |
-
$block = null;
|
140 |
-
}
|
141 |
-
|
142 |
-
if (null !== $template) {
|
143 |
-
try {
|
144 |
-
$template->$block($context, $blocks);
|
145 |
-
} catch (Twig_Error $e) {
|
146 |
-
throw $e;
|
147 |
-
} catch (Exception $e) {
|
148 |
-
throw new Twig_Error_Runtime(sprintf('An exception has been thrown during the rendering of a template ("%s").', $e->getMessage()), -1, $template->getTemplateName(), $e);
|
149 |
-
}
|
150 |
-
} elseif (false !== $parent = $this->getParent($context)) {
|
151 |
-
$parent->displayBlock($name, $context, array_merge($this->blocks, $blocks), false);
|
152 |
-
}
|
153 |
-
}
|
154 |
-
|
155 |
-
/**
|
156 |
-
* Renders a parent block.
|
157 |
-
*
|
158 |
-
* This method is for internal use only and should never be called
|
159 |
-
* directly.
|
160 |
-
*
|
161 |
-
* @param string $name The block name to render from the parent
|
162 |
-
* @param array $context The context
|
163 |
-
* @param array $blocks The current set of blocks
|
164 |
-
*
|
165 |
-
* @return string The rendered block
|
166 |
-
*/
|
167 |
-
public function renderParentBlock($name, array $context, array $blocks = array())
|
168 |
-
{
|
169 |
-
ob_start();
|
170 |
-
$this->displayParentBlock($name, $context, $blocks);
|
171 |
-
|
172 |
-
return ob_get_clean();
|
173 |
-
}
|
174 |
-
|
175 |
-
/**
|
176 |
-
* Renders a block.
|
177 |
-
*
|
178 |
-
* This method is for internal use only and should never be called
|
179 |
-
* directly.
|
180 |
-
*
|
181 |
-
* @param string $name The block name to render
|
182 |
-
* @param array $context The context
|
183 |
-
* @param array $blocks The current set of blocks
|
184 |
-
* @param bool $useBlocks Whether to use the current set of blocks
|
185 |
-
*
|
186 |
-
* @return string The rendered block
|
187 |
-
*/
|
188 |
-
public function renderBlock($name, array $context, array $blocks = array(), $useBlocks = true)
|
189 |
-
{
|
190 |
-
ob_start();
|
191 |
-
$this->displayBlock($name, $context, $blocks, $useBlocks);
|
192 |
-
|
193 |
-
return ob_get_clean();
|
194 |
-
}
|
195 |
-
|
196 |
-
/**
|
197 |
-
* Returns whether a block exists or not.
|
198 |
-
*
|
199 |
-
* This method is for internal use only and should never be called
|
200 |
-
* directly.
|
201 |
-
*
|
202 |
-
* This method does only return blocks defined in the current template
|
203 |
-
* or defined in "used" traits.
|
204 |
-
*
|
205 |
-
* It does not return blocks from parent templates as the parent
|
206 |
-
* template name can be dynamic, which is only known based on the
|
207 |
-
* current context.
|
208 |
-
*
|
209 |
-
* @param string $name The block name
|
210 |
-
*
|
211 |
-
* @return bool true if the block exists, false otherwise
|
212 |
-
*/
|
213 |
-
public function hasBlock($name)
|
214 |
-
{
|
215 |
-
return isset($this->blocks[(string) $name]);
|
216 |
-
}
|
217 |
-
|
218 |
-
/**
|
219 |
-
* Returns all block names.
|
220 |
-
*
|
221 |
-
* This method is for internal use only and should never be called
|
222 |
-
* directly.
|
223 |
-
*
|
224 |
-
* @return array An array of block names
|
225 |
-
*
|
226 |
-
* @see hasBlock
|
227 |
-
*/
|
228 |
-
public function getBlockNames()
|
229 |
-
{
|
230 |
-
return array_keys($this->blocks);
|
231 |
-
}
|
232 |
-
|
233 |
-
/**
|
234 |
-
* Returns all blocks.
|
235 |
-
*
|
236 |
-
* This method is for internal use only and should never be called
|
237 |
-
* directly.
|
238 |
-
*
|
239 |
-
* @return array An array of blocks
|
240 |
-
*
|
241 |
-
* @see hasBlock
|
242 |
-
*/
|
243 |
-
public function getBlocks()
|
244 |
-
{
|
245 |
-
return $this->blocks;
|
246 |
-
}
|
247 |
-
|
248 |
-
/**
|
249 |
-
* {@inheritdoc}
|
250 |
-
*/
|
251 |
-
public function display(array $context, array $blocks = array())
|
252 |
-
{
|
253 |
-
$this->displayWithErrorHandling($this->env->mergeGlobals($context), array_merge($this->blocks, $blocks));
|
254 |
-
}
|
255 |
-
|
256 |
-
/**
|
257 |
-
* {@inheritdoc}
|
258 |
-
*/
|
259 |
-
public function render(array $context)
|
260 |
-
{
|
261 |
-
$level = ob_get_level();
|
262 |
-
ob_start();
|
263 |
-
try {
|
264 |
-
$this->display($context);
|
265 |
-
} catch (Exception $e) {
|
266 |
-
while (ob_get_level() > $level) {
|
267 |
-
ob_end_clean();
|
268 |
-
}
|
269 |
-
|
270 |
-
throw $e;
|
271 |
-
}
|
272 |
-
|
273 |
-
return ob_get_clean();
|
274 |
-
}
|
275 |
-
|
276 |
-
protected function displayWithErrorHandling(array $context, array $blocks = array())
|
277 |
-
{
|
278 |
-
try {
|
279 |
-
$this->doDisplay($context, $blocks);
|
280 |
-
} catch (Twig_Error $e) {
|
281 |
-
if (!$e->getTemplateFile()) {
|
282 |
-
$e->setTemplateFile($this->getTemplateName());
|
283 |
-
}
|
284 |
-
|
285 |
-
// this is mostly useful for Twig_Error_Loader exceptions
|
286 |
-
// see Twig_Error_Loader
|
287 |
-
if (false === $e->getTemplateLine()) {
|
288 |
-
$e->setTemplateLine(-1);
|
289 |
-
$e->guess();
|
290 |
-
}
|
291 |
-
|
292 |
-
throw $e;
|
293 |
-
} catch (Exception $e) {
|
294 |
-
throw new Twig_Error_Runtime(sprintf('An exception has been thrown during the rendering of a template ("%s").', $e->getMessage()), -1, $this->getTemplateName(), $e);
|
295 |
-
}
|
296 |
-
}
|
297 |
-
|
298 |
-
/**
|
299 |
-
* Auto-generated method to display the template with the given context.
|
300 |
-
*
|
301 |
-
* @param array $context An array of parameters to pass to the template
|
302 |
-
* @param array $blocks An array of blocks to pass to the template
|
303 |
-
*/
|
304 |
-
abstract protected function doDisplay(array $context, array $blocks = array());
|
305 |
-
|
306 |
-
/**
|
307 |
-
* Returns a variable from the context.
|
308 |
-
*
|
309 |
-
* This method is for internal use only and should never be called
|
310 |
-
* directly.
|
311 |
-
*
|
312 |
-
* This method should not be overridden in a sub-class as this is an
|
313 |
-
* implementation detail that has been introduced to optimize variable
|
314 |
-
* access for versions of PHP before 5.4. This is not a way to override
|
315 |
-
* the way to get a variable value.
|
316 |
-
*
|
317 |
-
* @param array $context The context
|
318 |
-
* @param string $item The variable to return from the context
|
319 |
-
* @param bool $ignoreStrictCheck Whether to ignore the strict variable check or not
|
320 |
-
*
|
321 |
-
* @return The content of the context variable
|
322 |
-
*
|
323 |
-
* @throws Twig_Error_Runtime if the variable does not exist and Twig is running in strict mode
|
324 |
-
*/
|
325 |
-
final protected function getContext($context, $item, $ignoreStrictCheck = false)
|
326 |
-
{
|
327 |
-
if (!array_key_exists($item, $context)) {
|
328 |
-
if ($ignoreStrictCheck || !$this->env->isStrictVariables()) {
|
329 |
-
return;
|
330 |
-
}
|
331 |
-
|
332 |
-
throw new Twig_Error_Runtime(sprintf('Variable "%s" does not exist', $item), -1, $this->getTemplateName());
|
333 |
-
}
|
334 |
-
|
335 |
-
return $context[$item];
|
336 |
-
}
|
337 |
-
|
338 |
-
/**
|
339 |
-
* Returns the attribute value for a given array/object.
|
340 |
-
*
|
341 |
-
* @param mixed $object The object or array from where to get the item
|
342 |
-
* @param mixed $item The item to get from the array or object
|
343 |
-
* @param array $arguments An array of arguments to pass if the item is an object method
|
344 |
-
* @param string $type The type of attribute (@see Twig_Template constants)
|
345 |
-
* @param bool $isDefinedTest Whether this is only a defined check
|
346 |
-
* @param bool $ignoreStrictCheck Whether to ignore the strict attribute check or not
|
347 |
-
*
|
348 |
-
* @return mixed The attribute value, or a Boolean when $isDefinedTest is true, or null when the attribute is not set and $ignoreStrictCheck is true
|
349 |
-
*
|
350 |
-
* @throws Twig_Error_Runtime if the attribute does not exist and Twig is running in strict mode and $isDefinedTest is false
|
351 |
-
*/
|
352 |
-
protected function getAttribute($object, $item, array $arguments = array(), $type = Twig_Template::ANY_CALL, $isDefinedTest = false, $ignoreStrictCheck = false)
|
353 |
-
{
|
354 |
-
// array
|
355 |
-
if (Twig_Template::METHOD_CALL !== $type) {
|
356 |
-
$arrayItem = is_bool($item) || is_float($item) ? (int) $item : $item;
|
357 |
-
|
358 |
-
if ((is_array($object) && array_key_exists($arrayItem, $object))
|
359 |
-
|| ($object instanceof ArrayAccess && isset($object[$arrayItem]))
|
360 |
-
) {
|
361 |
-
if ($isDefinedTest) {
|
362 |
-
return true;
|
363 |
-
}
|
364 |
-
|
365 |
-
return $object[$arrayItem];
|
366 |
-
}
|
367 |
-
|
368 |
-
if (Twig_Template::ARRAY_CALL === $type || !is_object($object)) {
|
369 |
-
if ($isDefinedTest) {
|
370 |
-
return false;
|
371 |
-
}
|
372 |
-
|
373 |
-
if ($ignoreStrictCheck || !$this->env->isStrictVariables()) {
|
374 |
-
return;
|
375 |
-
}
|
376 |
-
|
377 |
-
if ($object instanceof ArrayAccess) {
|
378 |
-
$message = sprintf('Key "%s" in object with ArrayAccess of class "%s" does not exist', $arrayItem, get_class($object));
|
379 |
-
} elseif (is_object($object)) {
|
380 |
-
$message = sprintf('Impossible to access a key "%s" on an object of class "%s" that does not implement ArrayAccess interface', $item, get_class($object));
|
381 |
-
} elseif (is_array($object)) {
|
382 |
-
$message = sprintf('Key "%s" for array with keys "%s" does not exist', $arrayItem, implode(', ', array_keys($object)));
|
383 |
-
} elseif (Twig_Template::ARRAY_CALL === $type) {
|
384 |
-
$message = sprintf('Impossible to access a key ("%s") on a %s variable ("%s")', $item, gettype($object), $object);
|
385 |
-
} else {
|
386 |
-
$message = sprintf('Impossible to access an attribute ("%s") on a %s variable ("%s")', $item, gettype($object), $object);
|
387 |
-
}
|
388 |
-
|
389 |
-
throw new Twig_Error_Runtime($message, -1, $this->getTemplateName());
|
390 |
-
}
|
391 |
-
}
|
392 |
-
|
393 |
-
if (!is_object($object)) {
|
394 |
-
if ($isDefinedTest) {
|
395 |
-
return false;
|
396 |
-
}
|
397 |
-
|
398 |
-
if ($ignoreStrictCheck || !$this->env->isStrictVariables()) {
|
399 |
-
return;
|
400 |
-
}
|
401 |
-
|
402 |
-
throw new Twig_Error_Runtime(sprintf('Impossible to invoke a method ("%s") on a %s variable ("%s")', $item, gettype($object), $object), -1, $this->getTemplateName());
|
403 |
-
}
|
404 |
-
|
405 |
-
// object property
|
406 |
-
if (Twig_Template::METHOD_CALL !== $type) {
|
407 |
-
if (isset($object->$item) || array_key_exists((string) $item, $object)) {
|
408 |
-
if ($isDefinedTest) {
|
409 |
-
return true;
|
410 |
-
}
|
411 |
-
|
412 |
-
if ($this->env->hasExtension('sandbox')) {
|
413 |
-
$this->env->getExtension('sandbox')->checkPropertyAllowed($object, $item);
|
414 |
-
}
|
415 |
-
|
416 |
-
return $object->$item;
|
417 |
-
}
|
418 |
-
}
|
419 |
-
|
420 |
-
$class = get_class($object);
|
421 |
-
|
422 |
-
// object method
|
423 |
-
if (!isset(self::$cache[$class]['methods'])) {
|
424 |
-
self::$cache[$class]['methods'] = array_change_key_case(array_flip(get_class_methods($object)));
|
425 |
-
}
|
426 |
-
|
427 |
-
$call = false;
|
428 |
-
$lcItem = strtolower($item);
|
429 |
-
if (isset(self::$cache[$class]['methods'][$lcItem])) {
|
430 |
-
$method = (string) $item;
|
431 |
-
} elseif (isset(self::$cache[$class]['methods']['get'.$lcItem])) {
|
432 |
-
$method = 'get'.$item;
|
433 |
-
} elseif (isset(self::$cache[$class]['methods']['is'.$lcItem])) {
|
434 |
-
$method = 'is'.$item;
|
435 |
-
} elseif (isset(self::$cache[$class]['methods']['__call'])) {
|
436 |
-
$method = (string) $item;
|
437 |
-
$call = true;
|
438 |
-
} else {
|
439 |
-
if ($isDefinedTest) {
|
440 |
-
return false;
|
441 |
-
}
|
442 |
-
|
443 |
-
if ($ignoreStrictCheck || !$this->env->isStrictVariables()) {
|
444 |
-
return;
|
445 |
-
}
|
446 |
-
|
447 |
-
throw new Twig_Error_Runtime(sprintf('Method "%s" for object "%s" does not exist', $item, get_class($object)), -1, $this->getTemplateName());
|
448 |
-
}
|
449 |
-
|
450 |
-
if ($isDefinedTest) {
|
451 |
-
return true;
|
452 |
-
}
|
453 |
-
|
454 |
-
if ($this->env->hasExtension('sandbox')) {
|
455 |
-
$this->env->getExtension('sandbox')->checkMethodAllowed($object, $method);
|
456 |
-
}
|
457 |
-
|
458 |
-
// Some objects throw exceptions when they have __call, and the method we try
|
459 |
-
// to call is not supported. If ignoreStrictCheck is true, we should return null.
|
460 |
-
try {
|
461 |
-
$ret = call_user_func_array(array($object, $method), $arguments);
|
462 |
-
} catch (BadMethodCallException $e) {
|
463 |
-
if ($call && ($ignoreStrictCheck || !$this->env->isStrictVariables())) {
|
464 |
-
return;
|
465 |
-
}
|
466 |
-
throw $e;
|
467 |
-
}
|
468 |
-
|
469 |
-
// useful when calling a template method from a template
|
470 |
-
// this is not supported but unfortunately heavily used in the Symfony profiler
|
471 |
-
if ($object instanceof Twig_TemplateInterface) {
|
472 |
-
return $ret === '' ? '' : new Twig_Markup($ret, $this->env->getCharset());
|
473 |
-
}
|
474 |
-
|
475 |
-
return $ret;
|
476 |
-
}
|
477 |
-
|
478 |
-
/**
|
479 |
-
* This method is only useful when testing Twig. Do not use it.
|
480 |
-
*/
|
481 |
-
public static function clearCache()
|
482 |
-
{
|
483 |
-
self::$cache = array();
|
484 |
-
}
|
485 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2009 Fabien Potencier
|
7 |
+
* (c) 2009 Armin Ronacher
|
8 |
+
*
|
9 |
+
* For the full copyright and license information, please view the LICENSE
|
10 |
+
* file that was distributed with this source code.
|
11 |
+
*/
|
12 |
+
|
13 |
+
/**
|
14 |
+
* Default base class for compiled templates.
|
15 |
+
*
|
16 |
+
* @author Fabien Potencier <fabien@symfony.com>
|
17 |
+
*/
|
18 |
+
abstract class Twig_Template implements Twig_TemplateInterface
|
19 |
+
{
|
20 |
+
protected static $cache = array();
|
21 |
+
|
22 |
+
protected $parent;
|
23 |
+
protected $parents;
|
24 |
+
protected $env;
|
25 |
+
protected $blocks;
|
26 |
+
protected $traits;
|
27 |
+
|
28 |
+
/**
|
29 |
+
* Constructor.
|
30 |
+
*
|
31 |
+
* @param Twig_Environment $env A Twig_Environment instance
|
32 |
+
*/
|
33 |
+
public function __construct(Twig_Environment $env)
|
34 |
+
{
|
35 |
+
$this->env = $env;
|
36 |
+
$this->blocks = array();
|
37 |
+
$this->traits = array();
|
38 |
+
}
|
39 |
+
|
40 |
+
/**
|
41 |
+
* Returns the template name.
|
42 |
+
*
|
43 |
+
* @return string The template name
|
44 |
+
*/
|
45 |
+
abstract public function getTemplateName();
|
46 |
+
|
47 |
+
/**
|
48 |
+
* {@inheritdoc}
|
49 |
+
*/
|
50 |
+
public function getEnvironment()
|
51 |
+
{
|
52 |
+
return $this->env;
|
53 |
+
}
|
54 |
+
|
55 |
+
/**
|
56 |
+
* Returns the parent template.
|
57 |
+
*
|
58 |
+
* This method is for internal use only and should never be called
|
59 |
+
* directly.
|
60 |
+
*
|
61 |
+
* @return Twig_TemplateInterface|false The parent template or false if there is no parent
|
62 |
+
*/
|
63 |
+
public function getParent(array $context)
|
64 |
+
{
|
65 |
+
if (null !== $this->parent) {
|
66 |
+
return $this->parent;
|
67 |
+
}
|
68 |
+
|
69 |
+
$parent = $this->doGetParent($context);
|
70 |
+
if (false === $parent) {
|
71 |
+
return false;
|
72 |
+
} elseif ($parent instanceof Twig_Template) {
|
73 |
+
$name = $parent->getTemplateName();
|
74 |
+
$this->parents[$name] = $parent;
|
75 |
+
$parent = $name;
|
76 |
+
} elseif (!isset($this->parents[$parent])) {
|
77 |
+
$this->parents[$parent] = $this->env->loadTemplate($parent);
|
78 |
+
}
|
79 |
+
|
80 |
+
return $this->parents[$parent];
|
81 |
+
}
|
82 |
+
|
83 |
+
protected function doGetParent(array $context)
|
84 |
+
{
|
85 |
+
return false;
|
86 |
+
}
|
87 |
+
|
88 |
+
public function isTraitable()
|
89 |
+
{
|
90 |
+
return true;
|
91 |
+
}
|
92 |
+
|
93 |
+
/**
|
94 |
+
* Displays a parent block.
|
95 |
+
*
|
96 |
+
* This method is for internal use only and should never be called
|
97 |
+
* directly.
|
98 |
+
*
|
99 |
+
* @param string $name The block name to display from the parent
|
100 |
+
* @param array $context The context
|
101 |
+
* @param array $blocks The current set of blocks
|
102 |
+
*/
|
103 |
+
public function displayParentBlock($name, array $context, array $blocks = array())
|
104 |
+
{
|
105 |
+
$name = (string) $name;
|
106 |
+
|
107 |
+
if (isset($this->traits[$name])) {
|
108 |
+
$this->traits[$name][0]->displayBlock($name, $context, $blocks, false);
|
109 |
+
} elseif (false !== $parent = $this->getParent($context)) {
|
110 |
+
$parent->displayBlock($name, $context, $blocks, false);
|
111 |
+
} else {
|
112 |
+
throw new Twig_Error_Runtime(sprintf('The template has no parent and no traits defining the "%s" block', $name), -1, $this->getTemplateName());
|
113 |
+
}
|
114 |
+
}
|
115 |
+
|
116 |
+
/**
|
117 |
+
* Displays a block.
|
118 |
+
*
|
119 |
+
* This method is for internal use only and should never be called
|
120 |
+
* directly.
|
121 |
+
*
|
122 |
+
* @param string $name The block name to display
|
123 |
+
* @param array $context The context
|
124 |
+
* @param array $blocks The current set of blocks
|
125 |
+
* @param bool $useBlocks Whether to use the current set of blocks
|
126 |
+
*/
|
127 |
+
public function displayBlock($name, array $context, array $blocks = array(), $useBlocks = true)
|
128 |
+
{
|
129 |
+
$name = (string) $name;
|
130 |
+
|
131 |
+
if ($useBlocks && isset($blocks[$name])) {
|
132 |
+
$template = $blocks[$name][0];
|
133 |
+
$block = $blocks[$name][1];
|
134 |
+
} elseif (isset($this->blocks[$name])) {
|
135 |
+
$template = $this->blocks[$name][0];
|
136 |
+
$block = $this->blocks[$name][1];
|
137 |
+
} else {
|
138 |
+
$template = null;
|
139 |
+
$block = null;
|
140 |
+
}
|
141 |
+
|
142 |
+
if (null !== $template) {
|
143 |
+
try {
|
144 |
+
$template->$block($context, $blocks);
|
145 |
+
} catch (Twig_Error $e) {
|
146 |
+
throw $e;
|
147 |
+
} catch (Exception $e) {
|
148 |
+
throw new Twig_Error_Runtime(sprintf('An exception has been thrown during the rendering of a template ("%s").', $e->getMessage()), -1, $template->getTemplateName(), $e);
|
149 |
+
}
|
150 |
+
} elseif (false !== $parent = $this->getParent($context)) {
|
151 |
+
$parent->displayBlock($name, $context, array_merge($this->blocks, $blocks), false);
|
152 |
+
}
|
153 |
+
}
|
154 |
+
|
155 |
+
/**
|
156 |
+
* Renders a parent block.
|
157 |
+
*
|
158 |
+
* This method is for internal use only and should never be called
|
159 |
+
* directly.
|
160 |
+
*
|
161 |
+
* @param string $name The block name to render from the parent
|
162 |
+
* @param array $context The context
|
163 |
+
* @param array $blocks The current set of blocks
|
164 |
+
*
|
165 |
+
* @return string The rendered block
|
166 |
+
*/
|
167 |
+
public function renderParentBlock($name, array $context, array $blocks = array())
|
168 |
+
{
|
169 |
+
ob_start();
|
170 |
+
$this->displayParentBlock($name, $context, $blocks);
|
171 |
+
|
172 |
+
return ob_get_clean();
|
173 |
+
}
|
174 |
+
|
175 |
+
/**
|
176 |
+
* Renders a block.
|
177 |
+
*
|
178 |
+
* This method is for internal use only and should never be called
|
179 |
+
* directly.
|
180 |
+
*
|
181 |
+
* @param string $name The block name to render
|
182 |
+
* @param array $context The context
|
183 |
+
* @param array $blocks The current set of blocks
|
184 |
+
* @param bool $useBlocks Whether to use the current set of blocks
|
185 |
+
*
|
186 |
+
* @return string The rendered block
|
187 |
+
*/
|
188 |
+
public function renderBlock($name, array $context, array $blocks = array(), $useBlocks = true)
|
189 |
+
{
|
190 |
+
ob_start();
|
191 |
+
$this->displayBlock($name, $context, $blocks, $useBlocks);
|
192 |
+
|
193 |
+
return ob_get_clean();
|
194 |
+
}
|
195 |
+
|
196 |
+
/**
|
197 |
+
* Returns whether a block exists or not.
|
198 |
+
*
|
199 |
+
* This method is for internal use only and should never be called
|
200 |
+
* directly.
|
201 |
+
*
|
202 |
+
* This method does only return blocks defined in the current template
|
203 |
+
* or defined in "used" traits.
|
204 |
+
*
|
205 |
+
* It does not return blocks from parent templates as the parent
|
206 |
+
* template name can be dynamic, which is only known based on the
|
207 |
+
* current context.
|
208 |
+
*
|
209 |
+
* @param string $name The block name
|
210 |
+
*
|
211 |
+
* @return bool true if the block exists, false otherwise
|
212 |
+
*/
|
213 |
+
public function hasBlock($name)
|
214 |
+
{
|
215 |
+
return isset($this->blocks[(string) $name]);
|
216 |
+
}
|
217 |
+
|
218 |
+
/**
|
219 |
+
* Returns all block names.
|
220 |
+
*
|
221 |
+
* This method is for internal use only and should never be called
|
222 |
+
* directly.
|
223 |
+
*
|
224 |
+
* @return array An array of block names
|
225 |
+
*
|
226 |
+
* @see hasBlock
|
227 |
+
*/
|
228 |
+
public function getBlockNames()
|
229 |
+
{
|
230 |
+
return array_keys($this->blocks);
|
231 |
+
}
|
232 |
+
|
233 |
+
/**
|
234 |
+
* Returns all blocks.
|
235 |
+
*
|
236 |
+
* This method is for internal use only and should never be called
|
237 |
+
* directly.
|
238 |
+
*
|
239 |
+
* @return array An array of blocks
|
240 |
+
*
|
241 |
+
* @see hasBlock
|
242 |
+
*/
|
243 |
+
public function getBlocks()
|
244 |
+
{
|
245 |
+
return $this->blocks;
|
246 |
+
}
|
247 |
+
|
248 |
+
/**
|
249 |
+
* {@inheritdoc}
|
250 |
+
*/
|
251 |
+
public function display(array $context, array $blocks = array())
|
252 |
+
{
|
253 |
+
$this->displayWithErrorHandling($this->env->mergeGlobals($context), array_merge($this->blocks, $blocks));
|
254 |
+
}
|
255 |
+
|
256 |
+
/**
|
257 |
+
* {@inheritdoc}
|
258 |
+
*/
|
259 |
+
public function render(array $context)
|
260 |
+
{
|
261 |
+
$level = ob_get_level();
|
262 |
+
ob_start();
|
263 |
+
try {
|
264 |
+
$this->display($context);
|
265 |
+
} catch (Exception $e) {
|
266 |
+
while (ob_get_level() > $level) {
|
267 |
+
ob_end_clean();
|
268 |
+
}
|
269 |
+
|
270 |
+
throw $e;
|
271 |
+
}
|
272 |
+
|
273 |
+
return ob_get_clean();
|
274 |
+
}
|
275 |
+
|
276 |
+
protected function displayWithErrorHandling(array $context, array $blocks = array())
|
277 |
+
{
|
278 |
+
try {
|
279 |
+
$this->doDisplay($context, $blocks);
|
280 |
+
} catch (Twig_Error $e) {
|
281 |
+
if (!$e->getTemplateFile()) {
|
282 |
+
$e->setTemplateFile($this->getTemplateName());
|
283 |
+
}
|
284 |
+
|
285 |
+
// this is mostly useful for Twig_Error_Loader exceptions
|
286 |
+
// see Twig_Error_Loader
|
287 |
+
if (false === $e->getTemplateLine()) {
|
288 |
+
$e->setTemplateLine(-1);
|
289 |
+
$e->guess();
|
290 |
+
}
|
291 |
+
|
292 |
+
throw $e;
|
293 |
+
} catch (Exception $e) {
|
294 |
+
throw new Twig_Error_Runtime(sprintf('An exception has been thrown during the rendering of a template ("%s").', $e->getMessage()), -1, $this->getTemplateName(), $e);
|
295 |
+
}
|
296 |
+
}
|
297 |
+
|
298 |
+
/**
|
299 |
+
* Auto-generated method to display the template with the given context.
|
300 |
+
*
|
301 |
+
* @param array $context An array of parameters to pass to the template
|
302 |
+
* @param array $blocks An array of blocks to pass to the template
|
303 |
+
*/
|
304 |
+
abstract protected function doDisplay(array $context, array $blocks = array());
|
305 |
+
|
306 |
+
/**
|
307 |
+
* Returns a variable from the context.
|
308 |
+
*
|
309 |
+
* This method is for internal use only and should never be called
|
310 |
+
* directly.
|
311 |
+
*
|
312 |
+
* This method should not be overridden in a sub-class as this is an
|
313 |
+
* implementation detail that has been introduced to optimize variable
|
314 |
+
* access for versions of PHP before 5.4. This is not a way to override
|
315 |
+
* the way to get a variable value.
|
316 |
+
*
|
317 |
+
* @param array $context The context
|
318 |
+
* @param string $item The variable to return from the context
|
319 |
+
* @param bool $ignoreStrictCheck Whether to ignore the strict variable check or not
|
320 |
+
*
|
321 |
+
* @return The content of the context variable
|
322 |
+
*
|
323 |
+
* @throws Twig_Error_Runtime if the variable does not exist and Twig is running in strict mode
|
324 |
+
*/
|
325 |
+
final protected function getContext($context, $item, $ignoreStrictCheck = false)
|
326 |
+
{
|
327 |
+
if (!array_key_exists($item, $context)) {
|
328 |
+
if ($ignoreStrictCheck || !$this->env->isStrictVariables()) {
|
329 |
+
return;
|
330 |
+
}
|
331 |
+
|
332 |
+
throw new Twig_Error_Runtime(sprintf('Variable "%s" does not exist', $item), -1, $this->getTemplateName());
|
333 |
+
}
|
334 |
+
|
335 |
+
return $context[$item];
|
336 |
+
}
|
337 |
+
|
338 |
+
/**
|
339 |
+
* Returns the attribute value for a given array/object.
|
340 |
+
*
|
341 |
+
* @param mixed $object The object or array from where to get the item
|
342 |
+
* @param mixed $item The item to get from the array or object
|
343 |
+
* @param array $arguments An array of arguments to pass if the item is an object method
|
344 |
+
* @param string $type The type of attribute (@see Twig_Template constants)
|
345 |
+
* @param bool $isDefinedTest Whether this is only a defined check
|
346 |
+
* @param bool $ignoreStrictCheck Whether to ignore the strict attribute check or not
|
347 |
+
*
|
348 |
+
* @return mixed The attribute value, or a Boolean when $isDefinedTest is true, or null when the attribute is not set and $ignoreStrictCheck is true
|
349 |
+
*
|
350 |
+
* @throws Twig_Error_Runtime if the attribute does not exist and Twig is running in strict mode and $isDefinedTest is false
|
351 |
+
*/
|
352 |
+
protected function getAttribute($object, $item, array $arguments = array(), $type = Twig_Template::ANY_CALL, $isDefinedTest = false, $ignoreStrictCheck = false)
|
353 |
+
{
|
354 |
+
// array
|
355 |
+
if (Twig_Template::METHOD_CALL !== $type) {
|
356 |
+
$arrayItem = is_bool($item) || is_float($item) ? (int) $item : $item;
|
357 |
+
|
358 |
+
if ((is_array($object) && array_key_exists($arrayItem, $object))
|
359 |
+
|| ($object instanceof ArrayAccess && isset($object[$arrayItem]))
|
360 |
+
) {
|
361 |
+
if ($isDefinedTest) {
|
362 |
+
return true;
|
363 |
+
}
|
364 |
+
|
365 |
+
return $object[$arrayItem];
|
366 |
+
}
|
367 |
+
|
368 |
+
if (Twig_Template::ARRAY_CALL === $type || !is_object($object)) {
|
369 |
+
if ($isDefinedTest) {
|
370 |
+
return false;
|
371 |
+
}
|
372 |
+
|
373 |
+
if ($ignoreStrictCheck || !$this->env->isStrictVariables()) {
|
374 |
+
return;
|
375 |
+
}
|
376 |
+
|
377 |
+
if ($object instanceof ArrayAccess) {
|
378 |
+
$message = sprintf('Key "%s" in object with ArrayAccess of class "%s" does not exist', $arrayItem, get_class($object));
|
379 |
+
} elseif (is_object($object)) {
|
380 |
+
$message = sprintf('Impossible to access a key "%s" on an object of class "%s" that does not implement ArrayAccess interface', $item, get_class($object));
|
381 |
+
} elseif (is_array($object)) {
|
382 |
+
$message = sprintf('Key "%s" for array with keys "%s" does not exist', $arrayItem, implode(', ', array_keys($object)));
|
383 |
+
} elseif (Twig_Template::ARRAY_CALL === $type) {
|
384 |
+
$message = sprintf('Impossible to access a key ("%s") on a %s variable ("%s")', $item, gettype($object), $object);
|
385 |
+
} else {
|
386 |
+
$message = sprintf('Impossible to access an attribute ("%s") on a %s variable ("%s")', $item, gettype($object), $object);
|
387 |
+
}
|
388 |
+
|
389 |
+
throw new Twig_Error_Runtime($message, -1, $this->getTemplateName());
|
390 |
+
}
|
391 |
+
}
|
392 |
+
|
393 |
+
if (!is_object($object)) {
|
394 |
+
if ($isDefinedTest) {
|
395 |
+
return false;
|
396 |
+
}
|
397 |
+
|
398 |
+
if ($ignoreStrictCheck || !$this->env->isStrictVariables()) {
|
399 |
+
return;
|
400 |
+
}
|
401 |
+
|
402 |
+
throw new Twig_Error_Runtime(sprintf('Impossible to invoke a method ("%s") on a %s variable ("%s")', $item, gettype($object), $object), -1, $this->getTemplateName());
|
403 |
+
}
|
404 |
+
|
405 |
+
// object property
|
406 |
+
if (Twig_Template::METHOD_CALL !== $type) {
|
407 |
+
if (isset($object->$item) || array_key_exists((string) $item, $object)) {
|
408 |
+
if ($isDefinedTest) {
|
409 |
+
return true;
|
410 |
+
}
|
411 |
+
|
412 |
+
if ($this->env->hasExtension('sandbox')) {
|
413 |
+
$this->env->getExtension('sandbox')->checkPropertyAllowed($object, $item);
|
414 |
+
}
|
415 |
+
|
416 |
+
return $object->$item;
|
417 |
+
}
|
418 |
+
}
|
419 |
+
|
420 |
+
$class = get_class($object);
|
421 |
+
|
422 |
+
// object method
|
423 |
+
if (!isset(self::$cache[$class]['methods'])) {
|
424 |
+
self::$cache[$class]['methods'] = array_change_key_case(array_flip(get_class_methods($object)));
|
425 |
+
}
|
426 |
+
|
427 |
+
$call = false;
|
428 |
+
$lcItem = strtolower($item);
|
429 |
+
if (isset(self::$cache[$class]['methods'][$lcItem])) {
|
430 |
+
$method = (string) $item;
|
431 |
+
} elseif (isset(self::$cache[$class]['methods']['get'.$lcItem])) {
|
432 |
+
$method = 'get'.$item;
|
433 |
+
} elseif (isset(self::$cache[$class]['methods']['is'.$lcItem])) {
|
434 |
+
$method = 'is'.$item;
|
435 |
+
} elseif (isset(self::$cache[$class]['methods']['__call'])) {
|
436 |
+
$method = (string) $item;
|
437 |
+
$call = true;
|
438 |
+
} else {
|
439 |
+
if ($isDefinedTest) {
|
440 |
+
return false;
|
441 |
+
}
|
442 |
+
|
443 |
+
if ($ignoreStrictCheck || !$this->env->isStrictVariables()) {
|
444 |
+
return;
|
445 |
+
}
|
446 |
+
|
447 |
+
throw new Twig_Error_Runtime(sprintf('Method "%s" for object "%s" does not exist', $item, get_class($object)), -1, $this->getTemplateName());
|
448 |
+
}
|
449 |
+
|
450 |
+
if ($isDefinedTest) {
|
451 |
+
return true;
|
452 |
+
}
|
453 |
+
|
454 |
+
if ($this->env->hasExtension('sandbox')) {
|
455 |
+
$this->env->getExtension('sandbox')->checkMethodAllowed($object, $method);
|
456 |
+
}
|
457 |
+
|
458 |
+
// Some objects throw exceptions when they have __call, and the method we try
|
459 |
+
// to call is not supported. If ignoreStrictCheck is true, we should return null.
|
460 |
+
try {
|
461 |
+
$ret = call_user_func_array(array($object, $method), $arguments);
|
462 |
+
} catch (BadMethodCallException $e) {
|
463 |
+
if ($call && ($ignoreStrictCheck || !$this->env->isStrictVariables())) {
|
464 |
+
return;
|
465 |
+
}
|
466 |
+
throw $e;
|
467 |
+
}
|
468 |
+
|
469 |
+
// useful when calling a template method from a template
|
470 |
+
// this is not supported but unfortunately heavily used in the Symfony profiler
|
471 |
+
if ($object instanceof Twig_TemplateInterface) {
|
472 |
+
return $ret === '' ? '' : new Twig_Markup($ret, $this->env->getCharset());
|
473 |
+
}
|
474 |
+
|
475 |
+
return $ret;
|
476 |
+
}
|
477 |
+
|
478 |
+
/**
|
479 |
+
* This method is only useful when testing Twig. Do not use it.
|
480 |
+
*/
|
481 |
+
public static function clearCache()
|
482 |
+
{
|
483 |
+
self::$cache = array();
|
484 |
+
}
|
485 |
+
}
|
classes/Twig/TemplateInterface.php
CHANGED
@@ -1,48 +1,48 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2009 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
/**
|
13 |
-
* Interface implemented by all compiled templates.
|
14 |
-
*
|
15 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
16 |
-
*
|
17 |
-
* @deprecated since 1.12 (to be removed in 3.0)
|
18 |
-
*/
|
19 |
-
interface Twig_TemplateInterface
|
20 |
-
{
|
21 |
-
const ANY_CALL = 'any';
|
22 |
-
const ARRAY_CALL = 'array';
|
23 |
-
const METHOD_CALL = 'method';
|
24 |
-
|
25 |
-
/**
|
26 |
-
* Renders the template with the given context and returns it as string.
|
27 |
-
*
|
28 |
-
* @param array $context An array of parameters to pass to the template
|
29 |
-
*
|
30 |
-
* @return string The rendered template
|
31 |
-
*/
|
32 |
-
public function render(array $context);
|
33 |
-
|
34 |
-
/**
|
35 |
-
* Displays the template with the given context.
|
36 |
-
*
|
37 |
-
* @param array $context An array of parameters to pass to the template
|
38 |
-
* @param array $blocks An array of blocks to pass to the template
|
39 |
-
*/
|
40 |
-
public function display(array $context, array $blocks = array());
|
41 |
-
|
42 |
-
/**
|
43 |
-
* Returns the bound environment for this template.
|
44 |
-
*
|
45 |
-
* @return Twig_Environment The current environment
|
46 |
-
*/
|
47 |
-
public function getEnvironment();
|
48 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2009 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Interface implemented by all compiled templates.
|
14 |
+
*
|
15 |
+
* @author Fabien Potencier <fabien@symfony.com>
|
16 |
+
*
|
17 |
+
* @deprecated since 1.12 (to be removed in 3.0)
|
18 |
+
*/
|
19 |
+
interface Twig_TemplateInterface
|
20 |
+
{
|
21 |
+
const ANY_CALL = 'any';
|
22 |
+
const ARRAY_CALL = 'array';
|
23 |
+
const METHOD_CALL = 'method';
|
24 |
+
|
25 |
+
/**
|
26 |
+
* Renders the template with the given context and returns it as string.
|
27 |
+
*
|
28 |
+
* @param array $context An array of parameters to pass to the template
|
29 |
+
*
|
30 |
+
* @return string The rendered template
|
31 |
+
*/
|
32 |
+
public function render(array $context);
|
33 |
+
|
34 |
+
/**
|
35 |
+
* Displays the template with the given context.
|
36 |
+
*
|
37 |
+
* @param array $context An array of parameters to pass to the template
|
38 |
+
* @param array $blocks An array of blocks to pass to the template
|
39 |
+
*/
|
40 |
+
public function display(array $context, array $blocks = array());
|
41 |
+
|
42 |
+
/**
|
43 |
+
* Returns the bound environment for this template.
|
44 |
+
*
|
45 |
+
* @return Twig_Environment The current environment
|
46 |
+
*/
|
47 |
+
public function getEnvironment();
|
48 |
+
}
|
classes/Twig/Test.php
CHANGED
@@ -1,34 +1,34 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2012 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
/**
|
13 |
-
* Represents a template test.
|
14 |
-
*
|
15 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
16 |
-
* @deprecated since 1.12 (to be removed in 2.0)
|
17 |
-
*/
|
18 |
-
abstract class Twig_Test implements Twig_TestInterface, Twig_TestCallableInterface
|
19 |
-
{
|
20 |
-
protected $options;
|
21 |
-
protected $arguments = array();
|
22 |
-
|
23 |
-
public function __construct(array $options = array())
|
24 |
-
{
|
25 |
-
$this->options = array_merge(array(
|
26 |
-
'callable' => null,
|
27 |
-
), $options);
|
28 |
-
}
|
29 |
-
|
30 |
-
public function getCallable()
|
31 |
-
{
|
32 |
-
return $this->options['callable'];
|
33 |
-
}
|
34 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2012 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Represents a template test.
|
14 |
+
*
|
15 |
+
* @author Fabien Potencier <fabien@symfony.com>
|
16 |
+
* @deprecated since 1.12 (to be removed in 2.0)
|
17 |
+
*/
|
18 |
+
abstract class Twig_Test implements Twig_TestInterface, Twig_TestCallableInterface
|
19 |
+
{
|
20 |
+
protected $options;
|
21 |
+
protected $arguments = array();
|
22 |
+
|
23 |
+
public function __construct(array $options = array())
|
24 |
+
{
|
25 |
+
$this->options = array_merge(array(
|
26 |
+
'callable' => null,
|
27 |
+
), $options);
|
28 |
+
}
|
29 |
+
|
30 |
+
public function getCallable()
|
31 |
+
{
|
32 |
+
return $this->options['callable'];
|
33 |
+
}
|
34 |
+
}
|
classes/Twig/TestCallableInterface.php
CHANGED
@@ -1,21 +1,21 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2012 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
/**
|
13 |
-
* Represents a callable template test.
|
14 |
-
*
|
15 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
16 |
-
* @deprecated since 1.12 (to be removed in 2.0)
|
17 |
-
*/
|
18 |
-
interface Twig_TestCallableInterface
|
19 |
-
{
|
20 |
-
public function getCallable();
|
21 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2012 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Represents a callable template test.
|
14 |
+
*
|
15 |
+
* @author Fabien Potencier <fabien@symfony.com>
|
16 |
+
* @deprecated since 1.12 (to be removed in 2.0)
|
17 |
+
*/
|
18 |
+
interface Twig_TestCallableInterface
|
19 |
+
{
|
20 |
+
public function getCallable();
|
21 |
+
}
|
classes/Twig/TestInterface.php
CHANGED
@@ -1,26 +1,26 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2010 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
/**
|
13 |
-
* Represents a template test.
|
14 |
-
*
|
15 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
16 |
-
* @deprecated since 1.12 (to be removed in 2.0)
|
17 |
-
*/
|
18 |
-
interface Twig_TestInterface
|
19 |
-
{
|
20 |
-
/**
|
21 |
-
* Compiles a test.
|
22 |
-
*
|
23 |
-
* @return string The PHP code for the test
|
24 |
-
*/
|
25 |
-
public function compile();
|
26 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2010 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Represents a template test.
|
14 |
+
*
|
15 |
+
* @author Fabien Potencier <fabien@symfony.com>
|
16 |
+
* @deprecated since 1.12 (to be removed in 2.0)
|
17 |
+
*/
|
18 |
+
interface Twig_TestInterface
|
19 |
+
{
|
20 |
+
/**
|
21 |
+
* Compiles a test.
|
22 |
+
*
|
23 |
+
* @return string The PHP code for the test
|
24 |
+
*/
|
25 |
+
public function compile();
|
26 |
+
}
|
classes/Twig/Token.php
CHANGED
@@ -1,216 +1,216 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2009 Fabien Potencier
|
7 |
-
* (c) 2009 Armin Ronacher
|
8 |
-
*
|
9 |
-
* For the full copyright and license information, please view the LICENSE
|
10 |
-
* file that was distributed with this source code.
|
11 |
-
*/
|
12 |
-
|
13 |
-
/**
|
14 |
-
* Represents a Token.
|
15 |
-
*
|
16 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
17 |
-
*/
|
18 |
-
class Twig_Token
|
19 |
-
{
|
20 |
-
protected $value;
|
21 |
-
protected $type;
|
22 |
-
protected $lineno;
|
23 |
-
|
24 |
-
const EOF_TYPE = -1;
|
25 |
-
const TEXT_TYPE = 0;
|
26 |
-
const BLOCK_START_TYPE = 1;
|
27 |
-
const VAR_START_TYPE = 2;
|
28 |
-
const BLOCK_END_TYPE = 3;
|
29 |
-
const VAR_END_TYPE = 4;
|
30 |
-
const NAME_TYPE = 5;
|
31 |
-
const NUMBER_TYPE = 6;
|
32 |
-
const STRING_TYPE = 7;
|
33 |
-
const OPERATOR_TYPE = 8;
|
34 |
-
const PUNCTUATION_TYPE = 9;
|
35 |
-
const INTERPOLATION_START_TYPE = 10;
|
36 |
-
const INTERPOLATION_END_TYPE = 11;
|
37 |
-
|
38 |
-
/**
|
39 |
-
* Constructor.
|
40 |
-
*
|
41 |
-
* @param int $type The type of the token
|
42 |
-
* @param string $value The token value
|
43 |
-
* @param int $lineno The line position in the source
|
44 |
-
*/
|
45 |
-
public function __construct($type, $value, $lineno)
|
46 |
-
{
|
47 |
-
$this->type = $type;
|
48 |
-
$this->value = $value;
|
49 |
-
$this->lineno = $lineno;
|
50 |
-
}
|
51 |
-
|
52 |
-
/**
|
53 |
-
* Returns a string representation of the token.
|
54 |
-
*
|
55 |
-
* @return string A string representation of the token
|
56 |
-
*/
|
57 |
-
public function __toString()
|
58 |
-
{
|
59 |
-
return sprintf('%s(%s)', self::typeToString($this->type, true), $this->value);
|
60 |
-
}
|
61 |
-
|
62 |
-
/**
|
63 |
-
* Tests the current token for a type and/or a value.
|
64 |
-
*
|
65 |
-
* Parameters may be:
|
66 |
-
* * just type
|
67 |
-
* * type and value (or array of possible values)
|
68 |
-
* * just value (or array of possible values) (NAME_TYPE is used as type)
|
69 |
-
*
|
70 |
-
* @param array|int $type The type to test
|
71 |
-
* @param array|string|null $values The token value
|
72 |
-
*
|
73 |
-
* @return bool
|
74 |
-
*/
|
75 |
-
public function test($type, $values = null)
|
76 |
-
{
|
77 |
-
if (null === $values && !is_int($type)) {
|
78 |
-
$values = $type;
|
79 |
-
$type = self::NAME_TYPE;
|
80 |
-
}
|
81 |
-
|
82 |
-
return ($this->type === $type) && (
|
83 |
-
null === $values ||
|
84 |
-
(is_array($values) && in_array($this->value, $values)) ||
|
85 |
-
$this->value == $values
|
86 |
-
);
|
87 |
-
}
|
88 |
-
|
89 |
-
/**
|
90 |
-
* Gets the line.
|
91 |
-
*
|
92 |
-
* @return int The source line
|
93 |
-
*/
|
94 |
-
public function getLine()
|
95 |
-
{
|
96 |
-
return $this->lineno;
|
97 |
-
}
|
98 |
-
|
99 |
-
/**
|
100 |
-
* Gets the token type.
|
101 |
-
*
|
102 |
-
* @return int The token type
|
103 |
-
*/
|
104 |
-
public function getType()
|
105 |
-
{
|
106 |
-
return $this->type;
|
107 |
-
}
|
108 |
-
|
109 |
-
/**
|
110 |
-
* Gets the token value.
|
111 |
-
*
|
112 |
-
* @return string The token value
|
113 |
-
*/
|
114 |
-
public function getValue()
|
115 |
-
{
|
116 |
-
return $this->value;
|
117 |
-
}
|
118 |
-
|
119 |
-
/**
|
120 |
-
* Returns the constant representation (internal) of a given type.
|
121 |
-
*
|
122 |
-
* @param int $type The type as an integer
|
123 |
-
* @param bool $short Whether to return a short representation or not
|
124 |
-
*
|
125 |
-
* @return string The string representation
|
126 |
-
*/
|
127 |
-
public static function typeToString($type, $short = false)
|
128 |
-
{
|
129 |
-
switch ($type) {
|
130 |
-
case self::EOF_TYPE:
|
131 |
-
$name = 'EOF_TYPE';
|
132 |
-
break;
|
133 |
-
case self::TEXT_TYPE:
|
134 |
-
$name = 'TEXT_TYPE';
|
135 |
-
break;
|
136 |
-
case self::BLOCK_START_TYPE:
|
137 |
-
$name = 'BLOCK_START_TYPE';
|
138 |
-
break;
|
139 |
-
case self::VAR_START_TYPE:
|
140 |
-
$name = 'VAR_START_TYPE';
|
141 |
-
break;
|
142 |
-
case self::BLOCK_END_TYPE:
|
143 |
-
$name = 'BLOCK_END_TYPE';
|
144 |
-
break;
|
145 |
-
case self::VAR_END_TYPE:
|
146 |
-
$name = 'VAR_END_TYPE';
|
147 |
-
break;
|
148 |
-
case self::NAME_TYPE:
|
149 |
-
$name = 'NAME_TYPE';
|
150 |
-
break;
|
151 |
-
case self::NUMBER_TYPE:
|
152 |
-
$name = 'NUMBER_TYPE';
|
153 |
-
break;
|
154 |
-
case self::STRING_TYPE:
|
155 |
-
$name = 'STRING_TYPE';
|
156 |
-
break;
|
157 |
-
case self::OPERATOR_TYPE:
|
158 |
-
$name = 'OPERATOR_TYPE';
|
159 |
-
break;
|
160 |
-
case self::PUNCTUATION_TYPE:
|
161 |
-
$name = 'PUNCTUATION_TYPE';
|
162 |
-
break;
|
163 |
-
case self::INTERPOLATION_START_TYPE:
|
164 |
-
$name = 'INTERPOLATION_START_TYPE';
|
165 |
-
break;
|
166 |
-
case self::INTERPOLATION_END_TYPE:
|
167 |
-
$name = 'INTERPOLATION_END_TYPE';
|
168 |
-
break;
|
169 |
-
default:
|
170 |
-
throw new LogicException(sprintf('Token of type "%s" does not exist.', $type));
|
171 |
-
}
|
172 |
-
|
173 |
-
return $short ? $name : 'Twig_Token::'.$name;
|
174 |
-
}
|
175 |
-
|
176 |
-
/**
|
177 |
-
* Returns the english representation of a given type.
|
178 |
-
*
|
179 |
-
* @param int $type The type as an integer
|
180 |
-
*
|
181 |
-
* @return string The string representation
|
182 |
-
*/
|
183 |
-
public static function typeToEnglish($type)
|
184 |
-
{
|
185 |
-
switch ($type) {
|
186 |
-
case self::EOF_TYPE:
|
187 |
-
return 'end of template';
|
188 |
-
case self::TEXT_TYPE:
|
189 |
-
return 'text';
|
190 |
-
case self::BLOCK_START_TYPE:
|
191 |
-
return 'begin of statement block';
|
192 |
-
case self::VAR_START_TYPE:
|
193 |
-
return 'begin of print statement';
|
194 |
-
case self::BLOCK_END_TYPE:
|
195 |
-
return 'end of statement block';
|
196 |
-
case self::VAR_END_TYPE:
|
197 |
-
return 'end of print statement';
|
198 |
-
case self::NAME_TYPE:
|
199 |
-
return 'name';
|
200 |
-
case self::NUMBER_TYPE:
|
201 |
-
return 'number';
|
202 |
-
case self::STRING_TYPE:
|
203 |
-
return 'string';
|
204 |
-
case self::OPERATOR_TYPE:
|
205 |
-
return 'operator';
|
206 |
-
case self::PUNCTUATION_TYPE:
|
207 |
-
return 'punctuation';
|
208 |
-
case self::INTERPOLATION_START_TYPE:
|
209 |
-
return 'begin of string interpolation';
|
210 |
-
case self::INTERPOLATION_END_TYPE:
|
211 |
-
return 'end of string interpolation';
|
212 |
-
default:
|
213 |
-
throw new LogicException(sprintf('Token of type "%s" does not exist.', $type));
|
214 |
-
}
|
215 |
-
}
|
216 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2009 Fabien Potencier
|
7 |
+
* (c) 2009 Armin Ronacher
|
8 |
+
*
|
9 |
+
* For the full copyright and license information, please view the LICENSE
|
10 |
+
* file that was distributed with this source code.
|
11 |
+
*/
|
12 |
+
|
13 |
+
/**
|
14 |
+
* Represents a Token.
|
15 |
+
*
|
16 |
+
* @author Fabien Potencier <fabien@symfony.com>
|
17 |
+
*/
|
18 |
+
class Twig_Token
|
19 |
+
{
|
20 |
+
protected $value;
|
21 |
+
protected $type;
|
22 |
+
protected $lineno;
|
23 |
+
|
24 |
+
const EOF_TYPE = -1;
|
25 |
+
const TEXT_TYPE = 0;
|
26 |
+
const BLOCK_START_TYPE = 1;
|
27 |
+
const VAR_START_TYPE = 2;
|
28 |
+
const BLOCK_END_TYPE = 3;
|
29 |
+
const VAR_END_TYPE = 4;
|
30 |
+
const NAME_TYPE = 5;
|
31 |
+
const NUMBER_TYPE = 6;
|
32 |
+
const STRING_TYPE = 7;
|
33 |
+
const OPERATOR_TYPE = 8;
|
34 |
+
const PUNCTUATION_TYPE = 9;
|
35 |
+
const INTERPOLATION_START_TYPE = 10;
|
36 |
+
const INTERPOLATION_END_TYPE = 11;
|
37 |
+
|
38 |
+
/**
|
39 |
+
* Constructor.
|
40 |
+
*
|
41 |
+
* @param int $type The type of the token
|
42 |
+
* @param string $value The token value
|
43 |
+
* @param int $lineno The line position in the source
|
44 |
+
*/
|
45 |
+
public function __construct($type, $value, $lineno)
|
46 |
+
{
|
47 |
+
$this->type = $type;
|
48 |
+
$this->value = $value;
|
49 |
+
$this->lineno = $lineno;
|
50 |
+
}
|
51 |
+
|
52 |
+
/**
|
53 |
+
* Returns a string representation of the token.
|
54 |
+
*
|
55 |
+
* @return string A string representation of the token
|
56 |
+
*/
|
57 |
+
public function __toString()
|
58 |
+
{
|
59 |
+
return sprintf('%s(%s)', self::typeToString($this->type, true), $this->value);
|
60 |
+
}
|
61 |
+
|
62 |
+
/**
|
63 |
+
* Tests the current token for a type and/or a value.
|
64 |
+
*
|
65 |
+
* Parameters may be:
|
66 |
+
* * just type
|
67 |
+
* * type and value (or array of possible values)
|
68 |
+
* * just value (or array of possible values) (NAME_TYPE is used as type)
|
69 |
+
*
|
70 |
+
* @param array|int $type The type to test
|
71 |
+
* @param array|string|null $values The token value
|
72 |
+
*
|
73 |
+
* @return bool
|
74 |
+
*/
|
75 |
+
public function test($type, $values = null)
|
76 |
+
{
|
77 |
+
if (null === $values && !is_int($type)) {
|
78 |
+
$values = $type;
|
79 |
+
$type = self::NAME_TYPE;
|
80 |
+
}
|
81 |
+
|
82 |
+
return ($this->type === $type) && (
|
83 |
+
null === $values ||
|
84 |
+
(is_array($values) && in_array($this->value, $values)) ||
|
85 |
+
$this->value == $values
|
86 |
+
);
|
87 |
+
}
|
88 |
+
|
89 |
+
/**
|
90 |
+
* Gets the line.
|
91 |
+
*
|
92 |
+
* @return int The source line
|
93 |
+
*/
|
94 |
+
public function getLine()
|
95 |
+
{
|
96 |
+
return $this->lineno;
|
97 |
+
}
|
98 |
+
|
99 |
+
/**
|
100 |
+
* Gets the token type.
|
101 |
+
*
|
102 |
+
* @return int The token type
|
103 |
+
*/
|
104 |
+
public function getType()
|
105 |
+
{
|
106 |
+
return $this->type;
|
107 |
+
}
|
108 |
+
|
109 |
+
/**
|
110 |
+
* Gets the token value.
|
111 |
+
*
|
112 |
+
* @return string The token value
|
113 |
+
*/
|
114 |
+
public function getValue()
|
115 |
+
{
|
116 |
+
return $this->value;
|
117 |
+
}
|
118 |
+
|
119 |
+
/**
|
120 |
+
* Returns the constant representation (internal) of a given type.
|
121 |
+
*
|
122 |
+
* @param int $type The type as an integer
|
123 |
+
* @param bool $short Whether to return a short representation or not
|
124 |
+
*
|
125 |
+
* @return string The string representation
|
126 |
+
*/
|
127 |
+
public static function typeToString($type, $short = false)
|
128 |
+
{
|
129 |
+
switch ($type) {
|
130 |
+
case self::EOF_TYPE:
|
131 |
+
$name = 'EOF_TYPE';
|
132 |
+
break;
|
133 |
+
case self::TEXT_TYPE:
|
134 |
+
$name = 'TEXT_TYPE';
|
135 |
+
break;
|
136 |
+
case self::BLOCK_START_TYPE:
|
137 |
+
$name = 'BLOCK_START_TYPE';
|
138 |
+
break;
|
139 |
+
case self::VAR_START_TYPE:
|
140 |
+
$name = 'VAR_START_TYPE';
|
141 |
+
break;
|
142 |
+
case self::BLOCK_END_TYPE:
|
143 |
+
$name = 'BLOCK_END_TYPE';
|
144 |
+
break;
|
145 |
+
case self::VAR_END_TYPE:
|
146 |
+
$name = 'VAR_END_TYPE';
|
147 |
+
break;
|
148 |
+
case self::NAME_TYPE:
|
149 |
+
$name = 'NAME_TYPE';
|
150 |
+
break;
|
151 |
+
case self::NUMBER_TYPE:
|
152 |
+
$name = 'NUMBER_TYPE';
|
153 |
+
break;
|
154 |
+
case self::STRING_TYPE:
|
155 |
+
$name = 'STRING_TYPE';
|
156 |
+
break;
|
157 |
+
case self::OPERATOR_TYPE:
|
158 |
+
$name = 'OPERATOR_TYPE';
|
159 |
+
break;
|
160 |
+
case self::PUNCTUATION_TYPE:
|
161 |
+
$name = 'PUNCTUATION_TYPE';
|
162 |
+
break;
|
163 |
+
case self::INTERPOLATION_START_TYPE:
|
164 |
+
$name = 'INTERPOLATION_START_TYPE';
|
165 |
+
break;
|
166 |
+
case self::INTERPOLATION_END_TYPE:
|
167 |
+
$name = 'INTERPOLATION_END_TYPE';
|
168 |
+
break;
|
169 |
+
default:
|
170 |
+
throw new LogicException(sprintf('Token of type "%s" does not exist.', $type));
|
171 |
+
}
|
172 |
+
|
173 |
+
return $short ? $name : 'Twig_Token::'.$name;
|
174 |
+
}
|
175 |
+
|
176 |
+
/**
|
177 |
+
* Returns the english representation of a given type.
|
178 |
+
*
|
179 |
+
* @param int $type The type as an integer
|
180 |
+
*
|
181 |
+
* @return string The string representation
|
182 |
+
*/
|
183 |
+
public static function typeToEnglish($type)
|
184 |
+
{
|
185 |
+
switch ($type) {
|
186 |
+
case self::EOF_TYPE:
|
187 |
+
return 'end of template';
|
188 |
+
case self::TEXT_TYPE:
|
189 |
+
return 'text';
|
190 |
+
case self::BLOCK_START_TYPE:
|
191 |
+
return 'begin of statement block';
|
192 |
+
case self::VAR_START_TYPE:
|
193 |
+
return 'begin of print statement';
|
194 |
+
case self::BLOCK_END_TYPE:
|
195 |
+
return 'end of statement block';
|
196 |
+
case self::VAR_END_TYPE:
|
197 |
+
return 'end of print statement';
|
198 |
+
case self::NAME_TYPE:
|
199 |
+
return 'name';
|
200 |
+
case self::NUMBER_TYPE:
|
201 |
+
return 'number';
|
202 |
+
case self::STRING_TYPE:
|
203 |
+
return 'string';
|
204 |
+
case self::OPERATOR_TYPE:
|
205 |
+
return 'operator';
|
206 |
+
case self::PUNCTUATION_TYPE:
|
207 |
+
return 'punctuation';
|
208 |
+
case self::INTERPOLATION_START_TYPE:
|
209 |
+
return 'begin of string interpolation';
|
210 |
+
case self::INTERPOLATION_END_TYPE:
|
211 |
+
return 'end of string interpolation';
|
212 |
+
default:
|
213 |
+
throw new LogicException(sprintf('Token of type "%s" does not exist.', $type));
|
214 |
+
}
|
215 |
+
}
|
216 |
+
}
|
classes/Twig/TokenParser.php
CHANGED
@@ -1,33 +1,33 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2009 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
/**
|
13 |
-
* Base class for all token parsers.
|
14 |
-
*
|
15 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
16 |
-
*/
|
17 |
-
abstract class Twig_TokenParser implements Twig_TokenParserInterface
|
18 |
-
{
|
19 |
-
/**
|
20 |
-
* @var Twig_Parser
|
21 |
-
*/
|
22 |
-
protected $parser;
|
23 |
-
|
24 |
-
/**
|
25 |
-
* Sets the parser associated with this token parser
|
26 |
-
*
|
27 |
-
* @param $parser A Twig_Parser instance
|
28 |
-
*/
|
29 |
-
public function setParser(Twig_Parser $parser)
|
30 |
-
{
|
31 |
-
$this->parser = $parser;
|
32 |
-
}
|
33 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2009 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Base class for all token parsers.
|
14 |
+
*
|
15 |
+
* @author Fabien Potencier <fabien@symfony.com>
|
16 |
+
*/
|
17 |
+
abstract class Twig_TokenParser implements Twig_TokenParserInterface
|
18 |
+
{
|
19 |
+
/**
|
20 |
+
* @var Twig_Parser
|
21 |
+
*/
|
22 |
+
protected $parser;
|
23 |
+
|
24 |
+
/**
|
25 |
+
* Sets the parser associated with this token parser
|
26 |
+
*
|
27 |
+
* @param $parser A Twig_Parser instance
|
28 |
+
*/
|
29 |
+
public function setParser(Twig_Parser $parser)
|
30 |
+
{
|
31 |
+
$this->parser = $parser;
|
32 |
+
}
|
33 |
+
}
|
classes/Twig/TokenParser/AutoEscape.php
CHANGED
@@ -1,89 +1,89 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2009 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
/**
|
13 |
-
* Marks a section of a template to be escaped or not.
|
14 |
-
*
|
15 |
-
* <pre>
|
16 |
-
* {% autoescape true %}
|
17 |
-
* Everything will be automatically escaped in this block
|
18 |
-
* {% endautoescape %}
|
19 |
-
*
|
20 |
-
* {% autoescape false %}
|
21 |
-
* Everything will be outputed as is in this block
|
22 |
-
* {% endautoescape %}
|
23 |
-
*
|
24 |
-
* {% autoescape true js %}
|
25 |
-
* Everything will be automatically escaped in this block
|
26 |
-
* using the js escaping strategy
|
27 |
-
* {% endautoescape %}
|
28 |
-
* </pre>
|
29 |
-
*/
|
30 |
-
class Twig_TokenParser_AutoEscape extends Twig_TokenParser
|
31 |
-
{
|
32 |
-
/**
|
33 |
-
* Parses a token and returns a node.
|
34 |
-
*
|
35 |
-
* @param Twig_Token $token A Twig_Token instance
|
36 |
-
*
|
37 |
-
* @return Twig_NodeInterface A Twig_NodeInterface instance
|
38 |
-
*/
|
39 |
-
public function parse(Twig_Token $token)
|
40 |
-
{
|
41 |
-
$lineno = $token->getLine();
|
42 |
-
$stream = $this->parser->getStream();
|
43 |
-
|
44 |
-
if ($stream->test(Twig_Token::BLOCK_END_TYPE)) {
|
45 |
-
$value = 'html';
|
46 |
-
} else {
|
47 |
-
$expr = $this->parser->getExpressionParser()->parseExpression();
|
48 |
-
if (!$expr instanceof Twig_Node_Expression_Constant) {
|
49 |
-
throw new Twig_Error_Syntax('An escaping strategy must be a string or a Boolean.', $stream->getCurrent()->getLine(), $stream->getFilename());
|
50 |
-
}
|
51 |
-
$value = $expr->getAttribute('value');
|
52 |
-
|
53 |
-
$compat = true === $value || false === $value;
|
54 |
-
|
55 |
-
if (true === $value) {
|
56 |
-
$value = 'html';
|
57 |
-
}
|
58 |
-
|
59 |
-
if ($compat && $stream->test(Twig_Token::NAME_TYPE)) {
|
60 |
-
if (false === $value) {
|
61 |
-
throw new Twig_Error_Syntax('Unexpected escaping strategy as you set autoescaping to false.', $stream->getCurrent()->getLine(), $stream->getFilename());
|
62 |
-
}
|
63 |
-
|
64 |
-
$value = $stream->next()->getValue();
|
65 |
-
}
|
66 |
-
}
|
67 |
-
|
68 |
-
$stream->expect(Twig_Token::BLOCK_END_TYPE);
|
69 |
-
$body = $this->parser->subparse(array($this, 'decideBlockEnd'), true);
|
70 |
-
$stream->expect(Twig_Token::BLOCK_END_TYPE);
|
71 |
-
|
72 |
-
return new Twig_Node_AutoEscape($value, $body, $lineno, $this->getTag());
|
73 |
-
}
|
74 |
-
|
75 |
-
public function decideBlockEnd(Twig_Token $token)
|
76 |
-
{
|
77 |
-
return $token->test('endautoescape');
|
78 |
-
}
|
79 |
-
|
80 |
-
/**
|
81 |
-
* Gets the tag name associated with this token parser.
|
82 |
-
*
|
83 |
-
* @return string The tag name
|
84 |
-
*/
|
85 |
-
public function getTag()
|
86 |
-
{
|
87 |
-
return 'autoescape';
|
88 |
-
}
|
89 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2009 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Marks a section of a template to be escaped or not.
|
14 |
+
*
|
15 |
+
* <pre>
|
16 |
+
* {% autoescape true %}
|
17 |
+
* Everything will be automatically escaped in this block
|
18 |
+
* {% endautoescape %}
|
19 |
+
*
|
20 |
+
* {% autoescape false %}
|
21 |
+
* Everything will be outputed as is in this block
|
22 |
+
* {% endautoescape %}
|
23 |
+
*
|
24 |
+
* {% autoescape true js %}
|
25 |
+
* Everything will be automatically escaped in this block
|
26 |
+
* using the js escaping strategy
|
27 |
+
* {% endautoescape %}
|
28 |
+
* </pre>
|
29 |
+
*/
|
30 |
+
class Twig_TokenParser_AutoEscape extends Twig_TokenParser
|
31 |
+
{
|
32 |
+
/**
|
33 |
+
* Parses a token and returns a node.
|
34 |
+
*
|
35 |
+
* @param Twig_Token $token A Twig_Token instance
|
36 |
+
*
|
37 |
+
* @return Twig_NodeInterface A Twig_NodeInterface instance
|
38 |
+
*/
|
39 |
+
public function parse(Twig_Token $token)
|
40 |
+
{
|
41 |
+
$lineno = $token->getLine();
|
42 |
+
$stream = $this->parser->getStream();
|
43 |
+
|
44 |
+
if ($stream->test(Twig_Token::BLOCK_END_TYPE)) {
|
45 |
+
$value = 'html';
|
46 |
+
} else {
|
47 |
+
$expr = $this->parser->getExpressionParser()->parseExpression();
|
48 |
+
if (!$expr instanceof Twig_Node_Expression_Constant) {
|
49 |
+
throw new Twig_Error_Syntax('An escaping strategy must be a string or a Boolean.', $stream->getCurrent()->getLine(), $stream->getFilename());
|
50 |
+
}
|
51 |
+
$value = $expr->getAttribute('value');
|
52 |
+
|
53 |
+
$compat = true === $value || false === $value;
|
54 |
+
|
55 |
+
if (true === $value) {
|
56 |
+
$value = 'html';
|
57 |
+
}
|
58 |
+
|
59 |
+
if ($compat && $stream->test(Twig_Token::NAME_TYPE)) {
|
60 |
+
if (false === $value) {
|
61 |
+
throw new Twig_Error_Syntax('Unexpected escaping strategy as you set autoescaping to false.', $stream->getCurrent()->getLine(), $stream->getFilename());
|
62 |
+
}
|
63 |
+
|
64 |
+
$value = $stream->next()->getValue();
|
65 |
+
}
|
66 |
+
}
|
67 |
+
|
68 |
+
$stream->expect(Twig_Token::BLOCK_END_TYPE);
|
69 |
+
$body = $this->parser->subparse(array($this, 'decideBlockEnd'), true);
|
70 |
+
$stream->expect(Twig_Token::BLOCK_END_TYPE);
|
71 |
+
|
72 |
+
return new Twig_Node_AutoEscape($value, $body, $lineno, $this->getTag());
|
73 |
+
}
|
74 |
+
|
75 |
+
public function decideBlockEnd(Twig_Token $token)
|
76 |
+
{
|
77 |
+
return $token->test('endautoescape');
|
78 |
+
}
|
79 |
+
|
80 |
+
/**
|
81 |
+
* Gets the tag name associated with this token parser.
|
82 |
+
*
|
83 |
+
* @return string The tag name
|
84 |
+
*/
|
85 |
+
public function getTag()
|
86 |
+
{
|
87 |
+
return 'autoescape';
|
88 |
+
}
|
89 |
+
}
|
classes/Twig/TokenParser/Block.php
CHANGED
@@ -1,81 +1,81 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2009 Fabien Potencier
|
7 |
-
* (c) 2009 Armin Ronacher
|
8 |
-
*
|
9 |
-
* For the full copyright and license information, please view the LICENSE
|
10 |
-
* file that was distributed with this source code.
|
11 |
-
*/
|
12 |
-
|
13 |
-
/**
|
14 |
-
* Marks a section of a template as being reusable.
|
15 |
-
*
|
16 |
-
* <pre>
|
17 |
-
* {% block head %}
|
18 |
-
* <link rel="stylesheet" href="style.css" />
|
19 |
-
* <title>{% block title %}{% endblock %} - My Webpage</title>
|
20 |
-
* {% endblock %}
|
21 |
-
* </pre>
|
22 |
-
*/
|
23 |
-
class Twig_TokenParser_Block extends Twig_TokenParser
|
24 |
-
{
|
25 |
-
/**
|
26 |
-
* Parses a token and returns a node.
|
27 |
-
*
|
28 |
-
* @param Twig_Token $token A Twig_Token instance
|
29 |
-
*
|
30 |
-
* @return Twig_NodeInterface A Twig_NodeInterface instance
|
31 |
-
*/
|
32 |
-
public function parse(Twig_Token $token)
|
33 |
-
{
|
34 |
-
$lineno = $token->getLine();
|
35 |
-
$stream = $this->parser->getStream();
|
36 |
-
$name = $stream->expect(Twig_Token::NAME_TYPE)->getValue();
|
37 |
-
if ($this->parser->hasBlock($name)) {
|
38 |
-
throw new Twig_Error_Syntax(sprintf("The block '$name' has already been defined line %d", $this->parser->getBlock($name)->getLine()), $stream->getCurrent()->getLine(), $stream->getFilename());
|
39 |
-
}
|
40 |
-
$this->parser->setBlock($name, $block = new Twig_Node_Block($name, new Twig_Node(array()), $lineno));
|
41 |
-
$this->parser->pushLocalScope();
|
42 |
-
$this->parser->pushBlockStack($name);
|
43 |
-
|
44 |
-
if ($stream->nextIf(Twig_Token::BLOCK_END_TYPE)) {
|
45 |
-
$body = $this->parser->subparse(array($this, 'decideBlockEnd'), true);
|
46 |
-
if ($token = $stream->nextIf(Twig_Token::NAME_TYPE)) {
|
47 |
-
$value = $token->getValue();
|
48 |
-
|
49 |
-
if ($value != $name) {
|
50 |
-
throw new Twig_Error_Syntax(sprintf("Expected endblock for block '$name' (but %s given)", $value), $stream->getCurrent()->getLine(), $stream->getFilename());
|
51 |
-
}
|
52 |
-
}
|
53 |
-
} else {
|
54 |
-
$body = new Twig_Node(array(
|
55 |
-
new Twig_Node_Print($this->parser->getExpressionParser()->parseExpression(), $lineno),
|
56 |
-
));
|
57 |
-
}
|
58 |
-
$stream->expect(Twig_Token::BLOCK_END_TYPE);
|
59 |
-
|
60 |
-
$block->setNode('body', $body);
|
61 |
-
$this->parser->popBlockStack();
|
62 |
-
$this->parser->popLocalScope();
|
63 |
-
|
64 |
-
return new Twig_Node_BlockReference($name, $lineno, $this->getTag());
|
65 |
-
}
|
66 |
-
|
67 |
-
public function decideBlockEnd(Twig_Token $token)
|
68 |
-
{
|
69 |
-
return $token->test('endblock');
|
70 |
-
}
|
71 |
-
|
72 |
-
/**
|
73 |
-
* Gets the tag name associated with this token parser.
|
74 |
-
*
|
75 |
-
* @return string The tag name
|
76 |
-
*/
|
77 |
-
public function getTag()
|
78 |
-
{
|
79 |
-
return 'block';
|
80 |
-
}
|
81 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2009 Fabien Potencier
|
7 |
+
* (c) 2009 Armin Ronacher
|
8 |
+
*
|
9 |
+
* For the full copyright and license information, please view the LICENSE
|
10 |
+
* file that was distributed with this source code.
|
11 |
+
*/
|
12 |
+
|
13 |
+
/**
|
14 |
+
* Marks a section of a template as being reusable.
|
15 |
+
*
|
16 |
+
* <pre>
|
17 |
+
* {% block head %}
|
18 |
+
* <link rel="stylesheet" href="style.css" />
|
19 |
+
* <title>{% block title %}{% endblock %} - My Webpage</title>
|
20 |
+
* {% endblock %}
|
21 |
+
* </pre>
|
22 |
+
*/
|
23 |
+
class Twig_TokenParser_Block extends Twig_TokenParser
|
24 |
+
{
|
25 |
+
/**
|
26 |
+
* Parses a token and returns a node.
|
27 |
+
*
|
28 |
+
* @param Twig_Token $token A Twig_Token instance
|
29 |
+
*
|
30 |
+
* @return Twig_NodeInterface A Twig_NodeInterface instance
|
31 |
+
*/
|
32 |
+
public function parse(Twig_Token $token)
|
33 |
+
{
|
34 |
+
$lineno = $token->getLine();
|
35 |
+
$stream = $this->parser->getStream();
|
36 |
+
$name = $stream->expect(Twig_Token::NAME_TYPE)->getValue();
|
37 |
+
if ($this->parser->hasBlock($name)) {
|
38 |
+
throw new Twig_Error_Syntax(sprintf("The block '$name' has already been defined line %d", $this->parser->getBlock($name)->getLine()), $stream->getCurrent()->getLine(), $stream->getFilename());
|
39 |
+
}
|
40 |
+
$this->parser->setBlock($name, $block = new Twig_Node_Block($name, new Twig_Node(array()), $lineno));
|
41 |
+
$this->parser->pushLocalScope();
|
42 |
+
$this->parser->pushBlockStack($name);
|
43 |
+
|
44 |
+
if ($stream->nextIf(Twig_Token::BLOCK_END_TYPE)) {
|
45 |
+
$body = $this->parser->subparse(array($this, 'decideBlockEnd'), true);
|
46 |
+
if ($token = $stream->nextIf(Twig_Token::NAME_TYPE)) {
|
47 |
+
$value = $token->getValue();
|
48 |
+
|
49 |
+
if ($value != $name) {
|
50 |
+
throw new Twig_Error_Syntax(sprintf("Expected endblock for block '$name' (but %s given)", $value), $stream->getCurrent()->getLine(), $stream->getFilename());
|
51 |
+
}
|
52 |
+
}
|
53 |
+
} else {
|
54 |
+
$body = new Twig_Node(array(
|
55 |
+
new Twig_Node_Print($this->parser->getExpressionParser()->parseExpression(), $lineno),
|
56 |
+
));
|
57 |
+
}
|
58 |
+
$stream->expect(Twig_Token::BLOCK_END_TYPE);
|
59 |
+
|
60 |
+
$block->setNode('body', $body);
|
61 |
+
$this->parser->popBlockStack();
|
62 |
+
$this->parser->popLocalScope();
|
63 |
+
|
64 |
+
return new Twig_Node_BlockReference($name, $lineno, $this->getTag());
|
65 |
+
}
|
66 |
+
|
67 |
+
public function decideBlockEnd(Twig_Token $token)
|
68 |
+
{
|
69 |
+
return $token->test('endblock');
|
70 |
+
}
|
71 |
+
|
72 |
+
/**
|
73 |
+
* Gets the tag name associated with this token parser.
|
74 |
+
*
|
75 |
+
* @return string The tag name
|
76 |
+
*/
|
77 |
+
public function getTag()
|
78 |
+
{
|
79 |
+
return 'block';
|
80 |
+
}
|
81 |
+
}
|
classes/Twig/TokenParser/Do.php
CHANGED
@@ -1,42 +1,42 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2011 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
/**
|
13 |
-
* Evaluates an expression, discarding the returned value.
|
14 |
-
*/
|
15 |
-
class Twig_TokenParser_Do extends Twig_TokenParser
|
16 |
-
{
|
17 |
-
/**
|
18 |
-
* Parses a token and returns a node.
|
19 |
-
*
|
20 |
-
* @param Twig_Token $token A Twig_Token instance
|
21 |
-
*
|
22 |
-
* @return Twig_NodeInterface A Twig_NodeInterface instance
|
23 |
-
*/
|
24 |
-
public function parse(Twig_Token $token)
|
25 |
-
{
|
26 |
-
$expr = $this->parser->getExpressionParser()->parseExpression();
|
27 |
-
|
28 |
-
$this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
|
29 |
-
|
30 |
-
return new Twig_Node_Do($expr, $token->getLine(), $this->getTag());
|
31 |
-
}
|
32 |
-
|
33 |
-
/**
|
34 |
-
* Gets the tag name associated with this token parser.
|
35 |
-
*
|
36 |
-
* @return string The tag name
|
37 |
-
*/
|
38 |
-
public function getTag()
|
39 |
-
{
|
40 |
-
return 'do';
|
41 |
-
}
|
42 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2011 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Evaluates an expression, discarding the returned value.
|
14 |
+
*/
|
15 |
+
class Twig_TokenParser_Do extends Twig_TokenParser
|
16 |
+
{
|
17 |
+
/**
|
18 |
+
* Parses a token and returns a node.
|
19 |
+
*
|
20 |
+
* @param Twig_Token $token A Twig_Token instance
|
21 |
+
*
|
22 |
+
* @return Twig_NodeInterface A Twig_NodeInterface instance
|
23 |
+
*/
|
24 |
+
public function parse(Twig_Token $token)
|
25 |
+
{
|
26 |
+
$expr = $this->parser->getExpressionParser()->parseExpression();
|
27 |
+
|
28 |
+
$this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
|
29 |
+
|
30 |
+
return new Twig_Node_Do($expr, $token->getLine(), $this->getTag());
|
31 |
+
}
|
32 |
+
|
33 |
+
/**
|
34 |
+
* Gets the tag name associated with this token parser.
|
35 |
+
*
|
36 |
+
* @return string The tag name
|
37 |
+
*/
|
38 |
+
public function getTag()
|
39 |
+
{
|
40 |
+
return 'do';
|
41 |
+
}
|
42 |
+
}
|
classes/Twig/TokenParser/Embed.php
CHANGED
@@ -1,66 +1,66 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2012 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
/**
|
13 |
-
* Embeds a template.
|
14 |
-
*/
|
15 |
-
class Twig_TokenParser_Embed extends Twig_TokenParser_Include
|
16 |
-
{
|
17 |
-
/**
|
18 |
-
* Parses a token and returns a node.
|
19 |
-
*
|
20 |
-
* @param Twig_Token $token A Twig_Token instance
|
21 |
-
*
|
22 |
-
* @return Twig_NodeInterface A Twig_NodeInterface instance
|
23 |
-
*/
|
24 |
-
public function parse(Twig_Token $token)
|
25 |
-
{
|
26 |
-
$stream = $this->parser->getStream();
|
27 |
-
|
28 |
-
$parent = $this->parser->getExpressionParser()->parseExpression();
|
29 |
-
|
30 |
-
list($variables, $only, $ignoreMissing) = $this->parseArguments();
|
31 |
-
|
32 |
-
// inject a fake parent to make the parent() function work
|
33 |
-
$stream->injectTokens(array(
|
34 |
-
new Twig_Token(Twig_Token::BLOCK_START_TYPE, '', $token->getLine()),
|
35 |
-
new Twig_Token(Twig_Token::NAME_TYPE, 'extends', $token->getLine()),
|
36 |
-
new Twig_Token(Twig_Token::STRING_TYPE, '__parent__', $token->getLine()),
|
37 |
-
new Twig_Token(Twig_Token::BLOCK_END_TYPE, '', $token->getLine()),
|
38 |
-
));
|
39 |
-
|
40 |
-
$module = $this->parser->parse($stream, array($this, 'decideBlockEnd'), true);
|
41 |
-
|
42 |
-
// override the parent with the correct one
|
43 |
-
$module->setNode('parent', $parent);
|
44 |
-
|
45 |
-
$this->parser->embedTemplate($module);
|
46 |
-
|
47 |
-
$stream->expect(Twig_Token::BLOCK_END_TYPE);
|
48 |
-
|
49 |
-
return new Twig_Node_Embed($module->getAttribute('filename'), $module->getAttribute('index'), $variables, $only, $ignoreMissing, $token->getLine(), $this->getTag());
|
50 |
-
}
|
51 |
-
|
52 |
-
public function decideBlockEnd(Twig_Token $token)
|
53 |
-
{
|
54 |
-
return $token->test('endembed');
|
55 |
-
}
|
56 |
-
|
57 |
-
/**
|
58 |
-
* Gets the tag name associated with this token parser.
|
59 |
-
*
|
60 |
-
* @return string The tag name
|
61 |
-
*/
|
62 |
-
public function getTag()
|
63 |
-
{
|
64 |
-
return 'embed';
|
65 |
-
}
|
66 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2012 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Embeds a template.
|
14 |
+
*/
|
15 |
+
class Twig_TokenParser_Embed extends Twig_TokenParser_Include
|
16 |
+
{
|
17 |
+
/**
|
18 |
+
* Parses a token and returns a node.
|
19 |
+
*
|
20 |
+
* @param Twig_Token $token A Twig_Token instance
|
21 |
+
*
|
22 |
+
* @return Twig_NodeInterface A Twig_NodeInterface instance
|
23 |
+
*/
|
24 |
+
public function parse(Twig_Token $token)
|
25 |
+
{
|
26 |
+
$stream = $this->parser->getStream();
|
27 |
+
|
28 |
+
$parent = $this->parser->getExpressionParser()->parseExpression();
|
29 |
+
|
30 |
+
list($variables, $only, $ignoreMissing) = $this->parseArguments();
|
31 |
+
|
32 |
+
// inject a fake parent to make the parent() function work
|
33 |
+
$stream->injectTokens(array(
|
34 |
+
new Twig_Token(Twig_Token::BLOCK_START_TYPE, '', $token->getLine()),
|
35 |
+
new Twig_Token(Twig_Token::NAME_TYPE, 'extends', $token->getLine()),
|
36 |
+
new Twig_Token(Twig_Token::STRING_TYPE, '__parent__', $token->getLine()),
|
37 |
+
new Twig_Token(Twig_Token::BLOCK_END_TYPE, '', $token->getLine()),
|
38 |
+
));
|
39 |
+
|
40 |
+
$module = $this->parser->parse($stream, array($this, 'decideBlockEnd'), true);
|
41 |
+
|
42 |
+
// override the parent with the correct one
|
43 |
+
$module->setNode('parent', $parent);
|
44 |
+
|
45 |
+
$this->parser->embedTemplate($module);
|
46 |
+
|
47 |
+
$stream->expect(Twig_Token::BLOCK_END_TYPE);
|
48 |
+
|
49 |
+
return new Twig_Node_Embed($module->getAttribute('filename'), $module->getAttribute('index'), $variables, $only, $ignoreMissing, $token->getLine(), $this->getTag());
|
50 |
+
}
|
51 |
+
|
52 |
+
public function decideBlockEnd(Twig_Token $token)
|
53 |
+
{
|
54 |
+
return $token->test('endembed');
|
55 |
+
}
|
56 |
+
|
57 |
+
/**
|
58 |
+
* Gets the tag name associated with this token parser.
|
59 |
+
*
|
60 |
+
* @return string The tag name
|
61 |
+
*/
|
62 |
+
public function getTag()
|
63 |
+
{
|
64 |
+
return 'embed';
|
65 |
+
}
|
66 |
+
}
|
classes/Twig/TokenParser/Extends.php
CHANGED
@@ -1,52 +1,52 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2009 Fabien Potencier
|
7 |
-
* (c) 2009 Armin Ronacher
|
8 |
-
*
|
9 |
-
* For the full copyright and license information, please view the LICENSE
|
10 |
-
* file that was distributed with this source code.
|
11 |
-
*/
|
12 |
-
|
13 |
-
/**
|
14 |
-
* Extends a template by another one.
|
15 |
-
*
|
16 |
-
* <pre>
|
17 |
-
* {% extends "base.html" %}
|
18 |
-
* </pre>
|
19 |
-
*/
|
20 |
-
class Twig_TokenParser_Extends extends Twig_TokenParser
|
21 |
-
{
|
22 |
-
/**
|
23 |
-
* Parses a token and returns a node.
|
24 |
-
*
|
25 |
-
* @param Twig_Token $token A Twig_Token instance
|
26 |
-
*
|
27 |
-
* @return Twig_NodeInterface A Twig_NodeInterface instance
|
28 |
-
*/
|
29 |
-
public function parse(Twig_Token $token)
|
30 |
-
{
|
31 |
-
if (!$this->parser->isMainScope()) {
|
32 |
-
throw new Twig_Error_Syntax('Cannot extend from a block', $token->getLine(), $this->parser->getFilename());
|
33 |
-
}
|
34 |
-
|
35 |
-
if (null !== $this->parser->getParent()) {
|
36 |
-
throw new Twig_Error_Syntax('Multiple extends tags are forbidden', $token->getLine(), $this->parser->getFilename());
|
37 |
-
}
|
38 |
-
$this->parser->setParent($this->parser->getExpressionParser()->parseExpression());
|
39 |
-
|
40 |
-
$this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
|
41 |
-
}
|
42 |
-
|
43 |
-
/**
|
44 |
-
* Gets the tag name associated with this token parser.
|
45 |
-
*
|
46 |
-
* @return string The tag name
|
47 |
-
*/
|
48 |
-
public function getTag()
|
49 |
-
{
|
50 |
-
return 'extends';
|
51 |
-
}
|
52 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2009 Fabien Potencier
|
7 |
+
* (c) 2009 Armin Ronacher
|
8 |
+
*
|
9 |
+
* For the full copyright and license information, please view the LICENSE
|
10 |
+
* file that was distributed with this source code.
|
11 |
+
*/
|
12 |
+
|
13 |
+
/**
|
14 |
+
* Extends a template by another one.
|
15 |
+
*
|
16 |
+
* <pre>
|
17 |
+
* {% extends "base.html" %}
|
18 |
+
* </pre>
|
19 |
+
*/
|
20 |
+
class Twig_TokenParser_Extends extends Twig_TokenParser
|
21 |
+
{
|
22 |
+
/**
|
23 |
+
* Parses a token and returns a node.
|
24 |
+
*
|
25 |
+
* @param Twig_Token $token A Twig_Token instance
|
26 |
+
*
|
27 |
+
* @return Twig_NodeInterface A Twig_NodeInterface instance
|
28 |
+
*/
|
29 |
+
public function parse(Twig_Token $token)
|
30 |
+
{
|
31 |
+
if (!$this->parser->isMainScope()) {
|
32 |
+
throw new Twig_Error_Syntax('Cannot extend from a block', $token->getLine(), $this->parser->getFilename());
|
33 |
+
}
|
34 |
+
|
35 |
+
if (null !== $this->parser->getParent()) {
|
36 |
+
throw new Twig_Error_Syntax('Multiple extends tags are forbidden', $token->getLine(), $this->parser->getFilename());
|
37 |
+
}
|
38 |
+
$this->parser->setParent($this->parser->getExpressionParser()->parseExpression());
|
39 |
+
|
40 |
+
$this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
|
41 |
+
}
|
42 |
+
|
43 |
+
/**
|
44 |
+
* Gets the tag name associated with this token parser.
|
45 |
+
*
|
46 |
+
* @return string The tag name
|
47 |
+
*/
|
48 |
+
public function getTag()
|
49 |
+
{
|
50 |
+
return 'extends';
|
51 |
+
}
|
52 |
+
}
|
classes/Twig/TokenParser/Filter.php
CHANGED
@@ -1,61 +1,61 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2009 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
/**
|
13 |
-
* Filters a section of a template by applying filters.
|
14 |
-
*
|
15 |
-
* <pre>
|
16 |
-
* {% filter upper %}
|
17 |
-
* This text becomes uppercase
|
18 |
-
* {% endfilter %}
|
19 |
-
* </pre>
|
20 |
-
*/
|
21 |
-
class Twig_TokenParser_Filter extends Twig_TokenParser
|
22 |
-
{
|
23 |
-
/**
|
24 |
-
* Parses a token and returns a node.
|
25 |
-
*
|
26 |
-
* @param Twig_Token $token A Twig_Token instance
|
27 |
-
*
|
28 |
-
* @return Twig_NodeInterface A Twig_NodeInterface instance
|
29 |
-
*/
|
30 |
-
public function parse(Twig_Token $token)
|
31 |
-
{
|
32 |
-
$name = $this->parser->getVarName();
|
33 |
-
$ref = new Twig_Node_Expression_BlockReference(new Twig_Node_Expression_Constant($name, $token->getLine()), true, $token->getLine(), $this->getTag());
|
34 |
-
|
35 |
-
$filter = $this->parser->getExpressionParser()->parseFilterExpressionRaw($ref, $this->getTag());
|
36 |
-
$this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
|
37 |
-
|
38 |
-
$body = $this->parser->subparse(array($this, 'decideBlockEnd'), true);
|
39 |
-
$this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
|
40 |
-
|
41 |
-
$block = new Twig_Node_Block($name, $body, $token->getLine());
|
42 |
-
$this->parser->setBlock($name, $block);
|
43 |
-
|
44 |
-
return new Twig_Node_Print($filter, $token->getLine(), $this->getTag());
|
45 |
-
}
|
46 |
-
|
47 |
-
public function decideBlockEnd(Twig_Token $token)
|
48 |
-
{
|
49 |
-
return $token->test('endfilter');
|
50 |
-
}
|
51 |
-
|
52 |
-
/**
|
53 |
-
* Gets the tag name associated with this token parser.
|
54 |
-
*
|
55 |
-
* @return string The tag name
|
56 |
-
*/
|
57 |
-
public function getTag()
|
58 |
-
{
|
59 |
-
return 'filter';
|
60 |
-
}
|
61 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2009 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Filters a section of a template by applying filters.
|
14 |
+
*
|
15 |
+
* <pre>
|
16 |
+
* {% filter upper %}
|
17 |
+
* This text becomes uppercase
|
18 |
+
* {% endfilter %}
|
19 |
+
* </pre>
|
20 |
+
*/
|
21 |
+
class Twig_TokenParser_Filter extends Twig_TokenParser
|
22 |
+
{
|
23 |
+
/**
|
24 |
+
* Parses a token and returns a node.
|
25 |
+
*
|
26 |
+
* @param Twig_Token $token A Twig_Token instance
|
27 |
+
*
|
28 |
+
* @return Twig_NodeInterface A Twig_NodeInterface instance
|
29 |
+
*/
|
30 |
+
public function parse(Twig_Token $token)
|
31 |
+
{
|
32 |
+
$name = $this->parser->getVarName();
|
33 |
+
$ref = new Twig_Node_Expression_BlockReference(new Twig_Node_Expression_Constant($name, $token->getLine()), true, $token->getLine(), $this->getTag());
|
34 |
+
|
35 |
+
$filter = $this->parser->getExpressionParser()->parseFilterExpressionRaw($ref, $this->getTag());
|
36 |
+
$this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
|
37 |
+
|
38 |
+
$body = $this->parser->subparse(array($this, 'decideBlockEnd'), true);
|
39 |
+
$this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
|
40 |
+
|
41 |
+
$block = new Twig_Node_Block($name, $body, $token->getLine());
|
42 |
+
$this->parser->setBlock($name, $block);
|
43 |
+
|
44 |
+
return new Twig_Node_Print($filter, $token->getLine(), $this->getTag());
|
45 |
+
}
|
46 |
+
|
47 |
+
public function decideBlockEnd(Twig_Token $token)
|
48 |
+
{
|
49 |
+
return $token->test('endfilter');
|
50 |
+
}
|
51 |
+
|
52 |
+
/**
|
53 |
+
* Gets the tag name associated with this token parser.
|
54 |
+
*
|
55 |
+
* @return string The tag name
|
56 |
+
*/
|
57 |
+
public function getTag()
|
58 |
+
{
|
59 |
+
return 'filter';
|
60 |
+
}
|
61 |
+
}
|
classes/Twig/TokenParser/Flush.php
CHANGED
@@ -1,42 +1,42 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2011 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
/**
|
13 |
-
* Flushes the output to the client.
|
14 |
-
*
|
15 |
-
* @see flush()
|
16 |
-
*/
|
17 |
-
class Twig_TokenParser_Flush extends Twig_TokenParser
|
18 |
-
{
|
19 |
-
/**
|
20 |
-
* Parses a token and returns a node.
|
21 |
-
*
|
22 |
-
* @param Twig_Token $token A Twig_Token instance
|
23 |
-
*
|
24 |
-
* @return Twig_NodeInterface A Twig_NodeInterface instance
|
25 |
-
*/
|
26 |
-
public function parse(Twig_Token $token)
|
27 |
-
{
|
28 |
-
$this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
|
29 |
-
|
30 |
-
return new Twig_Node_Flush($token->getLine(), $this->getTag());
|
31 |
-
}
|
32 |
-
|
33 |
-
/**
|
34 |
-
* Gets the tag name associated with this token parser.
|
35 |
-
*
|
36 |
-
* @return string The tag name
|
37 |
-
*/
|
38 |
-
public function getTag()
|
39 |
-
{
|
40 |
-
return 'flush';
|
41 |
-
}
|
42 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2011 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Flushes the output to the client.
|
14 |
+
*
|
15 |
+
* @see flush()
|
16 |
+
*/
|
17 |
+
class Twig_TokenParser_Flush extends Twig_TokenParser
|
18 |
+
{
|
19 |
+
/**
|
20 |
+
* Parses a token and returns a node.
|
21 |
+
*
|
22 |
+
* @param Twig_Token $token A Twig_Token instance
|
23 |
+
*
|
24 |
+
* @return Twig_NodeInterface A Twig_NodeInterface instance
|
25 |
+
*/
|
26 |
+
public function parse(Twig_Token $token)
|
27 |
+
{
|
28 |
+
$this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
|
29 |
+
|
30 |
+
return new Twig_Node_Flush($token->getLine(), $this->getTag());
|
31 |
+
}
|
32 |
+
|
33 |
+
/**
|
34 |
+
* Gets the tag name associated with this token parser.
|
35 |
+
*
|
36 |
+
* @return string The tag name
|
37 |
+
*/
|
38 |
+
public function getTag()
|
39 |
+
{
|
40 |
+
return 'flush';
|
41 |
+
}
|
42 |
+
}
|
classes/Twig/TokenParser/For.php
CHANGED
@@ -1,135 +1,135 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2009 Fabien Potencier
|
7 |
-
* (c) 2009 Armin Ronacher
|
8 |
-
*
|
9 |
-
* For the full copyright and license information, please view the LICENSE
|
10 |
-
* file that was distributed with this source code.
|
11 |
-
*/
|
12 |
-
|
13 |
-
/**
|
14 |
-
* Loops over each item of a sequence.
|
15 |
-
*
|
16 |
-
* <pre>
|
17 |
-
* <ul>
|
18 |
-
* {% for user in users %}
|
19 |
-
* <li>{{ user.username|e }}</li>
|
20 |
-
* {% endfor %}
|
21 |
-
* </ul>
|
22 |
-
* </pre>
|
23 |
-
*/
|
24 |
-
class Twig_TokenParser_For extends Twig_TokenParser
|
25 |
-
{
|
26 |
-
/**
|
27 |
-
* Parses a token and returns a node.
|
28 |
-
*
|
29 |
-
* @param Twig_Token $token A Twig_Token instance
|
30 |
-
*
|
31 |
-
* @return Twig_NodeInterface A Twig_NodeInterface instance
|
32 |
-
*/
|
33 |
-
public function parse(Twig_Token $token)
|
34 |
-
{
|
35 |
-
$lineno = $token->getLine();
|
36 |
-
$stream = $this->parser->getStream();
|
37 |
-
$targets = $this->parser->getExpressionParser()->parseAssignmentExpression();
|
38 |
-
$stream->expect(Twig_Token::OPERATOR_TYPE, 'in');
|
39 |
-
$seq = $this->parser->getExpressionParser()->parseExpression();
|
40 |
-
|
41 |
-
$ifexpr = null;
|
42 |
-
if ($stream->nextIf(Twig_Token::NAME_TYPE, 'if')) {
|
43 |
-
$ifexpr = $this->parser->getExpressionParser()->parseExpression();
|
44 |
-
}
|
45 |
-
|
46 |
-
$stream->expect(Twig_Token::BLOCK_END_TYPE);
|
47 |
-
$body = $this->parser->subparse(array($this, 'decideForFork'));
|
48 |
-
if ($stream->next()->getValue() == 'else') {
|
49 |
-
$stream->expect(Twig_Token::BLOCK_END_TYPE);
|
50 |
-
$else = $this->parser->subparse(array($this, 'decideForEnd'), true);
|
51 |
-
} else {
|
52 |
-
$else = null;
|
53 |
-
}
|
54 |
-
$stream->expect(Twig_Token::BLOCK_END_TYPE);
|
55 |
-
|
56 |
-
if (count($targets) > 1) {
|
57 |
-
$keyTarget = $targets->getNode(0);
|
58 |
-
$keyTarget = new Twig_Node_Expression_AssignName($keyTarget->getAttribute('name'), $keyTarget->getLine());
|
59 |
-
$valueTarget = $targets->getNode(1);
|
60 |
-
$valueTarget = new Twig_Node_Expression_AssignName($valueTarget->getAttribute('name'), $valueTarget->getLine());
|
61 |
-
} else {
|
62 |
-
$keyTarget = new Twig_Node_Expression_AssignName('_key', $lineno);
|
63 |
-
$valueTarget = $targets->getNode(0);
|
64 |
-
$valueTarget = new Twig_Node_Expression_AssignName($valueTarget->getAttribute('name'), $valueTarget->getLine());
|
65 |
-
}
|
66 |
-
|
67 |
-
if ($ifexpr) {
|
68 |
-
$this->checkLoopUsageCondition($stream, $ifexpr);
|
69 |
-
$this->checkLoopUsageBody($stream, $body);
|
70 |
-
}
|
71 |
-
|
72 |
-
return new Twig_Node_For($keyTarget, $valueTarget, $seq, $ifexpr, $body, $else, $lineno, $this->getTag());
|
73 |
-
}
|
74 |
-
|
75 |
-
public function decideForFork(Twig_Token $token)
|
76 |
-
{
|
77 |
-
return $token->test(array('else', 'endfor'));
|
78 |
-
}
|
79 |
-
|
80 |
-
public function decideForEnd(Twig_Token $token)
|
81 |
-
{
|
82 |
-
return $token->test('endfor');
|
83 |
-
}
|
84 |
-
|
85 |
-
// the loop variable cannot be used in the condition
|
86 |
-
protected function checkLoopUsageCondition(Twig_TokenStream $stream, Twig_NodeInterface $node)
|
87 |
-
{
|
88 |
-
if ($node instanceof Twig_Node_Expression_GetAttr && $node->getNode('node') instanceof Twig_Node_Expression_Name && 'loop' == $node->getNode('node')->getAttribute('name')) {
|
89 |
-
throw new Twig_Error_Syntax('The "loop" variable cannot be used in a looping condition', $node->getLine(), $stream->getFilename());
|
90 |
-
}
|
91 |
-
|
92 |
-
foreach ($node as $n) {
|
93 |
-
if (!$n) {
|
94 |
-
continue;
|
95 |
-
}
|
96 |
-
|
97 |
-
$this->checkLoopUsageCondition($stream, $n);
|
98 |
-
}
|
99 |
-
}
|
100 |
-
|
101 |
-
// check usage of non-defined loop-items
|
102 |
-
// it does not catch all problems (for instance when a for is included into another or when the variable is used in an include)
|
103 |
-
protected function checkLoopUsageBody(Twig_TokenStream $stream, Twig_NodeInterface $node)
|
104 |
-
{
|
105 |
-
if ($node instanceof Twig_Node_Expression_GetAttr && $node->getNode('node') instanceof Twig_Node_Expression_Name && 'loop' == $node->getNode('node')->getAttribute('name')) {
|
106 |
-
$attribute = $node->getNode('attribute');
|
107 |
-
if ($attribute instanceof Twig_Node_Expression_Constant && in_array($attribute->getAttribute('value'), array('length', 'revindex0', 'revindex', 'last'))) {
|
108 |
-
throw new Twig_Error_Syntax(sprintf('The "loop.%s" variable is not defined when looping with a condition', $attribute->getAttribute('value')), $node->getLine(), $stream->getFilename());
|
109 |
-
}
|
110 |
-
}
|
111 |
-
|
112 |
-
// should check for parent.loop.XXX usage
|
113 |
-
if ($node instanceof Twig_Node_For) {
|
114 |
-
return;
|
115 |
-
}
|
116 |
-
|
117 |
-
foreach ($node as $n) {
|
118 |
-
if (!$n) {
|
119 |
-
continue;
|
120 |
-
}
|
121 |
-
|
122 |
-
$this->checkLoopUsageBody($stream, $n);
|
123 |
-
}
|
124 |
-
}
|
125 |
-
|
126 |
-
/**
|
127 |
-
* Gets the tag name associated with this token parser.
|
128 |
-
*
|
129 |
-
* @return string The tag name
|
130 |
-
*/
|
131 |
-
public function getTag()
|
132 |
-
{
|
133 |
-
return 'for';
|
134 |
-
}
|
135 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2009 Fabien Potencier
|
7 |
+
* (c) 2009 Armin Ronacher
|
8 |
+
*
|
9 |
+
* For the full copyright and license information, please view the LICENSE
|
10 |
+
* file that was distributed with this source code.
|
11 |
+
*/
|
12 |
+
|
13 |
+
/**
|
14 |
+
* Loops over each item of a sequence.
|
15 |
+
*
|
16 |
+
* <pre>
|
17 |
+
* <ul>
|
18 |
+
* {% for user in users %}
|
19 |
+
* <li>{{ user.username|e }}</li>
|
20 |
+
* {% endfor %}
|
21 |
+
* </ul>
|
22 |
+
* </pre>
|
23 |
+
*/
|
24 |
+
class Twig_TokenParser_For extends Twig_TokenParser
|
25 |
+
{
|
26 |
+
/**
|
27 |
+
* Parses a token and returns a node.
|
28 |
+
*
|
29 |
+
* @param Twig_Token $token A Twig_Token instance
|
30 |
+
*
|
31 |
+
* @return Twig_NodeInterface A Twig_NodeInterface instance
|
32 |
+
*/
|
33 |
+
public function parse(Twig_Token $token)
|
34 |
+
{
|
35 |
+
$lineno = $token->getLine();
|
36 |
+
$stream = $this->parser->getStream();
|
37 |
+
$targets = $this->parser->getExpressionParser()->parseAssignmentExpression();
|
38 |
+
$stream->expect(Twig_Token::OPERATOR_TYPE, 'in');
|
39 |
+
$seq = $this->parser->getExpressionParser()->parseExpression();
|
40 |
+
|
41 |
+
$ifexpr = null;
|
42 |
+
if ($stream->nextIf(Twig_Token::NAME_TYPE, 'if')) {
|
43 |
+
$ifexpr = $this->parser->getExpressionParser()->parseExpression();
|
44 |
+
}
|
45 |
+
|
46 |
+
$stream->expect(Twig_Token::BLOCK_END_TYPE);
|
47 |
+
$body = $this->parser->subparse(array($this, 'decideForFork'));
|
48 |
+
if ($stream->next()->getValue() == 'else') {
|
49 |
+
$stream->expect(Twig_Token::BLOCK_END_TYPE);
|
50 |
+
$else = $this->parser->subparse(array($this, 'decideForEnd'), true);
|
51 |
+
} else {
|
52 |
+
$else = null;
|
53 |
+
}
|
54 |
+
$stream->expect(Twig_Token::BLOCK_END_TYPE);
|
55 |
+
|
56 |
+
if (count($targets) > 1) {
|
57 |
+
$keyTarget = $targets->getNode(0);
|
58 |
+
$keyTarget = new Twig_Node_Expression_AssignName($keyTarget->getAttribute('name'), $keyTarget->getLine());
|
59 |
+
$valueTarget = $targets->getNode(1);
|
60 |
+
$valueTarget = new Twig_Node_Expression_AssignName($valueTarget->getAttribute('name'), $valueTarget->getLine());
|
61 |
+
} else {
|
62 |
+
$keyTarget = new Twig_Node_Expression_AssignName('_key', $lineno);
|
63 |
+
$valueTarget = $targets->getNode(0);
|
64 |
+
$valueTarget = new Twig_Node_Expression_AssignName($valueTarget->getAttribute('name'), $valueTarget->getLine());
|
65 |
+
}
|
66 |
+
|
67 |
+
if ($ifexpr) {
|
68 |
+
$this->checkLoopUsageCondition($stream, $ifexpr);
|
69 |
+
$this->checkLoopUsageBody($stream, $body);
|
70 |
+
}
|
71 |
+
|
72 |
+
return new Twig_Node_For($keyTarget, $valueTarget, $seq, $ifexpr, $body, $else, $lineno, $this->getTag());
|
73 |
+
}
|
74 |
+
|
75 |
+
public function decideForFork(Twig_Token $token)
|
76 |
+
{
|
77 |
+
return $token->test(array('else', 'endfor'));
|
78 |
+
}
|
79 |
+
|
80 |
+
public function decideForEnd(Twig_Token $token)
|
81 |
+
{
|
82 |
+
return $token->test('endfor');
|
83 |
+
}
|
84 |
+
|
85 |
+
// the loop variable cannot be used in the condition
|
86 |
+
protected function checkLoopUsageCondition(Twig_TokenStream $stream, Twig_NodeInterface $node)
|
87 |
+
{
|
88 |
+
if ($node instanceof Twig_Node_Expression_GetAttr && $node->getNode('node') instanceof Twig_Node_Expression_Name && 'loop' == $node->getNode('node')->getAttribute('name')) {
|
89 |
+
throw new Twig_Error_Syntax('The "loop" variable cannot be used in a looping condition', $node->getLine(), $stream->getFilename());
|
90 |
+
}
|
91 |
+
|
92 |
+
foreach ($node as $n) {
|
93 |
+
if (!$n) {
|
94 |
+
continue;
|
95 |
+
}
|
96 |
+
|
97 |
+
$this->checkLoopUsageCondition($stream, $n);
|
98 |
+
}
|
99 |
+
}
|
100 |
+
|
101 |
+
// check usage of non-defined loop-items
|
102 |
+
// it does not catch all problems (for instance when a for is included into another or when the variable is used in an include)
|
103 |
+
protected function checkLoopUsageBody(Twig_TokenStream $stream, Twig_NodeInterface $node)
|
104 |
+
{
|
105 |
+
if ($node instanceof Twig_Node_Expression_GetAttr && $node->getNode('node') instanceof Twig_Node_Expression_Name && 'loop' == $node->getNode('node')->getAttribute('name')) {
|
106 |
+
$attribute = $node->getNode('attribute');
|
107 |
+
if ($attribute instanceof Twig_Node_Expression_Constant && in_array($attribute->getAttribute('value'), array('length', 'revindex0', 'revindex', 'last'))) {
|
108 |
+
throw new Twig_Error_Syntax(sprintf('The "loop.%s" variable is not defined when looping with a condition', $attribute->getAttribute('value')), $node->getLine(), $stream->getFilename());
|
109 |
+
}
|
110 |
+
}
|
111 |
+
|
112 |
+
// should check for parent.loop.XXX usage
|
113 |
+
if ($node instanceof Twig_Node_For) {
|
114 |
+
return;
|
115 |
+
}
|
116 |
+
|
117 |
+
foreach ($node as $n) {
|
118 |
+
if (!$n) {
|
119 |
+
continue;
|
120 |
+
}
|
121 |
+
|
122 |
+
$this->checkLoopUsageBody($stream, $n);
|
123 |
+
}
|
124 |
+
}
|
125 |
+
|
126 |
+
/**
|
127 |
+
* Gets the tag name associated with this token parser.
|
128 |
+
*
|
129 |
+
* @return string The tag name
|
130 |
+
*/
|
131 |
+
public function getTag()
|
132 |
+
{
|
133 |
+
return 'for';
|
134 |
+
}
|
135 |
+
}
|
classes/Twig/TokenParser/From.php
CHANGED
@@ -1,70 +1,70 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2010 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
/**
|
13 |
-
* Imports macros.
|
14 |
-
*
|
15 |
-
* <pre>
|
16 |
-
* {% from 'forms.html' import forms %}
|
17 |
-
* </pre>
|
18 |
-
*/
|
19 |
-
class Twig_TokenParser_From extends Twig_TokenParser
|
20 |
-
{
|
21 |
-
/**
|
22 |
-
* Parses a token and returns a node.
|
23 |
-
*
|
24 |
-
* @param Twig_Token $token A Twig_Token instance
|
25 |
-
*
|
26 |
-
* @return Twig_NodeInterface A Twig_NodeInterface instance
|
27 |
-
*/
|
28 |
-
public function parse(Twig_Token $token)
|
29 |
-
{
|
30 |
-
$macro = $this->parser->getExpressionParser()->parseExpression();
|
31 |
-
$stream = $this->parser->getStream();
|
32 |
-
$stream->expect('import');
|
33 |
-
|
34 |
-
$targets = array();
|
35 |
-
do {
|
36 |
-
$name = $stream->expect(Twig_Token::NAME_TYPE)->getValue();
|
37 |
-
|
38 |
-
$alias = $name;
|
39 |
-
if ($stream->nextIf('as')) {
|
40 |
-
$alias = $stream->expect(Twig_Token::NAME_TYPE)->getValue();
|
41 |
-
}
|
42 |
-
|
43 |
-
$targets[$name] = $alias;
|
44 |
-
|
45 |
-
if (!$stream->nextIf(Twig_Token::PUNCTUATION_TYPE, ',')) {
|
46 |
-
break;
|
47 |
-
}
|
48 |
-
} while (true);
|
49 |
-
|
50 |
-
$stream->expect(Twig_Token::BLOCK_END_TYPE);
|
51 |
-
|
52 |
-
$node = new Twig_Node_Import($macro, new Twig_Node_Expression_AssignName($this->parser->getVarName(), $token->getLine()), $token->getLine(), $this->getTag());
|
53 |
-
|
54 |
-
foreach ($targets as $name => $alias) {
|
55 |
-
$this->parser->addImportedSymbol('function', $alias, 'get'.$name, $node->getNode('var'));
|
56 |
-
}
|
57 |
-
|
58 |
-
return $node;
|
59 |
-
}
|
60 |
-
|
61 |
-
/**
|
62 |
-
* Gets the tag name associated with this token parser.
|
63 |
-
*
|
64 |
-
* @return string The tag name
|
65 |
-
*/
|
66 |
-
public function getTag()
|
67 |
-
{
|
68 |
-
return 'from';
|
69 |
-
}
|
70 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2010 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Imports macros.
|
14 |
+
*
|
15 |
+
* <pre>
|
16 |
+
* {% from 'forms.html' import forms %}
|
17 |
+
* </pre>
|
18 |
+
*/
|
19 |
+
class Twig_TokenParser_From extends Twig_TokenParser
|
20 |
+
{
|
21 |
+
/**
|
22 |
+
* Parses a token and returns a node.
|
23 |
+
*
|
24 |
+
* @param Twig_Token $token A Twig_Token instance
|
25 |
+
*
|
26 |
+
* @return Twig_NodeInterface A Twig_NodeInterface instance
|
27 |
+
*/
|
28 |
+
public function parse(Twig_Token $token)
|
29 |
+
{
|
30 |
+
$macro = $this->parser->getExpressionParser()->parseExpression();
|
31 |
+
$stream = $this->parser->getStream();
|
32 |
+
$stream->expect('import');
|
33 |
+
|
34 |
+
$targets = array();
|
35 |
+
do {
|
36 |
+
$name = $stream->expect(Twig_Token::NAME_TYPE)->getValue();
|
37 |
+
|
38 |
+
$alias = $name;
|
39 |
+
if ($stream->nextIf('as')) {
|
40 |
+
$alias = $stream->expect(Twig_Token::NAME_TYPE)->getValue();
|
41 |
+
}
|
42 |
+
|
43 |
+
$targets[$name] = $alias;
|
44 |
+
|
45 |
+
if (!$stream->nextIf(Twig_Token::PUNCTUATION_TYPE, ',')) {
|
46 |
+
break;
|
47 |
+
}
|
48 |
+
} while (true);
|
49 |
+
|
50 |
+
$stream->expect(Twig_Token::BLOCK_END_TYPE);
|
51 |
+
|
52 |
+
$node = new Twig_Node_Import($macro, new Twig_Node_Expression_AssignName($this->parser->getVarName(), $token->getLine()), $token->getLine(), $this->getTag());
|
53 |
+
|
54 |
+
foreach ($targets as $name => $alias) {
|
55 |
+
$this->parser->addImportedSymbol('function', $alias, 'get'.$name, $node->getNode('var'));
|
56 |
+
}
|
57 |
+
|
58 |
+
return $node;
|
59 |
+
}
|
60 |
+
|
61 |
+
/**
|
62 |
+
* Gets the tag name associated with this token parser.
|
63 |
+
*
|
64 |
+
* @return string The tag name
|
65 |
+
*/
|
66 |
+
public function getTag()
|
67 |
+
{
|
68 |
+
return 'from';
|
69 |
+
}
|
70 |
+
}
|
classes/Twig/TokenParser/If.php
CHANGED
@@ -1,94 +1,94 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2009 Fabien Potencier
|
7 |
-
* (c) 2009 Armin Ronacher
|
8 |
-
*
|
9 |
-
* For the full copyright and license information, please view the LICENSE
|
10 |
-
* file that was distributed with this source code.
|
11 |
-
*/
|
12 |
-
|
13 |
-
/**
|
14 |
-
* Tests a condition.
|
15 |
-
*
|
16 |
-
* <pre>
|
17 |
-
* {% if users %}
|
18 |
-
* <ul>
|
19 |
-
* {% for user in users %}
|
20 |
-
* <li>{{ user.username|e }}</li>
|
21 |
-
* {% endfor %}
|
22 |
-
* </ul>
|
23 |
-
* {% endif %}
|
24 |
-
* </pre>
|
25 |
-
*/
|
26 |
-
class Twig_TokenParser_If extends Twig_TokenParser
|
27 |
-
{
|
28 |
-
/**
|
29 |
-
* Parses a token and returns a node.
|
30 |
-
*
|
31 |
-
* @param Twig_Token $token A Twig_Token instance
|
32 |
-
*
|
33 |
-
* @return Twig_NodeInterface A Twig_NodeInterface instance
|
34 |
-
*/
|
35 |
-
public function parse(Twig_Token $token)
|
36 |
-
{
|
37 |
-
$lineno = $token->getLine();
|
38 |
-
$expr = $this->parser->getExpressionParser()->parseExpression();
|
39 |
-
$stream = $this->parser->getStream();
|
40 |
-
$stream->expect(Twig_Token::BLOCK_END_TYPE);
|
41 |
-
$body = $this->parser->subparse(array($this, 'decideIfFork'));
|
42 |
-
$tests = array($expr, $body);
|
43 |
-
$else = null;
|
44 |
-
|
45 |
-
$end = false;
|
46 |
-
while (!$end) {
|
47 |
-
switch ($stream->next()->getValue()) {
|
48 |
-
case 'else':
|
49 |
-
$stream->expect(Twig_Token::BLOCK_END_TYPE);
|
50 |
-
$else = $this->parser->subparse(array($this, 'decideIfEnd'));
|
51 |
-
break;
|
52 |
-
|
53 |
-
case 'elseif':
|
54 |
-
$expr = $this->parser->getExpressionParser()->parseExpression();
|
55 |
-
$stream->expect(Twig_Token::BLOCK_END_TYPE);
|
56 |
-
$body = $this->parser->subparse(array($this, 'decideIfFork'));
|
57 |
-
$tests[] = $expr;
|
58 |
-
$tests[] = $body;
|
59 |
-
break;
|
60 |
-
|
61 |
-
case 'endif':
|
62 |
-
$end = true;
|
63 |
-
break;
|
64 |
-
|
65 |
-
default:
|
66 |
-
throw new Twig_Error_Syntax(sprintf('Unexpected end of template. Twig was looking for the following tags "else", "elseif", or "endif" to close the "if" block started at line %d)', $lineno), $stream->getCurrent()->getLine(), $stream->getFilename());
|
67 |
-
}
|
68 |
-
}
|
69 |
-
|
70 |
-
$stream->expect(Twig_Token::BLOCK_END_TYPE);
|
71 |
-
|
72 |
-
return new Twig_Node_If(new Twig_Node($tests), $else, $lineno, $this->getTag());
|
73 |
-
}
|
74 |
-
|
75 |
-
public function decideIfFork(Twig_Token $token)
|
76 |
-
{
|
77 |
-
return $token->test(array('elseif', 'else', 'endif'));
|
78 |
-
}
|
79 |
-
|
80 |
-
public function decideIfEnd(Twig_Token $token)
|
81 |
-
{
|
82 |
-
return $token->test(array('endif'));
|
83 |
-
}
|
84 |
-
|
85 |
-
/**
|
86 |
-
* Gets the tag name associated with this token parser.
|
87 |
-
*
|
88 |
-
* @return string The tag name
|
89 |
-
*/
|
90 |
-
public function getTag()
|
91 |
-
{
|
92 |
-
return 'if';
|
93 |
-
}
|
94 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2009 Fabien Potencier
|
7 |
+
* (c) 2009 Armin Ronacher
|
8 |
+
*
|
9 |
+
* For the full copyright and license information, please view the LICENSE
|
10 |
+
* file that was distributed with this source code.
|
11 |
+
*/
|
12 |
+
|
13 |
+
/**
|
14 |
+
* Tests a condition.
|
15 |
+
*
|
16 |
+
* <pre>
|
17 |
+
* {% if users %}
|
18 |
+
* <ul>
|
19 |
+
* {% for user in users %}
|
20 |
+
* <li>{{ user.username|e }}</li>
|
21 |
+
* {% endfor %}
|
22 |
+
* </ul>
|
23 |
+
* {% endif %}
|
24 |
+
* </pre>
|
25 |
+
*/
|
26 |
+
class Twig_TokenParser_If extends Twig_TokenParser
|
27 |
+
{
|
28 |
+
/**
|
29 |
+
* Parses a token and returns a node.
|
30 |
+
*
|
31 |
+
* @param Twig_Token $token A Twig_Token instance
|
32 |
+
*
|
33 |
+
* @return Twig_NodeInterface A Twig_NodeInterface instance
|
34 |
+
*/
|
35 |
+
public function parse(Twig_Token $token)
|
36 |
+
{
|
37 |
+
$lineno = $token->getLine();
|
38 |
+
$expr = $this->parser->getExpressionParser()->parseExpression();
|
39 |
+
$stream = $this->parser->getStream();
|
40 |
+
$stream->expect(Twig_Token::BLOCK_END_TYPE);
|
41 |
+
$body = $this->parser->subparse(array($this, 'decideIfFork'));
|
42 |
+
$tests = array($expr, $body);
|
43 |
+
$else = null;
|
44 |
+
|
45 |
+
$end = false;
|
46 |
+
while (!$end) {
|
47 |
+
switch ($stream->next()->getValue()) {
|
48 |
+
case 'else':
|
49 |
+
$stream->expect(Twig_Token::BLOCK_END_TYPE);
|
50 |
+
$else = $this->parser->subparse(array($this, 'decideIfEnd'));
|
51 |
+
break;
|
52 |
+
|
53 |
+
case 'elseif':
|
54 |
+
$expr = $this->parser->getExpressionParser()->parseExpression();
|
55 |
+
$stream->expect(Twig_Token::BLOCK_END_TYPE);
|
56 |
+
$body = $this->parser->subparse(array($this, 'decideIfFork'));
|
57 |
+
$tests[] = $expr;
|
58 |
+
$tests[] = $body;
|
59 |
+
break;
|
60 |
+
|
61 |
+
case 'endif':
|
62 |
+
$end = true;
|
63 |
+
break;
|
64 |
+
|
65 |
+
default:
|
66 |
+
throw new Twig_Error_Syntax(sprintf('Unexpected end of template. Twig was looking for the following tags "else", "elseif", or "endif" to close the "if" block started at line %d)', $lineno), $stream->getCurrent()->getLine(), $stream->getFilename());
|
67 |
+
}
|
68 |
+
}
|
69 |
+
|
70 |
+
$stream->expect(Twig_Token::BLOCK_END_TYPE);
|
71 |
+
|
72 |
+
return new Twig_Node_If(new Twig_Node($tests), $else, $lineno, $this->getTag());
|
73 |
+
}
|
74 |
+
|
75 |
+
public function decideIfFork(Twig_Token $token)
|
76 |
+
{
|
77 |
+
return $token->test(array('elseif', 'else', 'endif'));
|
78 |
+
}
|
79 |
+
|
80 |
+
public function decideIfEnd(Twig_Token $token)
|
81 |
+
{
|
82 |
+
return $token->test(array('endif'));
|
83 |
+
}
|
84 |
+
|
85 |
+
/**
|
86 |
+
* Gets the tag name associated with this token parser.
|
87 |
+
*
|
88 |
+
* @return string The tag name
|
89 |
+
*/
|
90 |
+
public function getTag()
|
91 |
+
{
|
92 |
+
return 'if';
|
93 |
+
}
|
94 |
+
}
|
classes/Twig/TokenParser/Import.php
CHANGED
@@ -1,49 +1,49 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2009 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
/**
|
13 |
-
* Imports macros.
|
14 |
-
*
|
15 |
-
* <pre>
|
16 |
-
* {% import 'forms.html' as forms %}
|
17 |
-
* </pre>
|
18 |
-
*/
|
19 |
-
class Twig_TokenParser_Import extends Twig_TokenParser
|
20 |
-
{
|
21 |
-
/**
|
22 |
-
* Parses a token and returns a node.
|
23 |
-
*
|
24 |
-
* @param Twig_Token $token A Twig_Token instance
|
25 |
-
*
|
26 |
-
* @return Twig_NodeInterface A Twig_NodeInterface instance
|
27 |
-
*/
|
28 |
-
public function parse(Twig_Token $token)
|
29 |
-
{
|
30 |
-
$macro = $this->parser->getExpressionParser()->parseExpression();
|
31 |
-
$this->parser->getStream()->expect('as');
|
32 |
-
$var = new Twig_Node_Expression_AssignName($this->parser->getStream()->expect(Twig_Token::NAME_TYPE)->getValue(), $token->getLine());
|
33 |
-
$this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
|
34 |
-
|
35 |
-
$this->parser->addImportedSymbol('template', $var->getAttribute('name'));
|
36 |
-
|
37 |
-
return new Twig_Node_Import($macro, $var, $token->getLine(), $this->getTag());
|
38 |
-
}
|
39 |
-
|
40 |
-
/**
|
41 |
-
* Gets the tag name associated with this token parser.
|
42 |
-
*
|
43 |
-
* @return string The tag name
|
44 |
-
*/
|
45 |
-
public function getTag()
|
46 |
-
{
|
47 |
-
return 'import';
|
48 |
-
}
|
49 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2009 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Imports macros.
|
14 |
+
*
|
15 |
+
* <pre>
|
16 |
+
* {% import 'forms.html' as forms %}
|
17 |
+
* </pre>
|
18 |
+
*/
|
19 |
+
class Twig_TokenParser_Import extends Twig_TokenParser
|
20 |
+
{
|
21 |
+
/**
|
22 |
+
* Parses a token and returns a node.
|
23 |
+
*
|
24 |
+
* @param Twig_Token $token A Twig_Token instance
|
25 |
+
*
|
26 |
+
* @return Twig_NodeInterface A Twig_NodeInterface instance
|
27 |
+
*/
|
28 |
+
public function parse(Twig_Token $token)
|
29 |
+
{
|
30 |
+
$macro = $this->parser->getExpressionParser()->parseExpression();
|
31 |
+
$this->parser->getStream()->expect('as');
|
32 |
+
$var = new Twig_Node_Expression_AssignName($this->parser->getStream()->expect(Twig_Token::NAME_TYPE)->getValue(), $token->getLine());
|
33 |
+
$this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
|
34 |
+
|
35 |
+
$this->parser->addImportedSymbol('template', $var->getAttribute('name'));
|
36 |
+
|
37 |
+
return new Twig_Node_Import($macro, $var, $token->getLine(), $this->getTag());
|
38 |
+
}
|
39 |
+
|
40 |
+
/**
|
41 |
+
* Gets the tag name associated with this token parser.
|
42 |
+
*
|
43 |
+
* @return string The tag name
|
44 |
+
*/
|
45 |
+
public function getTag()
|
46 |
+
{
|
47 |
+
return 'import';
|
48 |
+
}
|
49 |
+
}
|
classes/Twig/TokenParser/Include.php
CHANGED
@@ -1,75 +1,75 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2009 Fabien Potencier
|
7 |
-
* (c) 2009 Armin Ronacher
|
8 |
-
*
|
9 |
-
* For the full copyright and license information, please view the LICENSE
|
10 |
-
* file that was distributed with this source code.
|
11 |
-
*/
|
12 |
-
|
13 |
-
/**
|
14 |
-
* Includes a template.
|
15 |
-
*
|
16 |
-
* <pre>
|
17 |
-
* {% include 'header.html' %}
|
18 |
-
* Body
|
19 |
-
* {% include 'footer.html' %}
|
20 |
-
* </pre>
|
21 |
-
*/
|
22 |
-
class Twig_TokenParser_Include extends Twig_TokenParser
|
23 |
-
{
|
24 |
-
/**
|
25 |
-
* Parses a token and returns a node.
|
26 |
-
*
|
27 |
-
* @param Twig_Token $token A Twig_Token instance
|
28 |
-
*
|
29 |
-
* @return Twig_NodeInterface A Twig_NodeInterface instance
|
30 |
-
*/
|
31 |
-
public function parse(Twig_Token $token)
|
32 |
-
{
|
33 |
-
$expr = $this->parser->getExpressionParser()->parseExpression();
|
34 |
-
|
35 |
-
list($variables, $only, $ignoreMissing) = $this->parseArguments();
|
36 |
-
|
37 |
-
return new Twig_Node_Include($expr, $variables, $only, $ignoreMissing, $token->getLine(), $this->getTag());
|
38 |
-
}
|
39 |
-
|
40 |
-
protected function parseArguments()
|
41 |
-
{
|
42 |
-
$stream = $this->parser->getStream();
|
43 |
-
|
44 |
-
$ignoreMissing = false;
|
45 |
-
if ($stream->nextIf(Twig_Token::NAME_TYPE, 'ignore')) {
|
46 |
-
$stream->expect(Twig_Token::NAME_TYPE, 'missing');
|
47 |
-
|
48 |
-
$ignoreMissing = true;
|
49 |
-
}
|
50 |
-
|
51 |
-
$variables = null;
|
52 |
-
if ($stream->nextIf(Twig_Token::NAME_TYPE, 'with')) {
|
53 |
-
$variables = $this->parser->getExpressionParser()->parseExpression();
|
54 |
-
}
|
55 |
-
|
56 |
-
$only = false;
|
57 |
-
if ($stream->nextIf(Twig_Token::NAME_TYPE, 'only')) {
|
58 |
-
$only = true;
|
59 |
-
}
|
60 |
-
|
61 |
-
$stream->expect(Twig_Token::BLOCK_END_TYPE);
|
62 |
-
|
63 |
-
return array($variables, $only, $ignoreMissing);
|
64 |
-
}
|
65 |
-
|
66 |
-
/**
|
67 |
-
* Gets the tag name associated with this token parser.
|
68 |
-
*
|
69 |
-
* @return string The tag name
|
70 |
-
*/
|
71 |
-
public function getTag()
|
72 |
-
{
|
73 |
-
return 'include';
|
74 |
-
}
|
75 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2009 Fabien Potencier
|
7 |
+
* (c) 2009 Armin Ronacher
|
8 |
+
*
|
9 |
+
* For the full copyright and license information, please view the LICENSE
|
10 |
+
* file that was distributed with this source code.
|
11 |
+
*/
|
12 |
+
|
13 |
+
/**
|
14 |
+
* Includes a template.
|
15 |
+
*
|
16 |
+
* <pre>
|
17 |
+
* {% include 'header.html' %}
|
18 |
+
* Body
|
19 |
+
* {% include 'footer.html' %}
|
20 |
+
* </pre>
|
21 |
+
*/
|
22 |
+
class Twig_TokenParser_Include extends Twig_TokenParser
|
23 |
+
{
|
24 |
+
/**
|
25 |
+
* Parses a token and returns a node.
|
26 |
+
*
|
27 |
+
* @param Twig_Token $token A Twig_Token instance
|
28 |
+
*
|
29 |
+
* @return Twig_NodeInterface A Twig_NodeInterface instance
|
30 |
+
*/
|
31 |
+
public function parse(Twig_Token $token)
|
32 |
+
{
|
33 |
+
$expr = $this->parser->getExpressionParser()->parseExpression();
|
34 |
+
|
35 |
+
list($variables, $only, $ignoreMissing) = $this->parseArguments();
|
36 |
+
|
37 |
+
return new Twig_Node_Include($expr, $variables, $only, $ignoreMissing, $token->getLine(), $this->getTag());
|
38 |
+
}
|
39 |
+
|
40 |
+
protected function parseArguments()
|
41 |
+
{
|
42 |
+
$stream = $this->parser->getStream();
|
43 |
+
|
44 |
+
$ignoreMissing = false;
|
45 |
+
if ($stream->nextIf(Twig_Token::NAME_TYPE, 'ignore')) {
|
46 |
+
$stream->expect(Twig_Token::NAME_TYPE, 'missing');
|
47 |
+
|
48 |
+
$ignoreMissing = true;
|
49 |
+
}
|
50 |
+
|
51 |
+
$variables = null;
|
52 |
+
if ($stream->nextIf(Twig_Token::NAME_TYPE, 'with')) {
|
53 |
+
$variables = $this->parser->getExpressionParser()->parseExpression();
|
54 |
+
}
|
55 |
+
|
56 |
+
$only = false;
|
57 |
+
if ($stream->nextIf(Twig_Token::NAME_TYPE, 'only')) {
|
58 |
+
$only = true;
|
59 |
+
}
|
60 |
+
|
61 |
+
$stream->expect(Twig_Token::BLOCK_END_TYPE);
|
62 |
+
|
63 |
+
return array($variables, $only, $ignoreMissing);
|
64 |
+
}
|
65 |
+
|
66 |
+
/**
|
67 |
+
* Gets the tag name associated with this token parser.
|
68 |
+
*
|
69 |
+
* @return string The tag name
|
70 |
+
*/
|
71 |
+
public function getTag()
|
72 |
+
{
|
73 |
+
return 'include';
|
74 |
+
}
|
75 |
+
}
|
classes/Twig/TokenParser/Macro.php
CHANGED
@@ -1,68 +1,68 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2009 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
/**
|
13 |
-
* Defines a macro.
|
14 |
-
*
|
15 |
-
* <pre>
|
16 |
-
* {% macro input(name, value, type, size) %}
|
17 |
-
* <input type="{{ type|default('text') }}" name="{{ name }}" value="{{ value|e }}" size="{{ size|default(20) }}" />
|
18 |
-
* {% endmacro %}
|
19 |
-
* </pre>
|
20 |
-
*/
|
21 |
-
class Twig_TokenParser_Macro extends Twig_TokenParser
|
22 |
-
{
|
23 |
-
/**
|
24 |
-
* Parses a token and returns a node.
|
25 |
-
*
|
26 |
-
* @param Twig_Token $token A Twig_Token instance
|
27 |
-
*
|
28 |
-
* @return Twig_NodeInterface A Twig_NodeInterface instance
|
29 |
-
*/
|
30 |
-
public function parse(Twig_Token $token)
|
31 |
-
{
|
32 |
-
$lineno = $token->getLine();
|
33 |
-
$stream = $this->parser->getStream();
|
34 |
-
$name = $stream->expect(Twig_Token::NAME_TYPE)->getValue();
|
35 |
-
|
36 |
-
$arguments = $this->parser->getExpressionParser()->parseArguments(true, true);
|
37 |
-
|
38 |
-
$stream->expect(Twig_Token::BLOCK_END_TYPE);
|
39 |
-
$this->parser->pushLocalScope();
|
40 |
-
$body = $this->parser->subparse(array($this, 'decideBlockEnd'), true);
|
41 |
-
if ($token = $stream->nextIf(Twig_Token::NAME_TYPE)) {
|
42 |
-
$value = $token->getValue();
|
43 |
-
|
44 |
-
if ($value != $name) {
|
45 |
-
throw new Twig_Error_Syntax(sprintf("Expected endmacro for macro '$name' (but %s given)", $value), $stream->getCurrent()->getLine(), $stream->getFilename());
|
46 |
-
}
|
47 |
-
}
|
48 |
-
$this->parser->popLocalScope();
|
49 |
-
$stream->expect(Twig_Token::BLOCK_END_TYPE);
|
50 |
-
|
51 |
-
$this->parser->setMacro($name, new Twig_Node_Macro($name, new Twig_Node_Body(array($body)), $arguments, $lineno, $this->getTag()));
|
52 |
-
}
|
53 |
-
|
54 |
-
public function decideBlockEnd(Twig_Token $token)
|
55 |
-
{
|
56 |
-
return $token->test('endmacro');
|
57 |
-
}
|
58 |
-
|
59 |
-
/**
|
60 |
-
* Gets the tag name associated with this token parser.
|
61 |
-
*
|
62 |
-
* @return string The tag name
|
63 |
-
*/
|
64 |
-
public function getTag()
|
65 |
-
{
|
66 |
-
return 'macro';
|
67 |
-
}
|
68 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2009 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Defines a macro.
|
14 |
+
*
|
15 |
+
* <pre>
|
16 |
+
* {% macro input(name, value, type, size) %}
|
17 |
+
* <input type="{{ type|default('text') }}" name="{{ name }}" value="{{ value|e }}" size="{{ size|default(20) }}" />
|
18 |
+
* {% endmacro %}
|
19 |
+
* </pre>
|
20 |
+
*/
|
21 |
+
class Twig_TokenParser_Macro extends Twig_TokenParser
|
22 |
+
{
|
23 |
+
/**
|
24 |
+
* Parses a token and returns a node.
|
25 |
+
*
|
26 |
+
* @param Twig_Token $token A Twig_Token instance
|
27 |
+
*
|
28 |
+
* @return Twig_NodeInterface A Twig_NodeInterface instance
|
29 |
+
*/
|
30 |
+
public function parse(Twig_Token $token)
|
31 |
+
{
|
32 |
+
$lineno = $token->getLine();
|
33 |
+
$stream = $this->parser->getStream();
|
34 |
+
$name = $stream->expect(Twig_Token::NAME_TYPE)->getValue();
|
35 |
+
|
36 |
+
$arguments = $this->parser->getExpressionParser()->parseArguments(true, true);
|
37 |
+
|
38 |
+
$stream->expect(Twig_Token::BLOCK_END_TYPE);
|
39 |
+
$this->parser->pushLocalScope();
|
40 |
+
$body = $this->parser->subparse(array($this, 'decideBlockEnd'), true);
|
41 |
+
if ($token = $stream->nextIf(Twig_Token::NAME_TYPE)) {
|
42 |
+
$value = $token->getValue();
|
43 |
+
|
44 |
+
if ($value != $name) {
|
45 |
+
throw new Twig_Error_Syntax(sprintf("Expected endmacro for macro '$name' (but %s given)", $value), $stream->getCurrent()->getLine(), $stream->getFilename());
|
46 |
+
}
|
47 |
+
}
|
48 |
+
$this->parser->popLocalScope();
|
49 |
+
$stream->expect(Twig_Token::BLOCK_END_TYPE);
|
50 |
+
|
51 |
+
$this->parser->setMacro($name, new Twig_Node_Macro($name, new Twig_Node_Body(array($body)), $arguments, $lineno, $this->getTag()));
|
52 |
+
}
|
53 |
+
|
54 |
+
public function decideBlockEnd(Twig_Token $token)
|
55 |
+
{
|
56 |
+
return $token->test('endmacro');
|
57 |
+
}
|
58 |
+
|
59 |
+
/**
|
60 |
+
* Gets the tag name associated with this token parser.
|
61 |
+
*
|
62 |
+
* @return string The tag name
|
63 |
+
*/
|
64 |
+
public function getTag()
|
65 |
+
{
|
66 |
+
return 'macro';
|
67 |
+
}
|
68 |
+
}
|
classes/Twig/TokenParser/Sandbox.php
CHANGED
@@ -1,68 +1,68 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2010 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
/**
|
13 |
-
* Marks a section of a template as untrusted code that must be evaluated in the sandbox mode.
|
14 |
-
*
|
15 |
-
* <pre>
|
16 |
-
* {% sandbox %}
|
17 |
-
* {% include 'user.html' %}
|
18 |
-
* {% endsandbox %}
|
19 |
-
* </pre>
|
20 |
-
*
|
21 |
-
* @see http://www.twig-project.org/doc/api.html#sandbox-extension for details
|
22 |
-
*/
|
23 |
-
class Twig_TokenParser_Sandbox extends Twig_TokenParser
|
24 |
-
{
|
25 |
-
/**
|
26 |
-
* Parses a token and returns a node.
|
27 |
-
*
|
28 |
-
* @param Twig_Token $token A Twig_Token instance
|
29 |
-
*
|
30 |
-
* @return Twig_NodeInterface A Twig_NodeInterface instance
|
31 |
-
*/
|
32 |
-
public function parse(Twig_Token $token)
|
33 |
-
{
|
34 |
-
$this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
|
35 |
-
$body = $this->parser->subparse(array($this, 'decideBlockEnd'), true);
|
36 |
-
$this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
|
37 |
-
|
38 |
-
// in a sandbox tag, only include tags are allowed
|
39 |
-
if (!$body instanceof Twig_Node_Include) {
|
40 |
-
foreach ($body as $node) {
|
41 |
-
if ($node instanceof Twig_Node_Text && ctype_space($node->getAttribute('data'))) {
|
42 |
-
continue;
|
43 |
-
}
|
44 |
-
|
45 |
-
if (!$node instanceof Twig_Node_Include) {
|
46 |
-
throw new Twig_Error_Syntax('Only "include" tags are allowed within a "sandbox" section', $node->getLine(), $this->parser->getFilename());
|
47 |
-
}
|
48 |
-
}
|
49 |
-
}
|
50 |
-
|
51 |
-
return new Twig_Node_Sandbox($body, $token->getLine(), $this->getTag());
|
52 |
-
}
|
53 |
-
|
54 |
-
public function decideBlockEnd(Twig_Token $token)
|
55 |
-
{
|
56 |
-
return $token->test('endsandbox');
|
57 |
-
}
|
58 |
-
|
59 |
-
/**
|
60 |
-
* Gets the tag name associated with this token parser.
|
61 |
-
*
|
62 |
-
* @return string The tag name
|
63 |
-
*/
|
64 |
-
public function getTag()
|
65 |
-
{
|
66 |
-
return 'sandbox';
|
67 |
-
}
|
68 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2010 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Marks a section of a template as untrusted code that must be evaluated in the sandbox mode.
|
14 |
+
*
|
15 |
+
* <pre>
|
16 |
+
* {% sandbox %}
|
17 |
+
* {% include 'user.html' %}
|
18 |
+
* {% endsandbox %}
|
19 |
+
* </pre>
|
20 |
+
*
|
21 |
+
* @see http://www.twig-project.org/doc/api.html#sandbox-extension for details
|
22 |
+
*/
|
23 |
+
class Twig_TokenParser_Sandbox extends Twig_TokenParser
|
24 |
+
{
|
25 |
+
/**
|
26 |
+
* Parses a token and returns a node.
|
27 |
+
*
|
28 |
+
* @param Twig_Token $token A Twig_Token instance
|
29 |
+
*
|
30 |
+
* @return Twig_NodeInterface A Twig_NodeInterface instance
|
31 |
+
*/
|
32 |
+
public function parse(Twig_Token $token)
|
33 |
+
{
|
34 |
+
$this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
|
35 |
+
$body = $this->parser->subparse(array($this, 'decideBlockEnd'), true);
|
36 |
+
$this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
|
37 |
+
|
38 |
+
// in a sandbox tag, only include tags are allowed
|
39 |
+
if (!$body instanceof Twig_Node_Include) {
|
40 |
+
foreach ($body as $node) {
|
41 |
+
if ($node instanceof Twig_Node_Text && ctype_space($node->getAttribute('data'))) {
|
42 |
+
continue;
|
43 |
+
}
|
44 |
+
|
45 |
+
if (!$node instanceof Twig_Node_Include) {
|
46 |
+
throw new Twig_Error_Syntax('Only "include" tags are allowed within a "sandbox" section', $node->getLine(), $this->parser->getFilename());
|
47 |
+
}
|
48 |
+
}
|
49 |
+
}
|
50 |
+
|
51 |
+
return new Twig_Node_Sandbox($body, $token->getLine(), $this->getTag());
|
52 |
+
}
|
53 |
+
|
54 |
+
public function decideBlockEnd(Twig_Token $token)
|
55 |
+
{
|
56 |
+
return $token->test('endsandbox');
|
57 |
+
}
|
58 |
+
|
59 |
+
/**
|
60 |
+
* Gets the tag name associated with this token parser.
|
61 |
+
*
|
62 |
+
* @return string The tag name
|
63 |
+
*/
|
64 |
+
public function getTag()
|
65 |
+
{
|
66 |
+
return 'sandbox';
|
67 |
+
}
|
68 |
+
}
|
classes/Twig/TokenParser/Set.php
CHANGED
@@ -1,83 +1,83 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2009 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
/**
|
13 |
-
* Defines a variable.
|
14 |
-
*
|
15 |
-
* <pre>
|
16 |
-
* {% set foo = 'foo' %}
|
17 |
-
*
|
18 |
-
* {% set foo = [1, 2] %}
|
19 |
-
*
|
20 |
-
* {% set foo = {'foo': 'bar'} %}
|
21 |
-
*
|
22 |
-
* {% set foo = 'foo' ~ 'bar' %}
|
23 |
-
*
|
24 |
-
* {% set foo, bar = 'foo', 'bar' %}
|
25 |
-
*
|
26 |
-
* {% set foo %}Some content{% endset %}
|
27 |
-
* </pre>
|
28 |
-
*/
|
29 |
-
class Twig_TokenParser_Set extends Twig_TokenParser
|
30 |
-
{
|
31 |
-
/**
|
32 |
-
* Parses a token and returns a node.
|
33 |
-
*
|
34 |
-
* @param Twig_Token $token A Twig_Token instance
|
35 |
-
*
|
36 |
-
* @return Twig_NodeInterface A Twig_NodeInterface instance
|
37 |
-
*/
|
38 |
-
public function parse(Twig_Token $token)
|
39 |
-
{
|
40 |
-
$lineno = $token->getLine();
|
41 |
-
$stream = $this->parser->getStream();
|
42 |
-
$names = $this->parser->getExpressionParser()->parseAssignmentExpression();
|
43 |
-
|
44 |
-
$capture = false;
|
45 |
-
if ($stream->nextIf(Twig_Token::OPERATOR_TYPE, '=')) {
|
46 |
-
$values = $this->parser->getExpressionParser()->parseMultitargetExpression();
|
47 |
-
|
48 |
-
$stream->expect(Twig_Token::BLOCK_END_TYPE);
|
49 |
-
|
50 |
-
if (count($names) !== count($values)) {
|
51 |
-
throw new Twig_Error_Syntax("When using set, you must have the same number of variables and assignments.", $stream->getCurrent()->getLine(), $stream->getFilename());
|
52 |
-
}
|
53 |
-
} else {
|
54 |
-
$capture = true;
|
55 |
-
|
56 |
-
if (count($names) > 1) {
|
57 |
-
throw new Twig_Error_Syntax("When using set with a block, you cannot have a multi-target.", $stream->getCurrent()->getLine(), $stream->getFilename());
|
58 |
-
}
|
59 |
-
|
60 |
-
$stream->expect(Twig_Token::BLOCK_END_TYPE);
|
61 |
-
|
62 |
-
$values = $this->parser->subparse(array($this, 'decideBlockEnd'), true);
|
63 |
-
$stream->expect(Twig_Token::BLOCK_END_TYPE);
|
64 |
-
}
|
65 |
-
|
66 |
-
return new Twig_Node_Set($capture, $names, $values, $lineno, $this->getTag());
|
67 |
-
}
|
68 |
-
|
69 |
-
public function decideBlockEnd(Twig_Token $token)
|
70 |
-
{
|
71 |
-
return $token->test('endset');
|
72 |
-
}
|
73 |
-
|
74 |
-
/**
|
75 |
-
* Gets the tag name associated with this token parser.
|
76 |
-
*
|
77 |
-
* @return string The tag name
|
78 |
-
*/
|
79 |
-
public function getTag()
|
80 |
-
{
|
81 |
-
return 'set';
|
82 |
-
}
|
83 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2009 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Defines a variable.
|
14 |
+
*
|
15 |
+
* <pre>
|
16 |
+
* {% set foo = 'foo' %}
|
17 |
+
*
|
18 |
+
* {% set foo = [1, 2] %}
|
19 |
+
*
|
20 |
+
* {% set foo = {'foo': 'bar'} %}
|
21 |
+
*
|
22 |
+
* {% set foo = 'foo' ~ 'bar' %}
|
23 |
+
*
|
24 |
+
* {% set foo, bar = 'foo', 'bar' %}
|
25 |
+
*
|
26 |
+
* {% set foo %}Some content{% endset %}
|
27 |
+
* </pre>
|
28 |
+
*/
|
29 |
+
class Twig_TokenParser_Set extends Twig_TokenParser
|
30 |
+
{
|
31 |
+
/**
|
32 |
+
* Parses a token and returns a node.
|
33 |
+
*
|
34 |
+
* @param Twig_Token $token A Twig_Token instance
|
35 |
+
*
|
36 |
+
* @return Twig_NodeInterface A Twig_NodeInterface instance
|
37 |
+
*/
|
38 |
+
public function parse(Twig_Token $token)
|
39 |
+
{
|
40 |
+
$lineno = $token->getLine();
|
41 |
+
$stream = $this->parser->getStream();
|
42 |
+
$names = $this->parser->getExpressionParser()->parseAssignmentExpression();
|
43 |
+
|
44 |
+
$capture = false;
|
45 |
+
if ($stream->nextIf(Twig_Token::OPERATOR_TYPE, '=')) {
|
46 |
+
$values = $this->parser->getExpressionParser()->parseMultitargetExpression();
|
47 |
+
|
48 |
+
$stream->expect(Twig_Token::BLOCK_END_TYPE);
|
49 |
+
|
50 |
+
if (count($names) !== count($values)) {
|
51 |
+
throw new Twig_Error_Syntax("When using set, you must have the same number of variables and assignments.", $stream->getCurrent()->getLine(), $stream->getFilename());
|
52 |
+
}
|
53 |
+
} else {
|
54 |
+
$capture = true;
|
55 |
+
|
56 |
+
if (count($names) > 1) {
|
57 |
+
throw new Twig_Error_Syntax("When using set with a block, you cannot have a multi-target.", $stream->getCurrent()->getLine(), $stream->getFilename());
|
58 |
+
}
|
59 |
+
|
60 |
+
$stream->expect(Twig_Token::BLOCK_END_TYPE);
|
61 |
+
|
62 |
+
$values = $this->parser->subparse(array($this, 'decideBlockEnd'), true);
|
63 |
+
$stream->expect(Twig_Token::BLOCK_END_TYPE);
|
64 |
+
}
|
65 |
+
|
66 |
+
return new Twig_Node_Set($capture, $names, $values, $lineno, $this->getTag());
|
67 |
+
}
|
68 |
+
|
69 |
+
public function decideBlockEnd(Twig_Token $token)
|
70 |
+
{
|
71 |
+
return $token->test('endset');
|
72 |
+
}
|
73 |
+
|
74 |
+
/**
|
75 |
+
* Gets the tag name associated with this token parser.
|
76 |
+
*
|
77 |
+
* @return string The tag name
|
78 |
+
*/
|
79 |
+
public function getTag()
|
80 |
+
{
|
81 |
+
return 'set';
|
82 |
+
}
|
83 |
+
}
|
classes/Twig/TokenParser/Spaceless.php
CHANGED
@@ -1,59 +1,59 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2010 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
/**
|
13 |
-
* Remove whitespaces between HTML tags.
|
14 |
-
*
|
15 |
-
* <pre>
|
16 |
-
* {% spaceless %}
|
17 |
-
* <div>
|
18 |
-
* <strong>foo</strong>
|
19 |
-
* </div>
|
20 |
-
* {% endspaceless %}
|
21 |
-
*
|
22 |
-
* {# output will be <div><strong>foo</strong></div> #}
|
23 |
-
* </pre>
|
24 |
-
*/
|
25 |
-
class Twig_TokenParser_Spaceless extends Twig_TokenParser
|
26 |
-
{
|
27 |
-
/**
|
28 |
-
* Parses a token and returns a node.
|
29 |
-
*
|
30 |
-
* @param Twig_Token $token A Twig_Token instance
|
31 |
-
*
|
32 |
-
* @return Twig_NodeInterface A Twig_NodeInterface instance
|
33 |
-
*/
|
34 |
-
public function parse(Twig_Token $token)
|
35 |
-
{
|
36 |
-
$lineno = $token->getLine();
|
37 |
-
|
38 |
-
$this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
|
39 |
-
$body = $this->parser->subparse(array($this, 'decideSpacelessEnd'), true);
|
40 |
-
$this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
|
41 |
-
|
42 |
-
return new Twig_Node_Spaceless($body, $lineno, $this->getTag());
|
43 |
-
}
|
44 |
-
|
45 |
-
public function decideSpacelessEnd(Twig_Token $token)
|
46 |
-
{
|
47 |
-
return $token->test('endspaceless');
|
48 |
-
}
|
49 |
-
|
50 |
-
/**
|
51 |
-
* Gets the tag name associated with this token parser.
|
52 |
-
*
|
53 |
-
* @return string The tag name
|
54 |
-
*/
|
55 |
-
public function getTag()
|
56 |
-
{
|
57 |
-
return 'spaceless';
|
58 |
-
}
|
59 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2010 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Remove whitespaces between HTML tags.
|
14 |
+
*
|
15 |
+
* <pre>
|
16 |
+
* {% spaceless %}
|
17 |
+
* <div>
|
18 |
+
* <strong>foo</strong>
|
19 |
+
* </div>
|
20 |
+
* {% endspaceless %}
|
21 |
+
*
|
22 |
+
* {# output will be <div><strong>foo</strong></div> #}
|
23 |
+
* </pre>
|
24 |
+
*/
|
25 |
+
class Twig_TokenParser_Spaceless extends Twig_TokenParser
|
26 |
+
{
|
27 |
+
/**
|
28 |
+
* Parses a token and returns a node.
|
29 |
+
*
|
30 |
+
* @param Twig_Token $token A Twig_Token instance
|
31 |
+
*
|
32 |
+
* @return Twig_NodeInterface A Twig_NodeInterface instance
|
33 |
+
*/
|
34 |
+
public function parse(Twig_Token $token)
|
35 |
+
{
|
36 |
+
$lineno = $token->getLine();
|
37 |
+
|
38 |
+
$this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
|
39 |
+
$body = $this->parser->subparse(array($this, 'decideSpacelessEnd'), true);
|
40 |
+
$this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
|
41 |
+
|
42 |
+
return new Twig_Node_Spaceless($body, $lineno, $this->getTag());
|
43 |
+
}
|
44 |
+
|
45 |
+
public function decideSpacelessEnd(Twig_Token $token)
|
46 |
+
{
|
47 |
+
return $token->test('endspaceless');
|
48 |
+
}
|
49 |
+
|
50 |
+
/**
|
51 |
+
* Gets the tag name associated with this token parser.
|
52 |
+
*
|
53 |
+
* @return string The tag name
|
54 |
+
*/
|
55 |
+
public function getTag()
|
56 |
+
{
|
57 |
+
return 'spaceless';
|
58 |
+
}
|
59 |
+
}
|
classes/Twig/TokenParser/Use.php
CHANGED
@@ -1,76 +1,76 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2011 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
/**
|
13 |
-
* Imports blocks defined in another template into the current template.
|
14 |
-
*
|
15 |
-
* <pre>
|
16 |
-
* {% extends "base.html" %}
|
17 |
-
*
|
18 |
-
* {% use "blocks.html" %}
|
19 |
-
*
|
20 |
-
* {% block title %}{% endblock %}
|
21 |
-
* {% block content %}{% endblock %}
|
22 |
-
* </pre>
|
23 |
-
*
|
24 |
-
* @see http://www.twig-project.org/doc/templates.html#horizontal-reuse for details.
|
25 |
-
*/
|
26 |
-
class Twig_TokenParser_Use extends Twig_TokenParser
|
27 |
-
{
|
28 |
-
/**
|
29 |
-
* Parses a token and returns a node.
|
30 |
-
*
|
31 |
-
* @param Twig_Token $token A Twig_Token instance
|
32 |
-
*
|
33 |
-
* @return Twig_NodeInterface A Twig_NodeInterface instance
|
34 |
-
*/
|
35 |
-
public function parse(Twig_Token $token)
|
36 |
-
{
|
37 |
-
$template = $this->parser->getExpressionParser()->parseExpression();
|
38 |
-
$stream = $this->parser->getStream();
|
39 |
-
|
40 |
-
if (!$template instanceof Twig_Node_Expression_Constant) {
|
41 |
-
throw new Twig_Error_Syntax('The template references in a "use" statement must be a string.', $stream->getCurrent()->getLine(), $stream->getFilename());
|
42 |
-
}
|
43 |
-
|
44 |
-
$targets = array();
|
45 |
-
if ($stream->nextIf('with')) {
|
46 |
-
do {
|
47 |
-
$name = $stream->expect(Twig_Token::NAME_TYPE)->getValue();
|
48 |
-
|
49 |
-
$alias = $name;
|
50 |
-
if ($stream->nextIf('as')) {
|
51 |
-
$alias = $stream->expect(Twig_Token::NAME_TYPE)->getValue();
|
52 |
-
}
|
53 |
-
|
54 |
-
$targets[$name] = new Twig_Node_Expression_Constant($alias, -1);
|
55 |
-
|
56 |
-
if (!$stream->nextIf(Twig_Token::PUNCTUATION_TYPE, ',')) {
|
57 |
-
break;
|
58 |
-
}
|
59 |
-
} while (true);
|
60 |
-
}
|
61 |
-
|
62 |
-
$stream->expect(Twig_Token::BLOCK_END_TYPE);
|
63 |
-
|
64 |
-
$this->parser->addTrait(new Twig_Node(array('template' => $template, 'targets' => new Twig_Node($targets))));
|
65 |
-
}
|
66 |
-
|
67 |
-
/**
|
68 |
-
* Gets the tag name associated with this token parser.
|
69 |
-
*
|
70 |
-
* @return string The tag name
|
71 |
-
*/
|
72 |
-
public function getTag()
|
73 |
-
{
|
74 |
-
return 'use';
|
75 |
-
}
|
76 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2011 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Imports blocks defined in another template into the current template.
|
14 |
+
*
|
15 |
+
* <pre>
|
16 |
+
* {% extends "base.html" %}
|
17 |
+
*
|
18 |
+
* {% use "blocks.html" %}
|
19 |
+
*
|
20 |
+
* {% block title %}{% endblock %}
|
21 |
+
* {% block content %}{% endblock %}
|
22 |
+
* </pre>
|
23 |
+
*
|
24 |
+
* @see http://www.twig-project.org/doc/templates.html#horizontal-reuse for details.
|
25 |
+
*/
|
26 |
+
class Twig_TokenParser_Use extends Twig_TokenParser
|
27 |
+
{
|
28 |
+
/**
|
29 |
+
* Parses a token and returns a node.
|
30 |
+
*
|
31 |
+
* @param Twig_Token $token A Twig_Token instance
|
32 |
+
*
|
33 |
+
* @return Twig_NodeInterface A Twig_NodeInterface instance
|
34 |
+
*/
|
35 |
+
public function parse(Twig_Token $token)
|
36 |
+
{
|
37 |
+
$template = $this->parser->getExpressionParser()->parseExpression();
|
38 |
+
$stream = $this->parser->getStream();
|
39 |
+
|
40 |
+
if (!$template instanceof Twig_Node_Expression_Constant) {
|
41 |
+
throw new Twig_Error_Syntax('The template references in a "use" statement must be a string.', $stream->getCurrent()->getLine(), $stream->getFilename());
|
42 |
+
}
|
43 |
+
|
44 |
+
$targets = array();
|
45 |
+
if ($stream->nextIf('with')) {
|
46 |
+
do {
|
47 |
+
$name = $stream->expect(Twig_Token::NAME_TYPE)->getValue();
|
48 |
+
|
49 |
+
$alias = $name;
|
50 |
+
if ($stream->nextIf('as')) {
|
51 |
+
$alias = $stream->expect(Twig_Token::NAME_TYPE)->getValue();
|
52 |
+
}
|
53 |
+
|
54 |
+
$targets[$name] = new Twig_Node_Expression_Constant($alias, -1);
|
55 |
+
|
56 |
+
if (!$stream->nextIf(Twig_Token::PUNCTUATION_TYPE, ',')) {
|
57 |
+
break;
|
58 |
+
}
|
59 |
+
} while (true);
|
60 |
+
}
|
61 |
+
|
62 |
+
$stream->expect(Twig_Token::BLOCK_END_TYPE);
|
63 |
+
|
64 |
+
$this->parser->addTrait(new Twig_Node(array('template' => $template, 'targets' => new Twig_Node($targets))));
|
65 |
+
}
|
66 |
+
|
67 |
+
/**
|
68 |
+
* Gets the tag name associated with this token parser.
|
69 |
+
*
|
70 |
+
* @return string The tag name
|
71 |
+
*/
|
72 |
+
public function getTag()
|
73 |
+
{
|
74 |
+
return 'use';
|
75 |
+
}
|
76 |
+
}
|
classes/Twig/TokenParserBroker.php
CHANGED
@@ -1,136 +1,136 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2010 Fabien Potencier
|
7 |
-
* (c) 2010 Arnaud Le Blanc
|
8 |
-
*
|
9 |
-
* For the full copyright and license information, please view the LICENSE
|
10 |
-
* file that was distributed with this source code.
|
11 |
-
*/
|
12 |
-
|
13 |
-
/**
|
14 |
-
* Default implementation of a token parser broker.
|
15 |
-
*
|
16 |
-
* @author Arnaud Le Blanc <arnaud.lb@gmail.com>
|
17 |
-
* @deprecated since 1.12 (to be removed in 2.0)
|
18 |
-
*/
|
19 |
-
class Twig_TokenParserBroker implements Twig_TokenParserBrokerInterface
|
20 |
-
{
|
21 |
-
protected $parser;
|
22 |
-
protected $parsers = array();
|
23 |
-
protected $brokers = array();
|
24 |
-
|
25 |
-
/**
|
26 |
-
* Constructor.
|
27 |
-
*
|
28 |
-
* @param array|Traversable $parsers A Traversable of Twig_TokenParserInterface instances
|
29 |
-
* @param array|Traversable $brokers A Traversable of Twig_TokenParserBrokerInterface instances
|
30 |
-
*/
|
31 |
-
public function __construct($parsers = array(), $brokers = array())
|
32 |
-
{
|
33 |
-
foreach ($parsers as $parser) {
|
34 |
-
if (!$parser instanceof Twig_TokenParserInterface) {
|
35 |
-
throw new LogicException('$parsers must a an array of Twig_TokenParserInterface');
|
36 |
-
}
|
37 |
-
$this->parsers[$parser->getTag()] = $parser;
|
38 |
-
}
|
39 |
-
foreach ($brokers as $broker) {
|
40 |
-
if (!$broker instanceof Twig_TokenParserBrokerInterface) {
|
41 |
-
throw new LogicException('$brokers must a an array of Twig_TokenParserBrokerInterface');
|
42 |
-
}
|
43 |
-
$this->brokers[] = $broker;
|
44 |
-
}
|
45 |
-
}
|
46 |
-
|
47 |
-
/**
|
48 |
-
* Adds a TokenParser.
|
49 |
-
*
|
50 |
-
* @param Twig_TokenParserInterface $parser A Twig_TokenParserInterface instance
|
51 |
-
*/
|
52 |
-
public function addTokenParser(Twig_TokenParserInterface $parser)
|
53 |
-
{
|
54 |
-
$this->parsers[$parser->getTag()] = $parser;
|
55 |
-
}
|
56 |
-
|
57 |
-
/**
|
58 |
-
* Removes a TokenParser.
|
59 |
-
*
|
60 |
-
* @param Twig_TokenParserInterface $parser A Twig_TokenParserInterface instance
|
61 |
-
*/
|
62 |
-
public function removeTokenParser(Twig_TokenParserInterface $parser)
|
63 |
-
{
|
64 |
-
$name = $parser->getTag();
|
65 |
-
if (isset($this->parsers[$name]) && $parser === $this->parsers[$name]) {
|
66 |
-
unset($this->parsers[$name]);
|
67 |
-
}
|
68 |
-
}
|
69 |
-
|
70 |
-
/**
|
71 |
-
* Adds a TokenParserBroker.
|
72 |
-
*
|
73 |
-
* @param Twig_TokenParserBroker $broker A Twig_TokenParserBroker instance
|
74 |
-
*/
|
75 |
-
public function addTokenParserBroker(Twig_TokenParserBroker $broker)
|
76 |
-
{
|
77 |
-
$this->brokers[] = $broker;
|
78 |
-
}
|
79 |
-
|
80 |
-
/**
|
81 |
-
* Removes a TokenParserBroker.
|
82 |
-
*
|
83 |
-
* @param Twig_TokenParserBroker $broker A Twig_TokenParserBroker instance
|
84 |
-
*/
|
85 |
-
public function removeTokenParserBroker(Twig_TokenParserBroker $broker)
|
86 |
-
{
|
87 |
-
if (false !== $pos = array_search($broker, $this->brokers)) {
|
88 |
-
unset($this->brokers[$pos]);
|
89 |
-
}
|
90 |
-
}
|
91 |
-
|
92 |
-
/**
|
93 |
-
* Gets a suitable TokenParser for a tag.
|
94 |
-
*
|
95 |
-
* First looks in parsers, then in brokers.
|
96 |
-
*
|
97 |
-
* @param string $tag A tag name
|
98 |
-
*
|
99 |
-
* @return null|Twig_TokenParserInterface A Twig_TokenParserInterface or null if no suitable TokenParser was found
|
100 |
-
*/
|
101 |
-
public function getTokenParser($tag)
|
102 |
-
{
|
103 |
-
if (isset($this->parsers[$tag])) {
|
104 |
-
return $this->parsers[$tag];
|
105 |
-
}
|
106 |
-
$broker = end($this->brokers);
|
107 |
-
while (false !== $broker) {
|
108 |
-
$parser = $broker->getTokenParser($tag);
|
109 |
-
if (null !== $parser) {
|
110 |
-
return $parser;
|
111 |
-
}
|
112 |
-
$broker = prev($this->brokers);
|
113 |
-
}
|
114 |
-
}
|
115 |
-
|
116 |
-
public function getParsers()
|
117 |
-
{
|
118 |
-
return $this->parsers;
|
119 |
-
}
|
120 |
-
|
121 |
-
public function getParser()
|
122 |
-
{
|
123 |
-
return $this->parser;
|
124 |
-
}
|
125 |
-
|
126 |
-
public function setParser(Twig_ParserInterface $parser)
|
127 |
-
{
|
128 |
-
$this->parser = $parser;
|
129 |
-
foreach ($this->parsers as $tokenParser) {
|
130 |
-
$tokenParser->setParser($parser);
|
131 |
-
}
|
132 |
-
foreach ($this->brokers as $broker) {
|
133 |
-
$broker->setParser($parser);
|
134 |
-
}
|
135 |
-
}
|
136 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2010 Fabien Potencier
|
7 |
+
* (c) 2010 Arnaud Le Blanc
|
8 |
+
*
|
9 |
+
* For the full copyright and license information, please view the LICENSE
|
10 |
+
* file that was distributed with this source code.
|
11 |
+
*/
|
12 |
+
|
13 |
+
/**
|
14 |
+
* Default implementation of a token parser broker.
|
15 |
+
*
|
16 |
+
* @author Arnaud Le Blanc <arnaud.lb@gmail.com>
|
17 |
+
* @deprecated since 1.12 (to be removed in 2.0)
|
18 |
+
*/
|
19 |
+
class Twig_TokenParserBroker implements Twig_TokenParserBrokerInterface
|
20 |
+
{
|
21 |
+
protected $parser;
|
22 |
+
protected $parsers = array();
|
23 |
+
protected $brokers = array();
|
24 |
+
|
25 |
+
/**
|
26 |
+
* Constructor.
|
27 |
+
*
|
28 |
+
* @param array|Traversable $parsers A Traversable of Twig_TokenParserInterface instances
|
29 |
+
* @param array|Traversable $brokers A Traversable of Twig_TokenParserBrokerInterface instances
|
30 |
+
*/
|
31 |
+
public function __construct($parsers = array(), $brokers = array())
|
32 |
+
{
|
33 |
+
foreach ($parsers as $parser) {
|
34 |
+
if (!$parser instanceof Twig_TokenParserInterface) {
|
35 |
+
throw new LogicException('$parsers must a an array of Twig_TokenParserInterface');
|
36 |
+
}
|
37 |
+
$this->parsers[$parser->getTag()] = $parser;
|
38 |
+
}
|
39 |
+
foreach ($brokers as $broker) {
|
40 |
+
if (!$broker instanceof Twig_TokenParserBrokerInterface) {
|
41 |
+
throw new LogicException('$brokers must a an array of Twig_TokenParserBrokerInterface');
|
42 |
+
}
|
43 |
+
$this->brokers[] = $broker;
|
44 |
+
}
|
45 |
+
}
|
46 |
+
|
47 |
+
/**
|
48 |
+
* Adds a TokenParser.
|
49 |
+
*
|
50 |
+
* @param Twig_TokenParserInterface $parser A Twig_TokenParserInterface instance
|
51 |
+
*/
|
52 |
+
public function addTokenParser(Twig_TokenParserInterface $parser)
|
53 |
+
{
|
54 |
+
$this->parsers[$parser->getTag()] = $parser;
|
55 |
+
}
|
56 |
+
|
57 |
+
/**
|
58 |
+
* Removes a TokenParser.
|
59 |
+
*
|
60 |
+
* @param Twig_TokenParserInterface $parser A Twig_TokenParserInterface instance
|
61 |
+
*/
|
62 |
+
public function removeTokenParser(Twig_TokenParserInterface $parser)
|
63 |
+
{
|
64 |
+
$name = $parser->getTag();
|
65 |
+
if (isset($this->parsers[$name]) && $parser === $this->parsers[$name]) {
|
66 |
+
unset($this->parsers[$name]);
|
67 |
+
}
|
68 |
+
}
|
69 |
+
|
70 |
+
/**
|
71 |
+
* Adds a TokenParserBroker.
|
72 |
+
*
|
73 |
+
* @param Twig_TokenParserBroker $broker A Twig_TokenParserBroker instance
|
74 |
+
*/
|
75 |
+
public function addTokenParserBroker(Twig_TokenParserBroker $broker)
|
76 |
+
{
|
77 |
+
$this->brokers[] = $broker;
|
78 |
+
}
|
79 |
+
|
80 |
+
/**
|
81 |
+
* Removes a TokenParserBroker.
|
82 |
+
*
|
83 |
+
* @param Twig_TokenParserBroker $broker A Twig_TokenParserBroker instance
|
84 |
+
*/
|
85 |
+
public function removeTokenParserBroker(Twig_TokenParserBroker $broker)
|
86 |
+
{
|
87 |
+
if (false !== $pos = array_search($broker, $this->brokers)) {
|
88 |
+
unset($this->brokers[$pos]);
|
89 |
+
}
|
90 |
+
}
|
91 |
+
|
92 |
+
/**
|
93 |
+
* Gets a suitable TokenParser for a tag.
|
94 |
+
*
|
95 |
+
* First looks in parsers, then in brokers.
|
96 |
+
*
|
97 |
+
* @param string $tag A tag name
|
98 |
+
*
|
99 |
+
* @return null|Twig_TokenParserInterface A Twig_TokenParserInterface or null if no suitable TokenParser was found
|
100 |
+
*/
|
101 |
+
public function getTokenParser($tag)
|
102 |
+
{
|
103 |
+
if (isset($this->parsers[$tag])) {
|
104 |
+
return $this->parsers[$tag];
|
105 |
+
}
|
106 |
+
$broker = end($this->brokers);
|
107 |
+
while (false !== $broker) {
|
108 |
+
$parser = $broker->getTokenParser($tag);
|
109 |
+
if (null !== $parser) {
|
110 |
+
return $parser;
|
111 |
+
}
|
112 |
+
$broker = prev($this->brokers);
|
113 |
+
}
|
114 |
+
}
|
115 |
+
|
116 |
+
public function getParsers()
|
117 |
+
{
|
118 |
+
return $this->parsers;
|
119 |
+
}
|
120 |
+
|
121 |
+
public function getParser()
|
122 |
+
{
|
123 |
+
return $this->parser;
|
124 |
+
}
|
125 |
+
|
126 |
+
public function setParser(Twig_ParserInterface $parser)
|
127 |
+
{
|
128 |
+
$this->parser = $parser;
|
129 |
+
foreach ($this->parsers as $tokenParser) {
|
130 |
+
$tokenParser->setParser($parser);
|
131 |
+
}
|
132 |
+
foreach ($this->brokers as $broker) {
|
133 |
+
$broker->setParser($parser);
|
134 |
+
}
|
135 |
+
}
|
136 |
+
}
|
classes/Twig/TokenParserBrokerInterface.php
CHANGED
@@ -1,45 +1,45 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2010 Fabien Potencier
|
7 |
-
* (c) 2010 Arnaud Le Blanc
|
8 |
-
*
|
9 |
-
* For the full copyright and license information, please view the LICENSE
|
10 |
-
* file that was distributed with this source code.
|
11 |
-
*/
|
12 |
-
|
13 |
-
/**
|
14 |
-
* Interface implemented by token parser brokers.
|
15 |
-
*
|
16 |
-
* Token parser brokers allows to implement custom logic in the process of resolving a token parser for a given tag name.
|
17 |
-
*
|
18 |
-
* @author Arnaud Le Blanc <arnaud.lb@gmail.com>
|
19 |
-
* @deprecated since 1.12 (to be removed in 2.0)
|
20 |
-
*/
|
21 |
-
interface Twig_TokenParserBrokerInterface
|
22 |
-
{
|
23 |
-
/**
|
24 |
-
* Gets a TokenParser suitable for a tag.
|
25 |
-
*
|
26 |
-
* @param string $tag A tag name
|
27 |
-
*
|
28 |
-
* @return null|Twig_TokenParserInterface A Twig_TokenParserInterface or null if no suitable TokenParser was found
|
29 |
-
*/
|
30 |
-
public function getTokenParser($tag);
|
31 |
-
|
32 |
-
/**
|
33 |
-
* Calls Twig_TokenParserInterface::setParser on all parsers the implementation knows of.
|
34 |
-
*
|
35 |
-
* @param Twig_ParserInterface $parser A Twig_ParserInterface interface
|
36 |
-
*/
|
37 |
-
public function setParser(Twig_ParserInterface $parser);
|
38 |
-
|
39 |
-
/**
|
40 |
-
* Gets the Twig_ParserInterface.
|
41 |
-
*
|
42 |
-
* @return null|Twig_ParserInterface A Twig_ParserInterface instance or null
|
43 |
-
*/
|
44 |
-
public function getParser();
|
45 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2010 Fabien Potencier
|
7 |
+
* (c) 2010 Arnaud Le Blanc
|
8 |
+
*
|
9 |
+
* For the full copyright and license information, please view the LICENSE
|
10 |
+
* file that was distributed with this source code.
|
11 |
+
*/
|
12 |
+
|
13 |
+
/**
|
14 |
+
* Interface implemented by token parser brokers.
|
15 |
+
*
|
16 |
+
* Token parser brokers allows to implement custom logic in the process of resolving a token parser for a given tag name.
|
17 |
+
*
|
18 |
+
* @author Arnaud Le Blanc <arnaud.lb@gmail.com>
|
19 |
+
* @deprecated since 1.12 (to be removed in 2.0)
|
20 |
+
*/
|
21 |
+
interface Twig_TokenParserBrokerInterface
|
22 |
+
{
|
23 |
+
/**
|
24 |
+
* Gets a TokenParser suitable for a tag.
|
25 |
+
*
|
26 |
+
* @param string $tag A tag name
|
27 |
+
*
|
28 |
+
* @return null|Twig_TokenParserInterface A Twig_TokenParserInterface or null if no suitable TokenParser was found
|
29 |
+
*/
|
30 |
+
public function getTokenParser($tag);
|
31 |
+
|
32 |
+
/**
|
33 |
+
* Calls Twig_TokenParserInterface::setParser on all parsers the implementation knows of.
|
34 |
+
*
|
35 |
+
* @param Twig_ParserInterface $parser A Twig_ParserInterface interface
|
36 |
+
*/
|
37 |
+
public function setParser(Twig_ParserInterface $parser);
|
38 |
+
|
39 |
+
/**
|
40 |
+
* Gets the Twig_ParserInterface.
|
41 |
+
*
|
42 |
+
* @return null|Twig_ParserInterface A Twig_ParserInterface instance or null
|
43 |
+
*/
|
44 |
+
public function getParser();
|
45 |
+
}
|
classes/Twig/TokenParserInterface.php
CHANGED
@@ -1,43 +1,43 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2010 Fabien Potencier
|
7 |
-
*
|
8 |
-
* For the full copyright and license information, please view the LICENSE
|
9 |
-
* file that was distributed with this source code.
|
10 |
-
*/
|
11 |
-
|
12 |
-
/**
|
13 |
-
* Interface implemented by token parsers.
|
14 |
-
*
|
15 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
16 |
-
*/
|
17 |
-
interface Twig_TokenParserInterface
|
18 |
-
{
|
19 |
-
/**
|
20 |
-
* Sets the parser associated with this token parser
|
21 |
-
*
|
22 |
-
* @param $parser A Twig_Parser instance
|
23 |
-
*/
|
24 |
-
public function setParser(Twig_Parser $parser);
|
25 |
-
|
26 |
-
/**
|
27 |
-
* Parses a token and returns a node.
|
28 |
-
*
|
29 |
-
* @param Twig_Token $token A Twig_Token instance
|
30 |
-
*
|
31 |
-
* @return Twig_NodeInterface A Twig_NodeInterface instance
|
32 |
-
*
|
33 |
-
* @throws Twig_Error_Syntax
|
34 |
-
*/
|
35 |
-
public function parse(Twig_Token $token);
|
36 |
-
|
37 |
-
/**
|
38 |
-
* Gets the tag name associated with this token parser.
|
39 |
-
*
|
40 |
-
* @return string The tag name
|
41 |
-
*/
|
42 |
-
public function getTag();
|
43 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2010 Fabien Potencier
|
7 |
+
*
|
8 |
+
* For the full copyright and license information, please view the LICENSE
|
9 |
+
* file that was distributed with this source code.
|
10 |
+
*/
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Interface implemented by token parsers.
|
14 |
+
*
|
15 |
+
* @author Fabien Potencier <fabien@symfony.com>
|
16 |
+
*/
|
17 |
+
interface Twig_TokenParserInterface
|
18 |
+
{
|
19 |
+
/**
|
20 |
+
* Sets the parser associated with this token parser
|
21 |
+
*
|
22 |
+
* @param $parser A Twig_Parser instance
|
23 |
+
*/
|
24 |
+
public function setParser(Twig_Parser $parser);
|
25 |
+
|
26 |
+
/**
|
27 |
+
* Parses a token and returns a node.
|
28 |
+
*
|
29 |
+
* @param Twig_Token $token A Twig_Token instance
|
30 |
+
*
|
31 |
+
* @return Twig_NodeInterface A Twig_NodeInterface instance
|
32 |
+
*
|
33 |
+
* @throws Twig_Error_Syntax
|
34 |
+
*/
|
35 |
+
public function parse(Twig_Token $token);
|
36 |
+
|
37 |
+
/**
|
38 |
+
* Gets the tag name associated with this token parser.
|
39 |
+
*
|
40 |
+
* @return string The tag name
|
41 |
+
*/
|
42 |
+
public function getTag();
|
43 |
+
}
|
classes/Twig/TokenStream.php
CHANGED
@@ -1,156 +1,156 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/*
|
4 |
-
* This file is part of Twig.
|
5 |
-
*
|
6 |
-
* (c) 2009 Fabien Potencier
|
7 |
-
* (c) 2009 Armin Ronacher
|
8 |
-
*
|
9 |
-
* For the full copyright and license information, please view the LICENSE
|
10 |
-
* file that was distributed with this source code.
|
11 |
-
*/
|
12 |
-
|
13 |
-
/**
|
14 |
-
* Represents a token stream.
|
15 |
-
*
|
16 |
-
* @author Fabien Potencier <fabien@symfony.com>
|
17 |
-
*/
|
18 |
-
class Twig_TokenStream
|
19 |
-
{
|
20 |
-
protected $tokens;
|
21 |
-
protected $current;
|
22 |
-
protected $filename;
|
23 |
-
|
24 |
-
/**
|
25 |
-
* Constructor.
|
26 |
-
*
|
27 |
-
* @param array $tokens An array of tokens
|
28 |
-
* @param string $filename The name of the filename which tokens are associated with
|
29 |
-
*/
|
30 |
-
public function __construct(array $tokens, $filename = null)
|
31 |
-
{
|
32 |
-
$this->tokens = $tokens;
|
33 |
-
$this->current = 0;
|
34 |
-
$this->filename = $filename;
|
35 |
-
}
|
36 |
-
|
37 |
-
/**
|
38 |
-
* Returns a string representation of the token stream.
|
39 |
-
*
|
40 |
-
* @return string
|
41 |
-
*/
|
42 |
-
public function __toString()
|
43 |
-
{
|
44 |
-
return implode("\n", $this->tokens);
|
45 |
-
}
|
46 |
-
|
47 |
-
public function injectTokens(array $tokens)
|
48 |
-
{
|
49 |
-
$this->tokens = array_merge(array_slice($this->tokens, 0, $this->current), $tokens, array_slice($this->tokens, $this->current));
|
50 |
-
}
|
51 |
-
|
52 |
-
/**
|
53 |
-
* Sets the pointer to the next token and returns the old one.
|
54 |
-
*
|
55 |
-
* @return Twig_Token
|
56 |
-
*/
|
57 |
-
public function next()
|
58 |
-
{
|
59 |
-
if (!isset($this->tokens[++$this->current])) {
|
60 |
-
throw new Twig_Error_Syntax('Unexpected end of template', $this->tokens[$this->current - 1]->getLine(), $this->filename);
|
61 |
-
}
|
62 |
-
|
63 |
-
return $this->tokens[$this->current - 1];
|
64 |
-
}
|
65 |
-
|
66 |
-
/**
|
67 |
-
* Tests a token, sets the pointer to the next one and returns it or throws a syntax error.
|
68 |
-
*
|
69 |
-
* @return Twig_Token|null The next token if the condition is true, null otherwise
|
70 |
-
*/
|
71 |
-
public function nextIf($primary, $secondary = null)
|
72 |
-
{
|
73 |
-
if ($this->tokens[$this->current]->test($primary, $secondary)) {
|
74 |
-
return $this->next();
|
75 |
-
}
|
76 |
-
}
|
77 |
-
|
78 |
-
/**
|
79 |
-
* Tests a token and returns it or throws a syntax error.
|
80 |
-
*
|
81 |
-
* @return Twig_Token
|
82 |
-
*/
|
83 |
-
public function expect($type, $value = null, $message = null)
|
84 |
-
{
|
85 |
-
$token = $this->tokens[$this->current];
|
86 |
-
if (!$token->test($type, $value)) {
|
87 |
-
$line = $token->getLine();
|
88 |
-
throw new Twig_Error_Syntax(sprintf('%sUnexpected token "%s" of value "%s" ("%s" expected%s)',
|
89 |
-
$message ? $message.'. ' : '',
|
90 |
-
Twig_Token::typeToEnglish($token->getType()), $token->getValue(),
|
91 |
-
Twig_Token::typeToEnglish($type), $value ? sprintf(' with value "%s"', $value) : ''),
|
92 |
-
$line,
|
93 |
-
$this->filename
|
94 |
-
);
|
95 |
-
}
|
96 |
-
$this->next();
|
97 |
-
|
98 |
-
return $token;
|
99 |
-
}
|
100 |
-
|
101 |
-
/**
|
102 |
-
* Looks at the next token.
|
103 |
-
*
|
104 |
-
* @param int $number
|
105 |
-
*
|
106 |
-
* @return Twig_Token
|
107 |
-
*/
|
108 |
-
public function look($number = 1)
|
109 |
-
{
|
110 |
-
if (!isset($this->tokens[$this->current + $number])) {
|
111 |
-
throw new Twig_Error_Syntax('Unexpected end of template', $this->tokens[$this->current + $number - 1]->getLine(), $this->filename);
|
112 |
-
}
|
113 |
-
|
114 |
-
return $this->tokens[$this->current + $number];
|
115 |
-
}
|
116 |
-
|
117 |
-
/**
|
118 |
-
* Tests the current token
|
119 |
-
*
|
120 |
-
* @return bool
|
121 |
-
*/
|
122 |
-
public function test($primary, $secondary = null)
|
123 |
-
{
|
124 |
-
return $this->tokens[$this->current]->test($primary, $secondary);
|
125 |
-
}
|
126 |
-
|
127 |
-
/**
|
128 |
-
* Checks if end of stream was reached
|
129 |
-
*
|
130 |
-
* @return bool
|
131 |
-
*/
|
132 |
-
public function isEOF()
|
133 |
-
{
|
134 |
-
return $this->tokens[$this->current]->getType() === Twig_Token::EOF_TYPE;
|
135 |
-
}
|
136 |
-
|
137 |
-
/**
|
138 |
-
* Gets the current token
|
139 |
-
*
|
140 |
-
* @return Twig_Token
|
141 |
-
*/
|
142 |
-
public function getCurrent()
|
143 |
-
{
|
144 |
-
return $this->tokens[$this->current];
|
145 |
-
}
|
146 |
-
|
147 |
-
/**
|
148 |
-
* Gets the filename associated with this stream
|
149 |
-
*
|
150 |
-
* @return string
|
151 |
-
*/
|
152 |
-
public function getFilename()
|
153 |
-
{
|
154 |
-
return $this->filename;
|
155 |
-
}
|
156 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* This file is part of Twig.
|
5 |
+
*
|
6 |
+
* (c) 2009 Fabien Potencier
|
7 |
+
* (c) 2009 Armin Ronacher
|
8 |
+
*
|
9 |
+
* For the full copyright and license information, please view the LICENSE
|
10 |
+
* file that was distributed with this source code.
|
11 |
+
*/
|
12 |
+
|
13 |
+
/**
|
14 |
+
* Represents a token stream.
|
15 |
+
*
|
16 |
+
* @author Fabien Potencier <fabien@symfony.com>
|
17 |
+
*/
|
18 |
+
class Twig_TokenStream
|
19 |
+
{
|
20 |
+
protected $tokens;
|
21 |
+
protected $current;
|
22 |
+
protected $filename;
|
23 |
+
|
24 |
+
/**
|
25 |
+
* Constructor.
|
26 |
+
*
|
27 |
+
* @param array $tokens An array of tokens
|
28 |
+
* @param string $filename The name of the filename which tokens are associated with
|
29 |
+
*/
|
30 |
+
public function __construct(array $tokens, $filename = null)
|
31 |
+
{
|
32 |
+
$this->tokens = $tokens;
|
33 |
+
$this->current = 0;
|
34 |
+
$this->filename = $filename;
|
35 |
+
}
|
36 |
+
|
37 |
+
/**
|
38 |
+
* Returns a string representation of the token stream.
|
39 |
+
*
|
40 |
+
* @return string
|
41 |
+
*/
|
42 |
+
public function __toString()
|
43 |
+
{
|
44 |
+
return implode("\n", $this->tokens);
|
45 |
+
}
|
46 |
+
|
47 |
+
public function injectTokens(array $tokens)
|
48 |
+
{
|
49 |
+
$this->tokens = array_merge(array_slice($this->tokens, 0, $this->current), $tokens, array_slice($this->tokens, $this->current));
|
50 |
+
}
|
51 |
+
|
52 |
+
/**
|
53 |
+
* Sets the pointer to the next token and returns the old one.
|
54 |
+
*
|
55 |
+
* @return Twig_Token
|
56 |
+
*/
|
57 |
+
public function next()
|
58 |
+
{
|
59 |
+
if (!isset($this->tokens[++$this->current])) {
|
60 |
+
throw new Twig_Error_Syntax('Unexpected end of template', $this->tokens[$this->current - 1]->getLine(), $this->filename);
|
61 |
+
}
|
62 |
+
|
63 |
+
return $this->tokens[$this->current - 1];
|
64 |
+
}
|
65 |
+
|
66 |
+
/**
|
67 |
+
* Tests a token, sets the pointer to the next one and returns it or throws a syntax error.
|
68 |
+
*
|
69 |
+
* @return Twig_Token|null The next token if the condition is true, null otherwise
|
70 |
+
*/
|
71 |
+
public function nextIf($primary, $secondary = null)
|
72 |
+
{
|
73 |
+
if ($this->tokens[$this->current]->test($primary, $secondary)) {
|
74 |
+
return $this->next();
|
75 |
+
}
|
76 |
+
}
|
77 |
+
|
78 |
+
/**
|
79 |
+
* Tests a token and returns it or throws a syntax error.
|
80 |
+
*
|
81 |
+
* @return Twig_Token
|
82 |
+
*/
|
83 |
+
public function expect($type, $value = null, $message = null)
|
84 |
+
{
|
85 |
+
$token = $this->tokens[$this->current];
|
86 |
+
if (!$token->test($type, $value)) {
|
87 |
+
$line = $token->getLine();
|
88 |
+
throw new Twig_Error_Syntax(sprintf('%sUnexpected token "%s" of value "%s" ("%s" expected%s)',
|
89 |
+
$message ? $message.'. ' : '',
|
90 |
+
Twig_Token::typeToEnglish($token->getType()), $token->getValue(),
|
91 |
+
Twig_Token::typeToEnglish($type), $value ? sprintf(' with value "%s"', $value) : ''),
|
92 |
+
$line,
|
93 |
+
$this->filename
|
94 |
+
);
|
95 |
+
}
|
96 |
+
$this->next();
|
97 |
+
|
98 |
+
return $token;
|
99 |
+
}
|
100 |
+
|
101 |
+
/**
|
102 |
+
* Looks at the next token.
|
103 |
+
*
|
104 |
+
* @param int $number
|
105 |
+
*
|
106 |
+
* @return Twig_Token
|
107 |
+
*/
|
108 |
+
public function look($number = 1)
|
109 |
+
{
|
110 |
+
if (!isset($this->tokens[$this->current + $number])) {
|
111 |
+
throw new Twig_Error_Syntax('Unexpected end of template', $this->tokens[$this->current + $number - 1]->getLine(), $this->filename);
|
112 |
+
}
|
113 |
+
|
114 |
+
return $this->tokens[$this->current + $number];
|
115 |
+
}
|
116 |
+
|
117 |
+
/**
|
118 |
+
* Tests the current token
|
119 |
+
*
|
120 |
+
* @return bool
|
121 |
+
*/
|
122 |
+
public function test($primary, $secondary = null)
|
123 |
+
{
|
124 |
+
return $this->tokens[$this->current]->test($primary, $secondary);
|
125 |
+
}
|
126 |
+
|
127 |
+
/**
|
128 |
+
* Checks if end of stream was reached
|
129 |
+
*
|
130 |
+
* @return bool
|
131 |
+
*/
|
132 |
+
public function isEOF()
|
133 |
+
{
|
134 |
+
return $this->tokens[$this->current]->getType() === Twig_Token::EOF_TYPE;
|
135 |
+
}
|
136 |
+
|
137 |
+
/**
|
138 |
+
* Gets the current token
|
139 |
+
*
|
140 |
+
* @return Twig_Token
|
141 |
+
*/
|
142 |
+
public function getCurrent()
|
143 |
+
{
|
144 |
+
return $this->tokens[$this->current];
|
145 |
+
}
|
146 |
+
|
147 |
+
/**
|
148 |
+
* Gets the filename associated with this stream
|
149 |
+
*
|
150 |
+
* @return string
|
151 |
+
*/
|
152 |
+
public function getFilename()
|
153 |
+
{
|
154 |
+
return $this->filename;
|
155 |
+
}
|
156 |
+
}
|
classes/baseObject.php
CHANGED
@@ -1,22 +1,22 @@
|
|
1 |
-
<?php
|
2 |
-
abstract class baseObjectCfs {
|
3 |
-
protected $_internalErrors = array();
|
4 |
-
protected $_haveErrors = false;
|
5 |
-
public function pushError($error, $key = '') {
|
6 |
-
if(is_array($error)) {
|
7 |
-
$this->_internalErrors = array_merge ($this->_internalErrors, $error);
|
8 |
-
} elseif(empty($key)) {
|
9 |
-
$this->_internalErrors[] = $error;
|
10 |
-
} else {
|
11 |
-
$this->_internalErrors[ $key ] = $error;
|
12 |
-
}
|
13 |
-
$this->_haveErrors = true;
|
14 |
-
}
|
15 |
-
public function getErrors() {
|
16 |
-
return $this->_internalErrors;
|
17 |
-
}
|
18 |
-
public function haveErrors() {
|
19 |
-
return $this->_haveErrors;
|
20 |
-
}
|
21 |
-
}
|
22 |
-
|
1 |
+
<?php
|
2 |
+
abstract class baseObjectCfs {
|
3 |
+
protected $_internalErrors = array();
|
4 |
+
protected $_haveErrors = false;
|
5 |
+
public function pushError($error, $key = '') {
|
6 |
+
if(is_array($error)) {
|
7 |
+
$this->_internalErrors = array_merge ($this->_internalErrors, $error);
|
8 |
+
} elseif(empty($key)) {
|
9 |
+
$this->_internalErrors[] = $error;
|
10 |
+
} else {
|
11 |
+
$this->_internalErrors[ $key ] = $error;
|
12 |
+
}
|
13 |
+
$this->_haveErrors = true;
|
14 |
+
}
|
15 |
+
public function getErrors() {
|
16 |
+
return $this->_internalErrors;
|
17 |
+
}
|
18 |
+
public function haveErrors() {
|
19 |
+
return $this->_haveErrors;
|
20 |
+
}
|
21 |
+
}
|
22 |
+
|
classes/controller.php
CHANGED
@@ -1,234 +1,232 @@
|
|
1 |
-
<?php
|
2 |
-
abstract class controllerCfs {
|
3 |
-
protected $_models = array();
|
4 |
-
protected $_views = array();
|
5 |
-
protected $_task = '';
|
6 |
-
protected $_defaultView = '';
|
7 |
-
protected $_code = '';
|
8 |
-
public function __construct($code) {
|
9 |
-
$this->setCode($code);
|
10 |
-
$this->_defaultView = $this->getCode();
|
11 |
-
}
|
12 |
-
public function init() {
|
13 |
-
/*load model and other preload data goes here*/
|
14 |
-
}
|
15 |
-
protected function _onBeforeInit() {
|
16 |
-
|
17 |
-
}
|
18 |
-
protected function _onAfterInit() {
|
19 |
-
|
20 |
-
}
|
21 |
-
public function setCode($code) {
|
22 |
-
$this->_code = $code;
|
23 |
-
}
|
24 |
-
public function getCode() {
|
25 |
-
return $this->_code;
|
26 |
-
}
|
27 |
-
public function exec($task = '') {
|
28 |
-
if(method_exists($this, $task)) {
|
29 |
-
$this->_task = $task; //For multicontrollers module version - who know, maybe that's will be?))
|
30 |
-
return $this->$task();
|
31 |
-
}
|
32 |
-
return null;
|
33 |
-
}
|
34 |
-
public function getView($name = '') {
|
35 |
-
if(empty($name)) $name = $this->getCode();
|
36 |
-
if(!isset($this->_views[$name])) {
|
37 |
-
$this->_views[$name] = $this->_createView($name);
|
38 |
-
}
|
39 |
-
return $this->_views[$name];
|
40 |
-
}
|
41 |
-
public function getModel($name = '') {
|
42 |
-
if(!$name)
|
43 |
-
$name = $this->_code;
|
44 |
-
if(!isset($this->_models[$name])) {
|
45 |
-
$this->_models[$name] = $this->_createModel($name);
|
46 |
-
}
|
47 |
-
return $this->_models[$name];
|
48 |
-
}
|
49 |
-
protected function _createModel($name = '') {
|
50 |
-
if(empty($name)) $name = $this->getCode();
|
51 |
-
$parentModule = frameCfs::_()->getModule( $this->getCode() );
|
52 |
-
$className = '';
|
53 |
-
if(importCfs($parentModule->getModDir(). 'models'. DS. $name. '.php')) {
|
54 |
-
$className = toeGetClassNameCfs($name. 'Model');
|
55 |
-
}
|
56 |
-
|
57 |
-
if($className) {
|
58 |
-
$model = new $className();
|
59 |
-
$model->setCode( $this->getCode() );
|
60 |
-
return $model;
|
61 |
-
}
|
62 |
-
return NULL;
|
63 |
-
}
|
64 |
-
protected function _createView($name = '') {
|
65 |
-
if(empty($name)) $name = $this->getCode();
|
66 |
-
$parentModule = frameCfs::_()->getModule( $this->getCode() );
|
67 |
-
$className = '';
|
68 |
-
|
69 |
-
if(importCfs($parentModule->getModDir(). 'views'. DS. $name. '.php')) {
|
70 |
-
$className = toeGetClassNameCfs($name. 'View');
|
71 |
-
}
|
72 |
-
|
73 |
-
if($className) {
|
74 |
-
$view = new $className();
|
75 |
-
$view->setCode( $this->getCode() );
|
76 |
-
return $view;
|
77 |
-
}
|
78 |
-
return NULL;
|
79 |
-
}
|
80 |
-
public function display($viewName = '') {
|
81 |
-
$view = NULL;
|
82 |
-
if(($view = $this->getView($viewName)) === NULL) {
|
83 |
-
$view = $this->getView(); //Get default view
|
84 |
-
}
|
85 |
-
if($view) {
|
86 |
-
$view->display();
|
87 |
-
}
|
88 |
-
}
|
89 |
-
public function __call($name, $arguments) {
|
90 |
-
$model = $this->getModel();
|
91 |
-
if(method_exists($model, $name))
|
92 |
-
return $model->$name($arguments[0]);
|
93 |
-
else
|
94 |
-
return false;
|
95 |
-
}
|
96 |
-
/**
|
97 |
-
* Retrive permissions for controller methods if exist.
|
98 |
-
* If need - should be redefined in each controller where it required.
|
99 |
-
* @return array with permissions
|
100 |
-
* @example :
|
101 |
-
return array(
|
102 |
-
S_METHODS => array(
|
103 |
-
'save' => array(CFS_ADMIN),
|
104 |
-
'remove' => array(CFS_ADMIN),
|
105 |
-
'restore' => CFS_ADMIN,
|
106 |
-
),
|
107 |
-
S_USERLEVELS => array(
|
108 |
-
S_ADMIN => array('save', 'remove', 'restore')
|
109 |
-
),
|
110 |
-
);
|
111 |
-
* Can be used on of sub-array - CFS_METHODS or CFS_USERLEVELS
|
112 |
-
*/
|
113 |
-
public function getPermissions() {
|
114 |
-
return array();
|
115 |
-
}
|
116 |
-
/**
|
117 |
-
* Methods that require nonce to be generated
|
118 |
-
* If need - should be redefined in each controller where it required.
|
119 |
-
* @return array
|
120 |
-
*/
|
121 |
-
public function getNoncedMethods() {
|
122 |
-
return array();
|
123 |
-
}
|
124 |
-
public function getModule() {
|
125 |
-
return frameCfs::_()->getModule( $this->getCode() );
|
126 |
-
}
|
127 |
-
protected function _prepareTextLikeSearch($val) {
|
128 |
-
|
129 |
-
}
|
130 |
-
protected function _prepareModelBeforeListSelect($model) {
|
131 |
-
|
132 |
-
}
|
133 |
-
/**
|
134 |
-
* Common method for list table data
|
135 |
-
*/
|
136 |
-
public function getListForTbl() {
|
137 |
-
$res = new responseCfs();
|
138 |
-
$res->ignoreShellData();
|
139 |
-
$model = $this->getModel();
|
140 |
-
|
141 |
-
$page = (int) sanitize_text_field(reqCfs::getVar('page'));
|
142 |
-
$rowsLimit = (int) sanitize_text_field(reqCfs::getVar('rows'));
|
143 |
-
|
144 |
-
|
145 |
-
//
|
146 |
-
$search
|
147 |
-
|
148 |
-
|
149 |
-
|
150 |
-
|
151 |
-
|
152 |
-
|
153 |
-
|
154 |
-
|
155 |
-
|
156 |
-
|
157 |
-
|
158 |
-
|
159 |
-
|
160 |
-
|
161 |
-
|
162 |
-
|
163 |
-
|
164 |
-
|
165 |
-
//
|
166 |
-
$isSearch
|
167 |
-
|
168 |
-
|
169 |
-
|
170 |
-
|
171 |
-
|
172 |
-
|
173 |
-
|
174 |
-
|
175 |
-
|
176 |
-
|
177 |
-
|
178 |
-
//
|
179 |
-
$
|
180 |
-
$
|
181 |
-
|
182 |
-
|
183 |
-
|
184 |
-
|
185 |
-
|
186 |
-
|
187 |
-
//
|
188 |
-
|
189 |
-
|
190 |
-
|
191 |
-
|
192 |
-
|
193 |
-
|
194 |
-
|
195 |
-
|
196 |
-
|
197 |
-
|
198 |
-
|
199 |
-
$res->addData('
|
200 |
-
$res->addData('
|
201 |
-
$res->
|
202 |
-
$res->
|
203 |
-
|
204 |
-
|
205 |
-
|
206 |
-
|
207 |
-
|
208 |
-
|
209 |
-
$res->
|
210 |
-
|
211 |
-
|
212 |
-
|
213 |
-
|
214 |
-
|
215 |
-
|
216 |
-
|
217 |
-
$res->
|
218 |
-
|
219 |
-
|
220 |
-
|
221 |
-
|
222 |
-
|
223 |
-
|
224 |
-
|
225 |
-
|
226 |
-
|
227 |
-
|
228 |
-
|
229 |
-
|
230 |
-
|
231 |
-
|
232 |
-
|
233 |
-
}
|
234 |
-
}
|
1 |
+
<?php
|
2 |
+
abstract class controllerCfs {
|
3 |
+
protected $_models = array();
|
4 |
+
protected $_views = array();
|
5 |
+
protected $_task = '';
|
6 |
+
protected $_defaultView = '';
|
7 |
+
protected $_code = '';
|
8 |
+
public function __construct($code) {
|
9 |
+
$this->setCode($code);
|
10 |
+
$this->_defaultView = $this->getCode();
|
11 |
+
}
|
12 |
+
public function init() {
|
13 |
+
/*load model and other preload data goes here*/
|
14 |
+
}
|
15 |
+
protected function _onBeforeInit() {
|
16 |
+
|
17 |
+
}
|
18 |
+
protected function _onAfterInit() {
|
19 |
+
|
20 |
+
}
|
21 |
+
public function setCode($code) {
|
22 |
+
$this->_code = $code;
|
23 |
+
}
|
24 |
+
public function getCode() {
|
25 |
+
return $this->_code;
|
26 |
+
}
|
27 |
+
public function exec($task = '') {
|
28 |
+
if(method_exists($this, $task)) {
|
29 |
+
$this->_task = $task; //For multicontrollers module version - who know, maybe that's will be?))
|
30 |
+
return $this->$task();
|
31 |
+
}
|
32 |
+
return null;
|
33 |
+
}
|
34 |
+
public function getView($name = '') {
|
35 |
+
if(empty($name)) $name = $this->getCode();
|
36 |
+
if(!isset($this->_views[$name])) {
|
37 |
+
$this->_views[$name] = $this->_createView($name);
|
38 |
+
}
|
39 |
+
return $this->_views[$name];
|
40 |
+
}
|
41 |
+
public function getModel($name = '') {
|
42 |
+
if(!$name)
|
43 |
+
$name = $this->_code;
|
44 |
+
if(!isset($this->_models[$name])) {
|
45 |
+
$this->_models[$name] = $this->_createModel($name);
|
46 |
+
}
|
47 |
+
return $this->_models[$name];
|
48 |
+
}
|
49 |
+
protected function _createModel($name = '') {
|
50 |
+
if(empty($name)) $name = $this->getCode();
|
51 |
+
$parentModule = frameCfs::_()->getModule( $this->getCode() );
|
52 |
+
$className = '';
|
53 |
+
if(importCfs($parentModule->getModDir(). 'models'. DS. $name. '.php')) {
|
54 |
+
$className = toeGetClassNameCfs($name. 'Model');
|
55 |
+
}
|
56 |
+
|
57 |
+
if($className) {
|
58 |
+
$model = new $className();
|
59 |
+
$model->setCode( $this->getCode() );
|
60 |
+
return $model;
|
61 |
+
}
|
62 |
+
return NULL;
|
63 |
+
}
|
64 |
+
protected function _createView($name = '') {
|
65 |
+
if(empty($name)) $name = $this->getCode();
|
66 |
+
$parentModule = frameCfs::_()->getModule( $this->getCode() );
|
67 |
+
$className = '';
|
68 |
+
|
69 |
+
if(importCfs($parentModule->getModDir(). 'views'. DS. $name. '.php')) {
|
70 |
+
$className = toeGetClassNameCfs($name. 'View');
|
71 |
+
}
|
72 |
+
|
73 |
+
if($className) {
|
74 |
+
$view = new $className();
|
75 |
+
$view->setCode( $this->getCode() );
|
76 |
+
return $view;
|
77 |
+
}
|
78 |
+
return NULL;
|
79 |
+
}
|
80 |
+
public function display($viewName = '') {
|
81 |
+
$view = NULL;
|
82 |
+
if(($view = $this->getView($viewName)) === NULL) {
|
83 |
+
$view = $this->getView(); //Get default view
|
84 |
+
}
|
85 |
+
if($view) {
|
86 |
+
$view->display();
|
87 |
+
}
|
88 |
+
}
|
89 |
+
public function __call($name, $arguments) {
|
90 |
+
$model = $this->getModel();
|
91 |
+
if(method_exists($model, $name))
|
92 |
+
return $model->$name($arguments[0]);
|
93 |
+
else
|
94 |
+
return false;
|
95 |
+
}
|
96 |
+
/**
|
97 |
+
* Retrive permissions for controller methods if exist.
|
98 |
+
* If need - should be redefined in each controller where it required.
|
99 |
+
* @return array with permissions
|
100 |
+
* @example :
|
101 |
+
return array(
|
102 |
+
S_METHODS => array(
|
103 |
+
'save' => array(CFS_ADMIN),
|
104 |
+
'remove' => array(CFS_ADMIN),
|
105 |
+
'restore' => CFS_ADMIN,
|
106 |
+
),
|
107 |
+
S_USERLEVELS => array(
|
108 |
+
S_ADMIN => array('save', 'remove', 'restore')
|
109 |
+
),
|
110 |
+
);
|
111 |
+
* Can be used on of sub-array - CFS_METHODS or CFS_USERLEVELS
|
112 |
+
*/
|
113 |
+
public function getPermissions() {
|
114 |
+
return array();
|
115 |
+
}
|
116 |
+
/**
|
117 |
+
* Methods that require nonce to be generated
|
118 |
+
* If need - should be redefined in each controller where it required.
|
119 |
+
* @return array
|
120 |
+
*/
|
121 |
+
public function getNoncedMethods() {
|
122 |
+
return array();
|
123 |
+
}
|
124 |
+
public function getModule() {
|
125 |
+
return frameCfs::_()->getModule( $this->getCode() );
|
126 |
+
}
|
127 |
+
// protected function _prepareTextLikeSearch($val) {
|
128 |
+
// return ''; // Should be re-defined for each type
|
129 |
+
// }
|
130 |
+
// protected function _prepareModelBeforeListSelect($model) {
|
131 |
+
// return $model;
|
132 |
+
// }
|
133 |
+
/**
|
134 |
+
* Common method for list table data
|
135 |
+
*/
|
136 |
+
//public function getListForTbl() {
|
137 |
+
// $res = new responseCfs();
|
138 |
+
// $res->ignoreShellData();
|
139 |
+
// $model = $this->getModel();
|
140 |
+
//
|
141 |
+
// $page = (int) sanitize_text_field(reqCfs::getVar('page'));
|
142 |
+
// $rowsLimit = (int) sanitize_text_field(reqCfs::getVar('rows'));
|
143 |
+
//
|
144 |
+
// // Our custom search
|
145 |
+
// $search = reqCfs::getVar('search');
|
146 |
+
// if($search && !empty($search) && is_array($search)) {
|
147 |
+
// foreach($search as $k => $v) {
|
148 |
+
// $v = trim($v);
|
149 |
+
// if(empty($v)) continue;
|
150 |
+
// if($k == 'text_like') {
|
151 |
+
// $k = sanitize_text_field($k);
|
152 |
+
// $v = sanitize_text_field($v);
|
153 |
+
// $v = $this->_prepareTextLikeSearch( $v );
|
154 |
+
// if(!empty($v)) {
|
155 |
+
// $model->addWhere(array('additionalCondition' => $v));
|
156 |
+
// }
|
157 |
+
// } else {
|
158 |
+
// $k = sanitize_text_field($k);
|
159 |
+
// $v = sanitize_text_field($v);
|
160 |
+
// $model->addWhere(array($k => $v));
|
161 |
+
// }
|
162 |
+
// }
|
163 |
+
// }
|
164 |
+
// // jqGrid search
|
165 |
+
// $isSearch = reqCfs::getVar('_search');
|
166 |
+
// if($isSearch) {
|
167 |
+
// $searchField = sanitize_text_field(trim(reqCfs::getVar('searchField')));
|
168 |
+
// $searchString = sanitize_text_field(trim(reqCfs::getVar('searchString')));
|
169 |
+
// if(!empty($searchField) && !empty($searchString)) {
|
170 |
+
// // For some cases - we will need to modify search keys and/or values before put it to the model
|
171 |
+
// $model->addWhere(array(
|
172 |
+
// $this->_prepareSearchField($searchField) => $this->_prepareSearchString($searchString)
|
173 |
+
// ));
|
174 |
+
// }
|
175 |
+
// }
|
176 |
+
// $model = $this->_prepareModelBeforeListSelect($model);
|
177 |
+
// // Get total pages count for current request
|
178 |
+
// $totalCount = $model->getCount(array('clear' => array('selectFields')));
|
179 |
+
// $totalPages = 0;
|
180 |
+
// if($totalCount > 0) {
|
181 |
+
// $totalPages = ceil($totalCount / $rowsLimit);
|
182 |
+
// }
|
183 |
+
// if($page > $totalPages) {
|
184 |
+
// $page = $totalPages;
|
185 |
+
// }
|
186 |
+
// // Calc limits - to get data only for current set
|
187 |
+
// $limitStart = $rowsLimit * $page - $rowsLimit; // do not put $limit*($page - 1)
|
188 |
+
// if($limitStart < 0)
|
189 |
+
// $limitStart = 0;
|
190 |
+
//
|
191 |
+
// $data = $model
|
192 |
+
// ->setLimit($limitStart. ', '. $rowsLimit)
|
193 |
+
// ->setSimpleGetFields()
|
194 |
+
// ->getFromTbl();
|
195 |
+
//
|
196 |
+
// $data = $this->_prepareListForTbl( $data );
|
197 |
+
// $res->addData('page', $page);
|
198 |
+
// $res->addData('total', $totalPages);
|
199 |
+
// $res->addData('rows', $data);
|
200 |
+
// $res->addData('records', $model->getLastGetCount());
|
201 |
+
// $res = dispatcherCfs::applyFilters($this->getCode(). '_getListForTblResults', $res);
|
202 |
+
// $res->ajaxExec();
|
203 |
+
//}
|
204 |
+
public function removeGroup() {
|
205 |
+
$res = new responseCfs();
|
206 |
+
if($this->getModel()->removeGroup(reqCfs::getVar('listIds', 'post'))) {
|
207 |
+
$res->addMessage(__('Done', CFS_LANG_CODE));
|
208 |
+
} else
|
209 |
+
$res->pushError($this->getModel()->getErrors());
|
210 |
+
$res->ajaxExec();
|
211 |
+
}
|
212 |
+
public function clear() {
|
213 |
+
$res = new responseCfs();
|
214 |
+
if($this->getModel()->clear()) {
|
215 |
+
$res->addMessage(__('Done', CFS_LANG_CODE));
|
216 |
+
} else
|
217 |
+
$res->pushError($this->getModel()->getErrors());
|
218 |
+
$res->ajaxExec();
|
219 |
+
}
|
220 |
+
protected function _prepareListForTbl($data) {
|
221 |
+
return $data;
|
222 |
+
}
|
223 |
+
protected function _prepareSearchField($searchField) {
|
224 |
+
return $searchField;
|
225 |
+
}
|
226 |
+
protected function _prepareSearchString($searchString) {
|
227 |
+
return $searchString;
|
228 |
+
}
|
229 |
+
// protected function _prepareSortOrder($sortOrder) {
|
230 |
+
// return $sortOrder;
|
231 |
+
// }
|
232 |
+
}
|
|
|
|
classes/csvgenerator.php
CHANGED
@@ -1,38 +1,38 @@
|
|
1 |
-
<?php
|
2 |
-
class csvgeneratorCfs {
|
3 |
-
protected $_filename = '';
|
4 |
-
protected $_delimiter = ';';
|
5 |
-
protected $_enclosure = "\n";
|
6 |
-
protected $_data = array();
|
7 |
-
protected $_escape = '\\';
|
8 |
-
public function __construct($filename) {
|
9 |
-
$this->_filename = $filename;
|
10 |
-
}
|
11 |
-
public function addCell($x, $y, $value) {
|
12 |
-
$this->_data[ $x ][ $y ] = '"'. $value. '"'; //If will not do "" then wymbol for example , will broke file
|
13 |
-
}
|
14 |
-
public function generate() {
|
15 |
-
$strData = '';
|
16 |
-
if(!empty($this->_data)) {
|
17 |
-
$rows = array();
|
18 |
-
foreach($this->_data as $cells) {
|
19 |
-
$rows[] = implode($this->_delimiter, $cells);
|
20 |
-
}
|
21 |
-
$strData = implode($this->_enclosure, $rows);
|
22 |
-
}
|
23 |
-
filegeneratorCfs::_($this->_filename, $strData, 'csv')->generate();
|
24 |
-
}
|
25 |
-
public function getDelimiter() {
|
26 |
-
return $this->_delimiter;
|
27 |
-
}
|
28 |
-
public function getEnclosure() {
|
29 |
-
return $this->_enclosure;
|
30 |
-
}
|
31 |
-
public function getEscape() {
|
32 |
-
return $this->_escape;
|
33 |
-
}
|
34 |
-
public function setDelimiter( $delimiter ) {
|
35 |
-
$this->_delimiter = $delimiter;
|
36 |
-
}
|
37 |
-
}
|
38 |
-
|
1 |
+
<?php
|
2 |
+
class csvgeneratorCfs {
|
3 |
+
protected $_filename = '';
|
4 |
+
protected $_delimiter = ';';
|
5 |
+
protected $_enclosure = "\n";
|
6 |
+
protected $_data = array();
|
7 |
+
protected $_escape = '\\';
|
8 |
+
public function __construct($filename) {
|
9 |
+
$this->_filename = $filename;
|
10 |
+
}
|
11 |
+
public function addCell($x, $y, $value) {
|
12 |
+
$this->_data[ $x ][ $y ] = '"'. $value. '"'; //If will not do "" then wymbol for example , will broke file
|
13 |
+
}
|
14 |
+
public function generate() {
|
15 |
+
$strData = '';
|
16 |
+
if(!empty($this->_data)) {
|
17 |
+
$rows = array();
|
18 |
+
foreach($this->_data as $cells) {
|
19 |
+
$rows[] = implode($this->_delimiter, $cells);
|
20 |
+
}
|
21 |
+
$strData = implode($this->_enclosure, $rows);
|
22 |
+
}
|
23 |
+
filegeneratorCfs::_($this->_filename, $strData, 'csv')->generate();
|
24 |
+
}
|
25 |
+
public function getDelimiter() {
|
26 |
+
return $this->_delimiter;
|
27 |
+
}
|
28 |
+
public function getEnclosure() {
|
29 |
+
return $this->_enclosure;
|
30 |
+
}
|
31 |
+
public function getEscape() {
|
32 |
+
return $this->_escape;
|
33 |
+
}
|
34 |
+
public function setDelimiter( $delimiter ) {
|
35 |
+
$this->_delimiter = $delimiter;
|
36 |
+
}
|
37 |
+
}
|
38 |
+
|
classes/date.php
CHANGED
@@ -1,9 +1,9 @@
|
|
1 |
-
<?php
|
2 |
-
class dateCfs {
|
3 |
-
static public function _($time = NULL) {
|
4 |
-
if(is_null($time)) {
|
5 |
-
$time = time();
|
6 |
-
}
|
7 |
-
return date(CFS_DATE_FORMAT_HIS, $time);
|
8 |
-
}
|
9 |
}
|
1 |
+
<?php
|
2 |
+
class dateCfs {
|
3 |
+
static public function _($time = NULL) {
|
4 |
+
if(is_null($time)) {
|
5 |
+
$time = time();
|
6 |
+
}
|
7 |
+
return date(CFS_DATE_FORMAT_HIS, $time);
|
8 |
+
}
|
9 |
}
|
classes/db.php
CHANGED
@@ -1,141 +1,154 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* Shell - class to work with $wpdb global object
|
4 |
-
*/
|
5 |
-
class dbCfs {
|
6 |
-
/**
|
7 |
-
* Execute query and return results
|
8 |
-
* @param string $query query to be executed
|
9 |
-
* @param string $get what must be returned - one value (one), one row (row), one col (col) or all results (all - by default)
|
10 |
-
* @param const $outputType type of returned data
|
11 |
-
* @return mixed data from DB
|
12 |
-
*/
|
13 |
-
static public $query = '';
|
14 |
-
static public function get($query, $get = 'all', $outputType = ARRAY_A) {
|
15 |
-
|
16 |
-
|
17 |
-
$
|
18 |
-
$
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
return $
|
36 |
-
}
|
37 |
-
/**
|
38 |
-
*
|
39 |
-
* @return
|
40 |
-
*/
|
41 |
-
static public function
|
42 |
-
global $wpdb;
|
43 |
-
return
|
44 |
-
}
|
45 |
-
/**
|
46 |
-
*
|
47 |
-
*
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
return
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
|
94 |
-
|
95 |
-
|
96 |
-
|
97 |
-
|
98 |
-
|
99 |
-
|
100 |
-
|
101 |
-
|
102 |
-
|
103 |
-
|
104 |
-
$res =
|
105 |
-
|
106 |
-
|
107 |
-
|
108 |
-
|
109 |
-
|
110 |
-
|
111 |
-
|
112 |
-
|
113 |
-
|
114 |
-
|
115 |
-
|
116 |
-
|
117 |
-
|
118 |
-
|
119 |
-
|
120 |
-
|
121 |
-
|
122 |
-
|
123 |
-
|
124 |
-
|
125 |
-
|
126 |
-
|
127 |
-
|
128 |
-
|
129 |
-
|
130 |
-
|
131 |
-
|
132 |
-
|
133 |
-
|
134 |
-
|
135 |
-
|
136 |
-
|
137 |
-
|
138 |
-
|
139 |
-
|
140 |
-
|
141 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Shell - class to work with $wpdb global object
|
4 |
+
*/
|
5 |
+
class dbCfs {
|
6 |
+
/**
|
7 |
+
* Execute query and return results
|
8 |
+
* @param string $query query to be executed
|
9 |
+
* @param string $get what must be returned - one value (one), one row (row), one col (col) or all results (all - by default)
|
10 |
+
* @param const $outputType type of returned data
|
11 |
+
* @return mixed data from DB
|
12 |
+
*/
|
13 |
+
static public $query = '';
|
14 |
+
static public function get($query, $get = 'all', $outputType = ARRAY_A) {
|
15 |
+
return false;
|
16 |
+
//global $wpdb;
|
17 |
+
// $get = strtolower($get);
|
18 |
+
// $res = NULL;
|
19 |
+
// $query = self::prepareQuery($query);
|
20 |
+
//error_log('QUERY: '. $query);
|
21 |
+
}
|
22 |
+
/**
|
23 |
+
* Execute one query
|
24 |
+
* @return query results
|
25 |
+
*/
|
26 |
+
static public function query($query) {
|
27 |
+
return false;
|
28 |
+
}
|
29 |
+
/**
|
30 |
+
* Get last insert ID
|
31 |
+
* @return int last ID
|
32 |
+
*/
|
33 |
+
static public function insertID() {
|
34 |
+
global $wpdb;
|
35 |
+
return $wpdb->insert_id;
|
36 |
+
}
|
37 |
+
/**
|
38 |
+
* Get number of rows returned by last query
|
39 |
+
* @return int number of rows
|
40 |
+
*/
|
41 |
+
static public function numRows() {
|
42 |
+
global $wpdb;
|
43 |
+
return $wpdb->num_rows;
|
44 |
+
}
|
45 |
+
/**
|
46 |
+
* Replace prefixes in custom query. Suported next prefixes:
|
47 |
+
* #__ Worcfsess prefix
|
48 |
+
* ^__ Store plugin tables prefix (@see CFS_DB_PREF if config.php)
|
49 |
+
* @__ Compared of WP table prefix + Store plugin prefix (@example wp_s_)
|
50 |
+
* @param string $query query to be executed
|
51 |
+
*/
|
52 |
+
static public function prepareQuery($query) {
|
53 |
+
global $wpdb;
|
54 |
+
return str_replace(
|
55 |
+
array('#__', '^__', '@__'),
|
56 |
+
array($wpdb->prefix, CFS_DB_PREF, $wpdb->prefix. CFS_DB_PREF),
|
57 |
+
$query);
|
58 |
+
}
|
59 |
+
static public function getError() {
|
60 |
+
global $wpdb;
|
61 |
+
return $wpdb->last_error;
|
62 |
+
}
|
63 |
+
static public function lastID() {
|
64 |
+
global $wpdb;
|
65 |
+
return $wpdb->insert_id;
|
66 |
+
}
|
67 |
+
static public function timeToDate($timestamp = 0) {
|
68 |
+
if($timestamp) {
|
69 |
+
if(!is_numeric($timestamp))
|
70 |
+
$timestamp = dateToTimestampCfs($timestamp);
|
71 |
+
return date('Y-m-d', $timestamp);
|
72 |
+
} else {
|
73 |
+
return date('Y-m-d');
|
74 |
+
}
|
75 |
+
}
|
76 |
+
static public function dateToTime($date) {
|
77 |
+
if(empty($date)) return '';
|
78 |
+
if(strpos($date, CFS_DATE_DL)) return dateToTimestampCfs($date);
|
79 |
+
$arr = explode('-', $date);
|
80 |
+
return dateToTimestampCfs($arr[2]. CFS_DATE_DL. $arr[1]. CFS_DATE_DL. $arr[0]);
|
81 |
+
}
|
82 |
+
static public function exist($table) {
|
83 |
+
global $wpdb;
|
84 |
+
switch ($table) {
|
85 |
+
case 'cfs_contacts':
|
86 |
+
$res = $wpdb->get_var("SHOW TABLES LIKE '{$wpdb->prefix}cfs_contacts'");
|
87 |
+
break;
|
88 |
+
case 'cfs_countries':
|
89 |
+
$res = $wpdb->get_var("SHOW TABLES LIKE '{$wpdb->prefix}cfs_countries'");
|
90 |
+
break;
|
91 |
+
case 'cfs_files':
|
92 |
+
$res = $wpdb->get_var("SHOW TABLES LIKE '{$wpdb->prefix}cfs_files'");
|
93 |
+
break;
|
94 |
+
case 'cfs_forms':
|
95 |
+
$res = $wpdb->get_var("SHOW TABLES LIKE '{$wpdb->prefix}cfs_forms'");
|
96 |
+
break;
|
97 |
+
case 'cfs_forms_rating':
|
98 |
+
$res = $wpdb->get_var("SHOW TABLES LIKE '{$wpdb->prefix}cfs_forms_rating'");
|
99 |
+
break;
|
100 |
+
case 'cfs_membership_presets':
|
101 |
+
$res = $wpdb->get_var("SHOW TABLES LIKE '{$wpdb->prefix}cfs_membership_presets'");
|
102 |
+
break;
|
103 |
+
case 'cfs_modules':
|
104 |
+
$res = $wpdb->get_var("SHOW TABLES LIKE '{$wpdb->prefix}cfs_modules'");
|
105 |
+
break;
|
106 |
+
case 'cfs_statistics':
|
107 |
+
$res = $wpdb->get_var("SHOW TABLES LIKE '{$wpdb->prefix}cfs_statistics'");
|
108 |
+
break;
|
109 |
+
case 'cfs_modules_type':
|
110 |
+
$res = $wpdb->get_var("SHOW TABLES LIKE '{$wpdb->prefix}cfs_modules_type'");
|
111 |
+
break;
|
112 |
+
case 'cfs_subscribers':
|
113 |
+
$res = $wpdb->get_var("SHOW TABLES LIKE '{$wpdb->prefix}cfs_subscribers'");
|
114 |
+
break;
|
115 |
+
case 'cfs_usage_stat':
|
116 |
+
$res = $wpdb->get_var("SHOW TABLES LIKE '{$wpdb->prefix}cfs_usage_stat'");
|
117 |
+
break;
|
118 |
+
}
|
119 |
+
return !empty($res);
|
120 |
+
}
|
121 |
+
static public function prepareHtml($d) {
|
122 |
+
if(is_array($d)) {
|
123 |
+
foreach($d as $i => $el) {
|
124 |
+
$d[ $i ] = self::prepareHtml( $el );
|
125 |
+
}
|
126 |
+
} else {
|
127 |
+
$d = esc_html($d);
|
128 |
+
}
|
129 |
+
return $d;
|
130 |
+
}
|
131 |
+
static public function prepareHtmlIn($d) {
|
132 |
+
if(is_array($d)) {
|
133 |
+
foreach($d as $i => $el) {
|
134 |
+
$d[ $i ] = self::prepareHtml( $el );
|
135 |
+
}
|
136 |
+
} else {
|
137 |
+
$d = wp_filter_nohtml_kses($d);
|
138 |
+
}
|
139 |
+
return $d;
|
140 |
+
}
|
141 |
+
static public function escape($data) {
|
142 |
+
global $wpdb;
|
143 |
+
return $wpdb->_escape($data);
|
144 |
+
}
|
145 |
+
static public function getAutoIncrement($table) {
|
146 |
+
return (int) self::get('SELECT AUTO_INCREMENT
|
147 |
+
FROM information_schema.tables
|
148 |
+
WHERE table_name = "'. $table. '"
|
149 |
+
AND table_schema = DATABASE( );', 'one');
|
150 |
+
}
|
151 |
+
static public function setAutoIncrement($table, $autoIncrement) {
|
152 |
+
return self::query("ALTER TABLE `". $table. "` AUTO_INCREMENT = ". $autoIncrement. ";");
|
153 |
+
}
|
154 |
+
}
|
classes/dispatcher.php
CHANGED
@@ -1,41 +1,41 @@
|
|
1 |
-
<?php
|
2 |
-
class dispatcherCfs {
|
3 |
-
static protected $_pref = 'cfs_';
|
4 |
-
|
5 |
-
static public function addAction($tag, $function_to_add, $priority = 10, $accepted_args = 1) {
|
6 |
-
if(strpos($tag, 'cfs_') === false)
|
7 |
-
$tag = self::$_pref. $tag;
|
8 |
-
return add_action( $tag, $function_to_add, $priority, $accepted_args );
|
9 |
-
}
|
10 |
-
static public function doAction($tag) {
|
11 |
-
if(strpos($tag, 'cfs_') === false)
|
12 |
-
$tag = self::$_pref. $tag;
|
13 |
-
$numArgs = func_num_args();
|
14 |
-
if($numArgs > 1) {
|
15 |
-
$args = array( $tag );
|
16 |
-
for($i = 1; $i < $numArgs; $i++) {
|
17 |
-
$args[] = func_get_arg($i);
|
18 |
-
}
|
19 |
-
return call_user_func_array('do_action', $args);
|
20 |
-
}
|
21 |
-
return do_action($tag);
|
22 |
-
}
|
23 |
-
static public function addFilter($tag, $function_to_add, $priority = 10, $accepted_args = 1) {
|
24 |
-
if(strpos($tag, 'cfs_') === false)
|
25 |
-
$tag = self::$_pref. $tag;
|
26 |
-
return add_filter( $tag, $function_to_add, $priority, $accepted_args );
|
27 |
-
}
|
28 |
-
static public function applyFilters($tag, $value) {
|
29 |
-
if(strpos($tag, 'cfs_') === false)
|
30 |
-
$tag = self::$_pref. $tag;
|
31 |
-
if(func_num_args() > 2) {
|
32 |
-
$args = array($tag);
|
33 |
-
for($i = 1; $i < func_num_args(); $i++) {
|
34 |
-
$args[] = func_get_arg($i);
|
35 |
-
}
|
36 |
-
return call_user_func_array('apply_filters', $args);
|
37 |
-
} else {
|
38 |
-
return apply_filters( $tag, $value );
|
39 |
-
}
|
40 |
-
}
|
41 |
-
}
|
1 |
+
<?php
|
2 |
+
class dispatcherCfs {
|
3 |
+
static protected $_pref = 'cfs_';
|
4 |
+
|
5 |
+
static public function addAction($tag, $function_to_add, $priority = 10, $accepted_args = 1) {
|
6 |
+
if(strpos($tag, 'cfs_') === false)
|
7 |
+
$tag = self::$_pref. $tag;
|
8 |
+
return add_action( $tag, $function_to_add, $priority, $accepted_args );
|
9 |
+
}
|
10 |
+
static public function doAction($tag) {
|
11 |
+
if(strpos($tag, 'cfs_') === false)
|
12 |
+
$tag = self::$_pref. $tag;
|
13 |
+
$numArgs = func_num_args();
|
14 |
+
if($numArgs > 1) {
|
15 |
+
$args = array( $tag );
|
16 |
+
for($i = 1; $i < $numArgs; $i++) {
|
17 |
+
$args[] = func_get_arg($i);
|
18 |
+
}
|
19 |
+
return call_user_func_array('do_action', $args);
|
20 |
+
}
|
21 |
+
return do_action($tag);
|
22 |
+
}
|
23 |
+
static public function addFilter($tag, $function_to_add, $priority = 10, $accepted_args = 1) {
|
24 |
+
if(strpos($tag, 'cfs_') === false)
|
25 |
+
$tag = self::$_pref. $tag;
|
26 |
+
return add_filter( $tag, $function_to_add, $priority, $accepted_args );
|
27 |
+
}
|
28 |
+
static public function applyFilters($tag, $value) {
|
29 |
+
if(strpos($tag, 'cfs_') === false)
|
30 |
+
$tag = self::$_pref. $tag;
|
31 |
+
if(func_num_args() > 2) {
|
32 |
+
$args = array($tag);
|
33 |
+
for($i = 1; $i < func_num_args(); $i++) {
|
34 |
+
$args[] = func_get_arg($i);
|
35 |
+
}
|
36 |
+
return call_user_func_array('apply_filters', $args);
|
37 |
+
} else {
|
38 |
+
return apply_filters( $tag, $value );
|
39 |
+
}
|
40 |
+
}
|
41 |
+
}
|
classes/errors.php
CHANGED
@@ -1,93 +1,93 @@
|
|
1 |
-
<?php
|
2 |
-
class errorsCfs {
|
3 |
-
const FATAL = 'fatal';
|
4 |
-
const MOD_INSTALL = 'mod_install';
|
5 |
-
static private $errors = array();
|
6 |
-
static private $haveErrors = false;
|
7 |
-
|
8 |
-
static public $current = array();
|
9 |
-
static public $displayed = false;
|
10 |
-
|
11 |
-
static public function push($error, $type = 'common') {
|
12 |
-
if(!isset(self::$errors[$type]))
|
13 |
-
self::$errors[$type] = array();
|
14 |
-
if(is_array($error))
|
15 |
-
self::$errors[$type] = array_merge(self::$errors[$type], $error);
|
16 |
-
else
|
17 |
-
self::$errors[$type][] = $error;
|
18 |
-
self::$haveErrors = true;
|
19 |
-
|
20 |
-
if($type == 'session')
|
21 |
-
self::setSession(self::$errors[$type]);
|
22 |
-
}
|
23 |
-
static public function setSession($error) {
|
24 |
-
$sesErrors = self::getSession();
|
25 |
-
if(empty($sesErrors))
|
26 |
-
$sesErrors = array();
|
27 |
-
if(is_array($error))
|
28 |
-
$sesErrors = array_merge($sesErrors, $error);
|
29 |
-
else
|
30 |
-
$sesErrors[] = $error;
|
31 |
-
reqCfs::setVar('sesErrors', $sesErrors, 'session');
|
32 |
-
}
|
33 |
-
static public function init() {
|
34 |
-
$cfsErrors = reqCfs::getVar('cfsErrors');
|
35 |
-
if(!empty($cfsErrors)) {
|
36 |
-
if(!is_array($cfsErrors)) {
|
37 |
-
$cfsErrors = array( $cfsErrors );
|
38 |
-
}
|
39 |
-
$cfsErrors = array_map('htmlspecialchars', array_map('stripslashes', array_map('trim', $cfsErrors)));
|
40 |
-
if(!empty($cfsErrors)) {
|
41 |
-
self::$current = $cfsErrors;
|
42 |
-
if(is_admin()) {
|
43 |
-
add_action('admin_notices', array('errorsCfs', 'showAdminErrors'));
|
44 |
-
} else {
|
45 |
-
add_filter('the_content', array('errorsCfs', 'appendErrorsContent'), 99999);
|
46 |
-
}
|
47 |
-
}
|
48 |
-
}
|
49 |
-
}
|
50 |
-
static public function showAdminErrors() {
|
51 |
-
if(self::$current) {
|
52 |
-
$html = '';
|
53 |
-
foreach(self::$current as $error) {
|
54 |
-
$html .= '<div class="error"><p><strong style="font-size: 15px;">'. $error. '</strong></p></div>';
|
55 |
-
}
|
56 |
-
echo $html;
|
57 |
-
}
|
58 |
-
}
|
59 |
-
static public function appendErrorsContent($content) {
|
60 |
-
if(!self::$displayed && !empty(self::$current)) {
|
61 |
-
$content = '<div class="toeErrorMsg">'. implode('<br />', self::$current). '</div>'. $content;
|
62 |
-
self::$displayed = true;
|
63 |
-
}
|
64 |
-
return $content;
|
65 |
-
}
|
66 |
-
static public function getSession() {
|
67 |
-
return reqCfs::getVar('sesErrors', 'session');
|
68 |
-
}
|
69 |
-
static public function clearSession() {
|
70 |
-
reqCfs::clearVar('sesErrors', 'session');
|
71 |
-
}
|
72 |
-
static public function get($type = '') {
|
73 |
-
$res = array();
|
74 |
-
if(!empty(self::$errors)) {
|
75 |
-
if(empty($type)) {
|
76 |
-
foreach(self::$errors as $e) {
|
77 |
-
foreach($e as $error) {
|
78 |
-
$res[] = $error;
|
79 |
-
}
|
80 |
-
}
|
81 |
-
} else
|
82 |
-
$res = self::$errors[$type];
|
83 |
-
}
|
84 |
-
return $res;
|
85 |
-
}
|
86 |
-
static public function haveErrors($type = '') {
|
87 |
-
if(empty($type))
|
88 |
-
return self::$haveErrors;
|
89 |
-
else
|
90 |
-
return isset(self::$errors[$type]);
|
91 |
-
}
|
92 |
-
}
|
93 |
-
|
1 |
+
<?php
|
2 |
+
class errorsCfs {
|
3 |
+
const FATAL = 'fatal';
|
4 |
+
const MOD_INSTALL = 'mod_install';
|
5 |
+
static private $errors = array();
|
6 |
+
static private $haveErrors = false;
|
7 |
+
|
8 |
+
static public $current = array();
|
9 |
+
static public $displayed = false;
|
10 |
+
|
11 |
+
static public function push($error, $type = 'common') {
|
12 |
+
if(!isset(self::$errors[$type]))
|
13 |
+
self::$errors[$type] = array();
|
14 |
+
if(is_array($error))
|
15 |
+
self::$errors[$type] = array_merge(self::$errors[$type], $error);
|
16 |
+
else
|
17 |
+
self::$errors[$type][] = $error;
|
18 |
+
self::$haveErrors = true;
|
19 |
+
|
20 |
+
if($type == 'session')
|
21 |
+
self::setSession(self::$errors[$type]);
|
22 |
+
}
|
23 |
+
static public function setSession($error) {
|
24 |
+
$sesErrors = self::getSession();
|
25 |
+
if(empty($sesErrors))
|
26 |
+
$sesErrors = array();
|
27 |
+
if(is_array($error))
|
28 |
+
$sesErrors = array_merge($sesErrors, $error);
|
29 |
+
else
|
30 |
+
$sesErrors[] = $error;
|
31 |
+
reqCfs::setVar('sesErrors', $sesErrors, 'session');
|
32 |
+
}
|
33 |
+
static public function init() {
|
34 |
+
$cfsErrors = reqCfs::getVar('cfsErrors');
|
35 |
+
if(!empty($cfsErrors)) {
|
36 |
+
if(!is_array($cfsErrors)) {
|
37 |
+
$cfsErrors = array( $cfsErrors );
|
38 |
+
}
|
39 |
+
$cfsErrors = array_map('htmlspecialchars', array_map('stripslashes', array_map('trim', $cfsErrors)));
|
40 |
+
if(!empty($cfsErrors)) {
|
41 |
+
self::$current = $cfsErrors;
|
42 |
+
if(is_admin()) {
|
43 |
+
add_action('admin_notices', array('errorsCfs', 'showAdminErrors'));
|
44 |
+
} else {
|
45 |
+
add_filter('the_content', array('errorsCfs', 'appendErrorsContent'), 99999);
|
46 |
+
}
|
47 |
+
}
|
48 |
+
}
|
49 |
+
}
|
50 |
+
static public function showAdminErrors() {
|
51 |
+
if(self::$current) {
|
52 |
+
$html = '';
|
53 |
+
foreach(self::$current as $error) {
|
54 |
+
$html .= '<div class="error"><p><strong style="font-size: 15px;">'. $error. '</strong></p></div>';
|
55 |
+
}
|
56 |
+
echo $html;
|
57 |
+
}
|
58 |
+
}
|
59 |
+
static public function appendErrorsContent($content) {
|
60 |
+
if(!self::$displayed && !empty(self::$current)) {
|
61 |
+
$content = '<div class="toeErrorMsg">'. implode('<br />', self::$current). '</div>'. $content;
|
62 |
+
self::$displayed = true;
|
63 |
+
}
|
64 |
+
return $content;
|
65 |
+
}
|
66 |
+
static public function getSession() {
|
67 |
+
return reqCfs::getVar('sesErrors', 'session');
|
68 |
+
}
|
69 |
+
static public function clearSession() {
|
70 |
+
reqCfs::clearVar('sesErrors', 'session');
|
71 |
+
}
|
72 |
+
static public function get($type = '') {
|
73 |
+
$res = array();
|
74 |
+
if(!empty(self::$errors)) {
|
75 |
+
if(empty($type)) {
|
76 |
+
foreach(self::$errors as $e) {
|
77 |
+
foreach($e as $error) {
|
78 |
+
$res[] = $error;
|
79 |
+
}
|
80 |
+
}
|
81 |
+
} else
|
82 |
+
$res = self::$errors[$type];
|
83 |
+
}
|
84 |
+
return $res;
|
85 |
+
}
|
86 |
+
static public function haveErrors($type = '') {
|
87 |
+
if(empty($type))
|
88 |
+
return self::$haveErrors;
|
89 |
+
else
|
90 |
+
return isset(self::$errors[$type]);
|
91 |
+
}
|
92 |
+
}
|
93 |
+
|
classes/field.php
CHANGED
@@ -1,518 +1,518 @@
|
|
1 |
-
<?php
|
2 |
-
class fieldCfs {
|
3 |
-
public $name = '';
|
4 |
-
public $html = '';
|
5 |
-
public $type = '';
|
6 |
-
public $default = '';
|
7 |
-
public $value = '';
|
8 |
-
public $label = '';
|
9 |
-
public $maxlen = 0;
|
10 |
-
public $id = 0;
|
11 |
-
public $htmlParams = array();
|
12 |
-
public $validate = array();
|
13 |
-
public $description = '';
|
14 |
-
/**
|
15 |
-
* Wheter or not add error html element right after input field
|
16 |
-
* if bool - will be added standard element
|
17 |
-
* if string - it will be add this string
|
18 |
-
*/
|
19 |
-
public $errorEl = false;
|
20 |
-
/**
|
21 |
-
* Name of method in table object to prepare data before insert / update operations
|
22 |
-
*/
|
23 |
-
public $adapt = array('htmlCfs' => '', 'dbFrom' => '', 'dbTo' => '');
|
24 |
-
/**
|
25 |
-
* Init database field representation
|
26 |
-
* @param string $html html type of field (text, textarea, etc. @see html class)
|
27 |
-
* @param string $type database type (int, varcahr, etc.)
|
28 |
-
* @param mixed $default default value for this field
|
29 |
-
*/
|
30 |
-
public function __construct($name, $html = 'text', $type = 'other', $default = '', $label = '', $maxlen = 0, $adaption = array(), $validate = '', $description = '') {
|
31 |
-
$this->name = $name;
|
32 |
-
$this->html = $html;
|
33 |
-
$this->type = $type;
|
34 |
-
$this->default = $default;
|
35 |
-
$this->value = $default; //Init field value same as default
|
36 |
-
$this->label = $label;
|
37 |
-
$this->maxlen = $maxlen;
|
38 |
-
$this->description = $description;
|
39 |
-
if($adaption)
|
40 |
-
$this->adapt = $adaption;
|
41 |
-
if($validate) {
|
42 |
-
$this->setValidation($validate);
|
43 |
-
}
|
44 |
-
if($type == 'varchar' && !empty($maxlen) && !in_array('validLen', $this->validate)) {
|
45 |
-
$this->addValidation('validLen');
|
46 |
-
}
|
47 |
-
}
|
48 |
-
/**
|
49 |
-
* @param mixed $errorEl - if bool and "true" - than we will use standard error element, if string - we will use this string as error element
|
50 |
-
*/
|
51 |
-
public function setErrorEl($errorEl) {
|
52 |
-
$this->errorEl = $errorEl;
|
53 |
-
}
|
54 |
-
public function getErrorEl() {
|
55 |
-
return $this->errorEl;
|
56 |
-
}
|
57 |
-
public function setValidation($validate) {
|
58 |
-
if(is_array($validate))
|
59 |
-
$this->validate = $validate;
|
60 |
-
else {
|
61 |
-
if(strpos($validate, ','))
|
62 |
-
$this->validate = array_map('trim', explode(',', $validate));
|
63 |
-
else
|
64 |
-
$this->validate = array(trim($validate));
|
65 |
-
}
|
66 |
-
}
|
67 |
-
public function addValidation($validate) {
|
68 |
-
$this->validate[] = $validate;
|
69 |
-
}
|
70 |
-
/**
|
71 |
-
* Set $value property.
|
72 |
-
* Sure - it is public and can be set directly, but it can be more
|
73 |
-
* comfortable to use this method in future
|
74 |
-
* @param mixed $value value to be set
|
75 |
-
*/
|
76 |
-
public function setValue($value, $fromDB = false) {
|
77 |
-
if(isset($this->adapt['dbFrom']) && $this->adapt['dbFrom'] && $fromDB)
|
78 |
-
$value = fieldAdapterCfs::_($value, $this->adapt['dbFrom'], fieldAdapterCfs::DB);
|
79 |
-
$this->value = $value;
|
80 |
-
}
|
81 |
-
public function setLabel($label) {
|
82 |
-
$this->label = $label;
|
83 |
-
}
|
84 |
-
public function setHtml($html) {
|
85 |
-
$this->html = $html;
|
86 |
-
}
|
87 |
-
public function getHtml() {
|
88 |
-
return $this->html;
|
89 |
-
}
|
90 |
-
public function setName($name) {
|
91 |
-
$this->name = $name;
|
92 |
-
}
|
93 |
-
public function getName() {
|
94 |
-
return $this->name;
|
95 |
-
}
|
96 |
-
public function getValue() {
|
97 |
-
return $this->value;
|
98 |
-
}
|
99 |
-
public function getLabel() {
|
100 |
-
return $this->label;
|
101 |
-
}
|
102 |
-
public function setID($id) {
|
103 |
-
$this->id = $id;
|
104 |
-
}
|
105 |
-
public function getID() {
|
106 |
-
return $this->id;
|
107 |
-
}
|
108 |
-
public function setAdapt($adapt) {
|
109 |
-
$this->adapt = $adapt;
|
110 |
-
}
|
111 |
-
public function drawHtml($tag, $id) {
|
112 |
-
if(method_exists('htmlCfs', $this->html)) {
|
113 |
-
$method = $this->html;
|
114 |
-
//echo $this->name. ': '. $this->value. '<br />';
|
115 |
-
if(!empty($this->value))
|
116 |
-
$this->htmlParams['value'] = $this->value;
|
117 |
-
if ($method == 'checkbox') {
|
118 |
-
if ($this->value == 1) {
|
119 |
-
$this->htmlParams['checked'] = 1;
|
120 |
-
}
|
121 |
-
}
|
122 |
-
if($this->adapt['html']) {
|
123 |
-
fieldAdapterCfs::_($this, $this->adapt['html'], fieldAdapterCfs::HTML);
|
124 |
-
}
|
125 |
-
$params = $this->processParams($tag, $id);
|
126 |
-
if ($params != '')
|
127 |
-
return $params;
|
128 |
-
if ($this->name == 'default_value') {
|
129 |
-
$optionsFromDb = frameCfs::_()->getModule('optionsCfs')->getHelper()->getOptions($id);
|
130 |
-
if (!empty($optionsFromDb)) {
|
131 |
-
$options = array(0 => __('Select', CFS_LANG_CODE));
|
132 |
-
foreach($optionsFromDb as $k => $v)
|
133 |
-
$options[$k] = $v;
|
134 |
-
$method = 'selectbox';
|
135 |
-
$this->htmlParams['optionsCfs'] = $options;
|
136 |
-
}
|
137 |
-
}
|
138 |
-
$htmlContent = htmlCfs::$method($this->name, $this->htmlParams);
|
139 |
-
if(!empty($this->errorEl)) {
|
140 |
-
if(is_bool($this->errorEl))
|
141 |
-
$errorEl = '<div class="toeErrorForField toe_'. htmlCfs::nameToClassId($this->name). '"></div>';
|
142 |
-
else //if it is string
|
143 |
-
$errorEl = $this->errorEl;
|
144 |
-
$htmlContent .= $errorEl;
|
145 |
-
}
|
146 |
-
return $htmlContent;
|
147 |
-
}
|
148 |
-
return false;
|
149 |
-
}
|
150 |
-
public function displayValue() {
|
151 |
-
$value = '';
|
152 |
-
switch($this->html) {
|
153 |
-
case 'countryList':
|
154 |
-
$value = fieldAdapterCfs::displayCountry($this->value);
|
155 |
-
break;
|
156 |
-
case 'statesList':
|
157 |
-
$value = fieldAdapterCfs::displayState($this->value);
|
158 |
-
break;
|
159 |
-
case 'checkboxlist':
|
160 |
-
$options = $this->getHtmlParam('optionsCfs');
|
161 |
-
$value = array();
|
162 |
-
if(!empty($options) && is_array($options)) {
|
163 |
-
foreach($options as $opt) {
|
164 |
-
if(isset($opt['checked']) && $opt['checked']) {
|
165 |
-
$value[] = $opt['text'];
|
166 |
-
}
|
167 |
-
}
|
168 |
-
}
|
169 |
-
if(empty($value))
|
170 |
-
$value = __('N/A', CFS_LANG_CODE);
|
171 |
-
else
|
172 |
-
$value = implode('<br />', $value);
|
173 |
-
break;
|
174 |
-
case 'selectbox': case 'radiobuttons':
|
175 |
-
$options = $this->getHtmlParam('optionsCfs');
|
176 |
-
if(!empty($options) && !empty($options[ $this->value ])) {
|
177 |
-
$value = $options[ $this->value ];
|
178 |
-
} else {
|
179 |
-
$value = __('N/A', CFS_LANG_CODE);
|
180 |
-
}
|
181 |
-
break;
|
182 |
-
default:
|
183 |
-
if ($this->value == '') {
|
184 |
-
$value = __('N/A', CFS_LANG_CODE);
|
185 |
-
} else {
|
186 |
-
if(is_array($this->value)) {
|
187 |
-
$options = $this->getHtmlParam('optionsCfs');
|
188 |
-
if(!empty($options) && is_array($options)) {
|
189 |
-
$valArr = array();
|
190 |
-
foreach($this->value as $v) {
|
191 |
-
$valArr[] = $options[$v];
|
192 |
-
}
|
193 |
-
$value = recImplode('<br />', $valArr);
|
194 |
-
} else {
|
195 |
-
$value = recImplode('<br />', $this->value);
|
196 |
-
}
|
197 |
-
} else
|
198 |
-
$value = $this->value;
|
199 |
-
}
|
200 |
-
break;
|
201 |
-
}
|
202 |
-
if($echo)
|
203 |
-
echo $value;
|
204 |
-
else
|
205 |
-
return $value;
|
206 |
-
}
|
207 |
-
public function showValue() {
|
208 |
-
echo $this->displayValue();
|
209 |
-
}
|
210 |
-
public function display($tag = 1, $id = 0) {
|
211 |
-
echo $this->drawHtml($tag, $id);
|
212 |
-
}
|
213 |
-
public function addHtmlParam($name, $value) {
|
214 |
-
$this->htmlParams[$name] = $value;
|
215 |
-
}
|
216 |
-
/**
|
217 |
-
* Alias for addHtmlParam();
|
218 |
-
*/
|
219 |
-
public function setHtmlParam($name, $value) {
|
220 |
-
$this->addHtmlParam($name, $value);
|
221 |
-
}
|
222 |
-
public function setHtmlParams($params) {
|
223 |
-
$this->htmlParams = $params;
|
224 |
-
}
|
225 |
-
public function getHtmlParam($name) {
|
226 |
-
return isset($this->htmlParams[$name]) ? $this->htmlParams[$name] : false;
|
227 |
-
}
|
228 |
-
/**
|
229 |
-
* Function to display userfields in front-end
|
230 |
-
*
|
231 |
-
* @param string $name
|
232 |
-
* @param mixed $fieldValue
|
233 |
-
* @return string
|
234 |
-
*/
|
235 |
-
public function viewField($name, $fieldValue = '') {
|
236 |
-
$method = $this->html;
|
237 |
-
$options = frameCfs::_()->getModule('optionsCfs')->getHelper()->getOptions($this->id);
|
238 |
-
$attrs = '';
|
239 |
-
if (is_object($this->htmlParams['attr']) && count($this->htmlParams['attr']) > 0) {
|
240 |
-
foreach ($this->htmlParams['attr'] as $attribute=>$value) {
|
241 |
-
if ($value != '') {
|
242 |
-
$attrs .= $attribute.'="'.$value.'" ';
|
243 |
-
}
|
244 |
-
}
|
245 |
-
}
|
246 |
-
if ($fieldValue == $this->default_value) {
|
247 |
-
$checked = 1;
|
248 |
-
} else {
|
249 |
-
$checked = 0;
|
250 |
-
}
|
251 |
-
if ($fieldValue == '') {
|
252 |
-
$fieldValue = $this->default_value;
|
253 |
-
}
|
254 |
-
$params = array('optionsCfs'=>$options, 'attrs' => $attrs, 'value' => $fieldValue, 'checked' => $checked);
|
255 |
-
$output = '';
|
256 |
-
if(method_exists('htmlCfs', $method)) {
|
257 |
-
$output .= htmlCfs::$method($name, $params);
|
258 |
-
$output .= htmlCfs::hidden('extra_field['.$this->name.']',array('value'=>$this->id));
|
259 |
-
}
|
260 |
-
return $output;
|
261 |
-
}
|
262 |
-
|
263 |
-
/**
|
264 |
-
* Function to process field params
|
265 |
-
*/
|
266 |
-
public function processParams($tag, $id){
|
267 |
-
return '';
|
268 |
-
if ($this->name == "params") {
|
269 |
-
if(is_array($this->value) || is_object($this->value)) {
|
270 |
-
$params = $this->value;
|
271 |
-
} else {
|
272 |
-
$params = json_decode($this->value);
|
273 |
-
}
|
274 |
-
$add_option = '';
|
275 |
-
switch ($tag) {
|
276 |
-
case 5:
|
277 |
-
$add_option = __('Add Checkbox', CFS_LANG_CODE);
|
278 |
-
$options_tag = '';
|
279 |
-
$image_tag = ' style="display:none"';
|
280 |
-
break;
|
281 |
-
case 9:
|
282 |
-
$add_option = __('Add Item', CFS_LANG_CODE);
|
283 |
-
$options_tag = '';
|
284 |
-
$image_tag = ' style="display:none"';
|
285 |
-
break;
|
286 |
-
case 12:
|
287 |
-
$add_option = __('Add Item', CFS_LANG_CODE);
|
288 |
-
$options_tag = '';
|
289 |
-
$image_tag = ' style="display:none"';
|
290 |
-
break;
|
291 |
-
case 10:
|
292 |
-
$options_tag = '';
|
293 |
-
$add_option = __('Add Radio Button', CFS_LANG_CODE);
|
294 |
-
$image_tag = ' style="display:none"';
|
295 |
-
break;
|
296 |
-
case 8:
|
297 |
-
$image_tag = '';
|
298 |
-
$options_tag = ' style="display:none"';
|
299 |
-
break;
|
300 |
-
default:
|
301 |
-
$options_tag = ' style="display:none"';
|
302 |
-
$image_tag = ' style="display:none"';
|
303 |
-
break;
|
304 |
-
}
|
305 |
-
if ($tag > 0 || $id == 0) {
|
306 |
-
$output .= '<div class="options options_tag"'.$options_tag.'>';
|
307 |
-
$output .= '<span class="add_option">'.$add_option.'</span>';
|
308 |
-
$output .= fieldAdapterCfs::_($id,'getExtraFieldOptions',fieldAdapterCfs::STR);
|
309 |
-
$output .= '</div>';
|
310 |
-
|
311 |
-
$output .= '<div class="options image_tag"'.$image_tag.'>'.__('Dimensions', CFS_LANG_CODE).':<br />';
|
312 |
-
$params->width?$width = $params->width:'';
|
313 |
-
$params->height?$height = $params->height:'';
|
314 |
-
$output .= __('width', CFS_LANG_CODE).':<br />';
|
315 |
-
$output .= htmlCfs::text('params[width]',array('value'=>$width)).'<br />';
|
316 |
-
$output .= __('height', CFS_LANG_CODE).':<br />';
|
317 |
-
$output .= htmlCfs::text('params[height]',array('value'=>$height)).'<br />';
|
318 |
-
$output .= '</div>';
|
319 |
-
}
|
320 |
-
if($this->adapt['htmlParams']) {
|
321 |
-
$output .= fieldAdapterCfs::_($this, $this->adapt['htmlParams'], fieldAdapterCfs::STR);
|
322 |
-
} else {
|
323 |
-
$output .= '<a href="javascript:void(0);" class="set_properties">'.__('Click to set field "id" and "class"', CFS_LANG_CODE).'</a>';
|
324 |
-
$output .= '<div class="attributes" style="display:none;">'.__('Attributes', CFS_LANG_CODE).':<br />';
|
325 |
-
$output .= fieldAdapterCfs::_($params,'getFieldAttributes', fieldAdapterCfs::STR);
|
326 |
-
$output .= '</div>';
|
327 |
-
}
|
328 |
-
return $output;
|
329 |
-
}
|
330 |
-
}
|
331 |
-
|
332 |
-
/**
|
333 |
-
* Check if the element exists in array
|
334 |
-
* @param array $param
|
335 |
-
*/
|
336 |
-
function checkVarFromParam($param, $element) {
|
337 |
-
return utilsCfs::xmlAttrToStr($param, $element);
|
338 |
-
/*if (isset($param[$element])) {
|
339 |
-
// convert object element to string
|
340 |
-
return (string)$param[$element];
|
341 |
-
} else {
|
342 |
-
return '';
|
343 |
-
}*/
|
344 |
-
}
|
345 |
-
|
346 |
-
/**
|
347 |
-
* Prepares configuration options
|
348 |
-
*
|
349 |
-
* @param file $xml
|
350 |
-
* @return array $config_params
|
351 |
-
*/
|
352 |
-
public function prepareConfigOptions($xml) {
|
353 |
-
// load xml structure of parameters
|
354 |
-
$config = simplexml_load_file($xml);
|
355 |
-
$config_params = array();
|
356 |
-
foreach ($config->params->param as $param) {
|
357 |
-
// read the variables
|
358 |
-
$name = $this->checkVarFromParam($param,'name');
|
359 |
-
$type = $this->checkVarFromParam($param,'type');
|
360 |
-
$label = $this->checkVarFromParam($param,'label');
|
361 |
-
$helper = $this->checkVarFromParam($param,'helperCfs');
|
362 |
-
$module = $this->checkVarFromParam($param,'moduleCfs');
|
363 |
-
$values = $this->checkVarFromParam($param,'values');
|
364 |
-
$default = $this->checkVarFromParam($param,'default');
|
365 |
-
$description = $this->checkVarFromParam($param,'description');
|
366 |
-
if ($name == '') continue;
|
367 |
-
// fill in the variables to configuration array
|
368 |
-
$config_params[$name] = array('type'=>$type,
|
369 |
-
'label'=>$label,
|
370 |
-
'helperCfs'=>$helper,
|
371 |
-
'moduleCfs'=>$module,
|
372 |
-
'values'=>$values,
|
373 |
-
'default'=>$default,
|
374 |
-
'description'=>$description,
|
375 |
-
);
|
376 |
-
}
|
377 |
-
return $config_params;
|
378 |
-
}
|
379 |
-
public function setDescription($desc) {
|
380 |
-
$this->description = $desc;
|
381 |
-
}
|
382 |
-
public function getDescription() {
|
383 |
-
return $this->description;
|
384 |
-
}
|
385 |
-
/**
|
386 |
-
* Displays the config options for given module
|
387 |
-
*
|
388 |
-
* @param string $module
|
389 |
-
* @param array $addDefaultOptions - if you want to add some additionsl options - specify it here
|
390 |
-
*/
|
391 |
-
public function drawConfig($module, $additionalOptions = array()) {
|
392 |
-
if(!frameCfs::_()->getModule($module))
|
393 |
-
return false;
|
394 |
-
// check for xml file with params structure
|
395 |
-
if(frameCfs::_()->getModule($module)->isExternal())
|
396 |
-
$config_xml = frameCfs::_()->getModule($module)->getModDir(). 'mod.xml';
|
397 |
-
else
|
398 |
-
$config_xml = CFS_MODULES_DIR.$module.DS.'mod.xml';
|
399 |
-
|
400 |
-
if (!file_exists($config_xml)) {
|
401 |
-
// if there is no configuration file for this $module
|
402 |
-
return __('There are no configuration options for this module', CFS_LANG_CODE);
|
403 |
-
}
|
404 |
-
$output = '';
|
405 |
-
// reading params structure
|
406 |
-
$configOptions = $this->prepareConfigOptions($config_xml);
|
407 |
-
// reading params from database
|
408 |
-
//bugodel2nia..............
|
409 |
-
if(is_string($this->value))
|
410 |
-
$params = Utils::jsonDecode($this->value);
|
411 |
-
elseif(is_object($this->value) || is_array($this->value))
|
412 |
-
$params = toeObjectToArray($this->value);
|
413 |
-
//if (!empty($params)) {
|
414 |
-
if (!empty($configOptions)){
|
415 |
-
$i = 0;
|
416 |
-
if (empty($params)) {
|
417 |
-
$params = array('0'=>array());
|
418 |
-
}
|
419 |
-
if(is_array($additionalOptions) && !empty($additionalOptions)) {
|
420 |
-
$configOptions = array_merge($configOptions, $additionalOptions);
|
421 |
-
}
|
422 |
-
foreach ($params as $param) {
|
423 |
-
$output .= '<div class="module_options">';
|
424 |
-
foreach ($configOptions as $key=>$value){
|
425 |
-
$fieldValue = '';
|
426 |
-
$output .= '<div class="module_option">';
|
427 |
-
$method = $configOptions[$key]['type'];
|
428 |
-
$name = 'params['.$i.']['.$key.']';
|
429 |
-
$options = array();
|
430 |
-
// if the values attribute is set
|
431 |
-
if ($configOptions[$key]['values'] != ''){
|
432 |
-
$extract_options = explode(',', $configOptions[$key]['values']);
|
433 |
-
if (count($extract_options) > 1) {
|
434 |
-
foreach ($extract_options as $item=>$string) {
|
435 |
-
if(strpos($string, '=>')) {
|
436 |
-
$keyVal = array_map('trim', explode('=>', $string));
|
437 |
-
$options[ $keyVal[0] ] = $keyVal[1];
|
438 |
-
} else {
|
439 |
-
$options[$string] = $string;
|
440 |
-
}
|
441 |
-
}
|
442 |
-
} else {
|
443 |
-
$fieldValue = $configOptions[$key]['default'];
|
444 |
-
}
|
445 |
-
// if helper is needed to render the object
|
446 |
-
} elseif ($configOptions[$key]['helper'] != '') {
|
447 |
-
$helper_name = $configOptions[$key]['helper'];
|
448 |
-
// is helper from current module or other?
|
449 |
-
if ($configOptions[$key]['module'] != '') {
|
450 |
-
$hmodule = $configOptions[$key]['module'];
|
451 |
-
} else {
|
452 |
-
$hmodule = $module;
|
453 |
-
}
|
454 |
-
// calling the helper class
|
455 |
-
$helper = frameCfs::_()->getModule($hmodule)->getHelper();
|
456 |
-
if ($helper) {
|
457 |
-
// calling the helper method for current option
|
458 |
-
if (method_exists($helper, $helper_name))
|
459 |
-
$options = $helper->$helper_name();
|
460 |
-
}
|
461 |
-
}
|
462 |
-
if (isset($param[$key])) {
|
463 |
-
$fieldValue = $param[$key];
|
464 |
-
} else {
|
465 |
-
if ($fieldValue == '')
|
466 |
-
$fieldValue = $configOptions[$key]['default'];
|
467 |
-
}
|
468 |
-
// filling the parameters to build html element
|
469 |
-
$htmlParams = array('value'=>$fieldValue,'optionsCfs'=>$options);
|
470 |
-
if($method == 'checkbox') {
|
471 |
-
$htmlParams['value'] = 1;
|
472 |
-
$htmlParams['checked'] = (bool)$fieldValue;
|
473 |
-
}
|
474 |
-
if(!empty($configOptions[$key]['htmlParams']) && is_array($configOptions[$key]['htmlParams'])) {
|
475 |
-
$htmlParams = array_merge($htmlParams, $configOptions[$key]['htmlParams']);
|
476 |
-
}
|
477 |
-
// output label and html element
|
478 |
-
$output .= '<label>'.__($configOptions[$key]['label']);
|
479 |
-
if ($configOptions[$key]['description'] != '') {
|
480 |
-
$output .= '<a class="toeOptTip" tip="'.__($configOptions[$key]['description']).'"></a>';
|
481 |
-
}
|
482 |
-
$output .= '</label><br />';
|
483 |
-
$output .= htmlCfs::$method($name,$htmlParams).'<br />';
|
484 |
-
$output .= '</div>';
|
485 |
-
}
|
486 |
-
$i++;
|
487 |
-
$output .= '</div>';
|
488 |
-
}
|
489 |
-
}
|
490 |
-
return $output;
|
491 |
-
}
|
492 |
-
|
493 |
-
public function displayConfig($module) {
|
494 |
-
echo $this->drawConfig($module);
|
495 |
-
}
|
496 |
-
/**
|
497 |
-
* This method will prepare internal value to it's type
|
498 |
-
* @see $this->type
|
499 |
-
* @return mixed - prepared value on the basis of $this->type
|
500 |
-
*/
|
501 |
-
public function valToType() {
|
502 |
-
switch($this->type) {
|
503 |
-
case 'int':
|
504 |
-
case 'mediumint':
|
505 |
-
case 'smallint':
|
506 |
-
$this->value = (int) $this->value;
|
507 |
-
break;
|
508 |
-
case 'float':
|
509 |
-
$this->value = (float) $this->value;
|
510 |
-
break;
|
511 |
-
case 'double':
|
512 |
-
case 'decimal':
|
513 |
-
$this->value = (double) $this->value;
|
514 |
-
break;
|
515 |
-
}
|
516 |
-
return $this->type;
|
517 |
-
}
|
518 |
-
}
|
1 |
+
<?php
|
2 |
+
class fieldCfs {
|
3 |
+
public $name = '';
|
4 |
+
public $html = '';
|
5 |
+
public $type = '';
|
6 |
+
public $default = '';
|
7 |
+
public $value = '';
|
8 |
+
public $label = '';
|
9 |
+
public $maxlen = 0;
|
10 |
+
public $id = 0;
|
11 |
+
public $htmlParams = array();
|
12 |
+
public $validate = array();
|
13 |
+
public $description = '';
|
14 |
+
/**
|
15 |
+
* Wheter or not add error html element right after input field
|
16 |
+
* if bool - will be added standard element
|
17 |
+
* if string - it will be add this string
|
18 |
+
*/
|
19 |
+
public $errorEl = false;
|
20 |
+
/**
|
21 |
+
* Name of method in table object to prepare data before insert / update operations
|
22 |
+
*/
|
23 |
+
public $adapt = array('htmlCfs' => '', 'dbFrom' => '', 'dbTo' => '');
|
24 |
+
/**
|
25 |
+
* Init database field representation
|
26 |
+
* @param string $html html type of field (text, textarea, etc. @see html class)
|
27 |
+
* @param string $type database type (int, varcahr, etc.)
|
28 |
+
* @param mixed $default default value for this field
|
29 |
+
*/
|
30 |
+
public function __construct($name, $html = 'text', $type = 'other', $default = '', $label = '', $maxlen = 0, $adaption = array(), $validate = '', $description = '') {
|
31 |
+
$this->name = $name;
|
32 |
+
$this->html = $html;
|
33 |
+
$this->type = $type;
|
34 |
+
$this->default = $default;
|
35 |
+
$this->value = $default; //Init field value same as default
|
36 |
+
$this->label = $label;
|
37 |
+
$this->maxlen = $maxlen;
|
38 |
+
$this->description = $description;
|
39 |
+
if($adaption)
|
40 |
+
$this->adapt = $adaption;
|
41 |
+
if($validate) {
|
42 |
+
$this->setValidation($validate);
|
43 |
+
}
|
44 |
+
if($type == 'varchar' && !empty($maxlen) && !in_array('validLen', $this->validate)) {
|
45 |
+
$this->addValidation('validLen');
|
46 |
+
}
|
47 |
+
}
|
48 |
+
/**
|
49 |
+
* @param mixed $errorEl - if bool and "true" - than we will use standard error element, if string - we will use this string as error element
|
50 |
+
*/
|
51 |
+
public function setErrorEl($errorEl) {
|
52 |
+
$this->errorEl = $errorEl;
|
53 |
+
}
|
54 |
+
public function getErrorEl() {
|
55 |
+
return $this->errorEl;
|
56 |
+
}
|
57 |
+
public function setValidation($validate) {
|
58 |
+
if(is_array($validate))
|
59 |
+
$this->validate = $validate;
|
60 |
+
else {
|
61 |
+
if(strpos($validate, ','))
|
62 |
+
$this->validate = array_map('trim', explode(',', $validate));
|
63 |
+
else
|
64 |
+
$this->validate = array(trim($validate));
|
65 |
+
}
|
66 |
+
}
|
67 |
+
public function addValidation($validate) {
|
68 |
+
$this->validate[] = $validate;
|
69 |
+
}
|
70 |
+
/**
|
71 |
+
* Set $value property.
|
72 |
+
* Sure - it is public and can be set directly, but it can be more
|
73 |
+
* comfortable to use this method in future
|
74 |
+
* @param mixed $value value to be set
|
75 |
+
*/
|
76 |
+
public function setValue($value, $fromDB = false) {
|
77 |
+
if(isset($this->adapt['dbFrom']) && $this->adapt['dbFrom'] && $fromDB)
|
78 |
+
$value = fieldAdapterCfs::_($value, $this->adapt['dbFrom'], fieldAdapterCfs::DB);
|
79 |
+
$this->value = $value;
|
80 |
+
}
|
81 |
+
public function setLabel($label) {
|
82 |
+
$this->label = $label;
|
83 |
+
}
|
84 |
+
public function setHtml($html) {
|
85 |
+
$this->html = $html;
|
86 |
+
}
|
87 |
+
public function getHtml() {
|
88 |
+
return $this->html;
|
89 |
+
}
|
90 |
+
public function setName($name) {
|
91 |
+
$this->name = $name;
|
92 |
+
}
|
93 |
+
public function getName() {
|
94 |
+
return $this->name;
|
95 |
+
}
|
96 |
+
public function getValue() {
|
97 |
+
return $this->value;
|
98 |
+
}
|
99 |
+
public function getLabel() {
|
100 |
+
return $this->label;
|
101 |
+
}
|
102 |
+
public function setID($id) {
|
103 |
+
$this->id = $id;
|
104 |
+
}
|
105 |
+
public function getID() {
|
106 |
+
return $this->id;
|
107 |
+
}
|
108 |
+
public function setAdapt($adapt) {
|
109 |
+
$this->adapt = $adapt;
|
110 |
+
}
|
111 |
+
public function drawHtml($tag, $id) {
|
112 |
+
if(method_exists('htmlCfs', $this->html)) {
|
113 |
+
$method = $this->html;
|
114 |
+
//echo $this->name. ': '. $this->value. '<br />';
|
115 |
+
if(!empty($this->value))
|
116 |
+
$this->htmlParams['value'] = $this->value;
|
117 |
+
if ($method == 'checkbox') {
|
118 |
+
if ($this->value == 1) {
|
119 |
+
$this->htmlParams['checked'] = 1;
|
120 |
+
}
|
121 |
+
}
|
122 |
+
if($this->adapt['html']) {
|
123 |
+
fieldAdapterCfs::_($this, $this->adapt['html'], fieldAdapterCfs::HTML);
|
124 |
+
}
|
125 |
+
$params = $this->processParams($tag, $id);
|
126 |
+
if ($params != '')
|
127 |
+
return $params;
|
128 |
+
if ($this->name == 'default_value') {
|
129 |
+
$optionsFromDb = frameCfs::_()->getModule('optionsCfs')->getHelper()->getOptions($id);
|
130 |
+
if (!empty($optionsFromDb)) {
|
131 |
+
$options = array(0 => __('Select', CFS_LANG_CODE));
|
132 |
+
foreach($optionsFromDb as $k => $v)
|
133 |
+
$options[$k] = $v;
|
134 |
+
$method = 'selectbox';
|
135 |
+
$this->htmlParams['optionsCfs'] = $options;
|
136 |
+
}
|
137 |
+
}
|
138 |
+
$htmlContent = htmlCfs::$method($this->name, $this->htmlParams);
|
139 |
+
if(!empty($this->errorEl)) {
|
140 |
+
if(is_bool($this->errorEl))
|
141 |
+
$errorEl = '<div class="toeErrorForField toe_'. htmlCfs::nameToClassId($this->name). '"></div>';
|
142 |
+
else //if it is string
|
143 |
+
$errorEl = $this->errorEl;
|
144 |
+
$htmlContent .= $errorEl;
|
145 |
+
}
|
146 |
+
return $htmlContent;
|
147 |
+
}
|
148 |
+
return false;
|
149 |
+
}
|
150 |
+
public function displayValue() {
|
151 |
+
$value = '';
|
152 |
+
switch($this->html) {
|
153 |
+
case 'countryList':
|
154 |
+
$value = fieldAdapterCfs::displayCountry($this->value);
|
155 |
+
break;
|
156 |
+
case 'statesList':
|
157 |
+
$value = fieldAdapterCfs::displayState($this->value);
|
158 |
+
break;
|
159 |
+
case 'checkboxlist':
|
160 |
+
$options = $this->getHtmlParam('optionsCfs');
|
161 |
+
$value = array();
|
162 |
+
if(!empty($options) && is_array($options)) {
|
163 |
+
foreach($options as $opt) {
|
164 |
+
if(isset($opt['checked']) && $opt['checked']) {
|
165 |
+
$value[] = $opt['text'];
|
166 |
+
}
|
167 |
+
}
|
168 |
+
}
|
169 |
+
if(empty($value))
|
170 |
+
$value = __('N/A', CFS_LANG_CODE);
|
171 |
+
else
|
172 |
+
$value = implode('<br />', $value);
|
173 |
+
break;
|
174 |
+
case 'selectbox': case 'radiobuttons':
|
175 |
+
$options = $this->getHtmlParam('optionsCfs');
|
176 |
+
if(!empty($options) && !empty($options[ $this->value ])) {
|
177 |
+
$value = $options[ $this->value ];
|
178 |
+
} else {
|
179 |
+
$value = __('N/A', CFS_LANG_CODE);
|
180 |
+
}
|
181 |
+
break;
|
182 |
+
default:
|
183 |
+
if ($this->value == '') {
|
184 |
+
$value = __('N/A', CFS_LANG_CODE);
|
185 |
+
} else {
|
186 |
+
if(is_array($this->value)) {
|
187 |
+
$options = $this->getHtmlParam('optionsCfs');
|
188 |
+
if(!empty($options) && is_array($options)) {
|
189 |
+
$valArr = array();
|
190 |
+
foreach($this->value as $v) {
|
191 |
+
$valArr[] = $options[$v];
|
192 |
+
}
|
193 |
+
$value = recImplode('<br />', $valArr);
|
194 |
+
} else {
|
195 |
+
$value = recImplode('<br />', $this->value);
|
196 |
+
}
|
197 |
+
} else
|
198 |
+
$value = $this->value;
|
199 |
+
}
|
200 |
+
break;
|
201 |
+
}
|
202 |
+
if($echo)
|
203 |
+
echo $value;
|
204 |
+
else
|
205 |
+
return $value;
|
206 |
+
}
|
207 |
+
public function showValue() {
|
208 |
+
echo $this->displayValue();
|
209 |
+
}
|
210 |
+
public function display($tag = 1, $id = 0) {
|
211 |
+
echo $this->drawHtml($tag, $id);
|
212 |
+
}
|
213 |
+
public function addHtmlParam($name, $value) {
|
214 |
+
$this->htmlParams[$name] = $value;
|
215 |
+
}
|
216 |
+
/**
|
217 |
+
* Alias for addHtmlParam();
|
218 |
+
*/
|
219 |
+
public function setHtmlParam($name, $value) {
|
220 |
+
$this->addHtmlParam($name, $value);
|
221 |
+
}
|
222 |
+
public function setHtmlParams($params) {
|
223 |
+
$this->htmlParams = $params;
|
224 |
+
}
|
225 |
+
public function getHtmlParam($name) {
|
226 |
+
return isset($this->htmlParams[$name]) ? $this->htmlParams[$name] : false;
|
227 |
+
}
|
228 |
+
/**
|
229 |
+
* Function to display userfields in front-end
|
230 |
+
*
|
231 |
+
* @param string $name
|
232 |
+
* @param mixed $fieldValue
|
233 |
+
* @return string
|
234 |
+
*/
|
235 |
+
public function viewField($name, $fieldValue = '') {
|
236 |
+
$method = $this->html;
|
237 |
+
$options = frameCfs::_()->getModule('optionsCfs')->getHelper()->getOptions($this->id);
|
238 |
+
$attrs = '';
|
239 |
+
if (is_object($this->htmlParams['attr']) && count($this->htmlParams['attr']) > 0) {
|
240 |
+
foreach ($this->htmlParams['attr'] as $attribute=>$value) {
|
241 |
+
if ($value != '') {
|
242 |
+
$attrs .= $attribute.'="'.$value.'" ';
|
243 |
+
}
|
244 |
+
}
|
245 |
+
}
|
246 |
+
if ($fieldValue == $this->default_value) {
|
247 |
+
$checked = 1;
|
248 |
+
} else {
|
249 |
+
$checked = 0;
|
250 |
+
}
|
251 |
+
if ($fieldValue == '') {
|
252 |
+
$fieldValue = $this->default_value;
|
253 |
+
}
|
254 |
+
$params = array('optionsCfs'=>$options, 'attrs' => $attrs, 'value' => $fieldValue, 'checked' => $checked);
|
255 |
+
$output = '';
|
256 |
+
if(method_exists('htmlCfs', $method)) {
|
257 |
+
$output .= htmlCfs::$method($name, $params);
|
258 |
+
$output .= htmlCfs::hidden('extra_field['.$this->name.']',array('value'=>$this->id));
|
259 |
+
}
|
260 |
+
return $output;
|
261 |
+
}
|
262 |
+
|
263 |
+
/**
|
264 |
+
* Function to process field params
|
265 |
+
*/
|
266 |
+
public function processParams($tag, $id){
|
267 |
+
return '';
|
268 |
+
if ($this->name == "params") {
|
269 |
+
if(is_array($this->value) || is_object($this->value)) {
|
270 |
+
$params = $this->value;
|
271 |
+
} else {
|
272 |
+
$params = json_decode($this->value);
|
273 |
+
}
|
274 |
+
$add_option = '';
|
275 |
+
switch ($tag) {
|
276 |
+
case 5:
|
277 |
+
$add_option = __('Add Checkbox', CFS_LANG_CODE);
|
278 |
+
$options_tag = '';
|
279 |
+
$image_tag = ' style="display:none"';
|
280 |
+
break;
|
281 |
+
case 9:
|
282 |
+
$add_option = __('Add Item', CFS_LANG_CODE);
|
283 |
+
$options_tag = '';
|
284 |
+
$image_tag = ' style="display:none"';
|
285 |
+
break;
|
286 |
+
case 12:
|
287 |
+
$add_option = __('Add Item', CFS_LANG_CODE);
|
288 |
+
$options_tag = '';
|
289 |
+
$image_tag = ' style="display:none"';
|
290 |
+
break;
|
291 |
+
case 10:
|
292 |
+
$options_tag = '';
|
293 |
+
$add_option = __('Add Radio Button', CFS_LANG_CODE);
|
294 |
+
$image_tag = ' style="display:none"';
|
295 |
+
break;
|
296 |
+
case 8:
|
297 |
+
$image_tag = '';
|
298 |
+
$options_tag = ' style="display:none"';
|
299 |
+
break;
|
300 |
+
default:
|
301 |
+
$options_tag = ' style="display:none"';
|
302 |
+
$image_tag = ' style="display:none"';
|
303 |
+
break;
|
304 |
+
}
|
305 |
+
if ($tag > 0 || $id == 0) {
|
306 |
+
$output .= '<div class="options options_tag"'.$options_tag.'>';
|
307 |
+
$output .= '<span class="add_option">'.$add_option.'</span>';
|
308 |
+
$output .= fieldAdapterCfs::_($id,'getExtraFieldOptions',fieldAdapterCfs::STR);
|
309 |
+
$output .= '</div>';
|
310 |
+
|
311 |
+
$output .= '<div class="options image_tag"'.$image_tag.'>'.__('Dimensions', CFS_LANG_CODE).':<br />';
|
312 |
+
$params->width?$width = $params->width:'';
|
313 |
+
$params->height?$height = $params->height:'';
|
314 |
+
$output .= __('width', CFS_LANG_CODE).':<br />';
|
315 |
+
$output .= htmlCfs::text('params[width]',array('value'=>$width)).'<br />';
|
316 |
+
$output .= __('height', CFS_LANG_CODE).':<br />';
|
317 |
+
$output .= htmlCfs::text('params[height]',array('value'=>$height)).'<br />';
|
318 |
+
$output .= '</div>';
|
319 |
+
}
|
320 |
+
if($this->adapt['htmlParams']) {
|
321 |
+
$output .= fieldAdapterCfs::_($this, $this->adapt['htmlParams'], fieldAdapterCfs::STR);
|
322 |
+
} else {
|
323 |
+
$output .= '<a href="javascript:void(0);" class="set_properties">'.__('Click to set field "id" and "class"', CFS_LANG_CODE).'</a>';
|
324 |
+
$output .= '<div class="attributes" style="display:none;">'.__('Attributes', CFS_LANG_CODE).':<br />';
|
325 |
+
$output .= fieldAdapterCfs::_($params,'getFieldAttributes', fieldAdapterCfs::STR);
|
326 |
+
$output .= '</div>';
|
327 |
+
}
|
328 |
+
return $output;
|
329 |
+
}
|
330 |
+
}
|
331 |
+
|
332 |
+
/**
|
333 |
+
* Check if the element exists in array
|
334 |
+
* @param array $param
|
335 |
+
*/
|
336 |
+
function checkVarFromParam($param, $element) {
|
337 |
+
return utilsCfs::xmlAttrToStr($param, $element);
|
338 |
+
/*if (isset($param[$element])) {
|
339 |
+
// convert object element to string
|
340 |
+
return (string)$param[$element];
|
341 |
+
} else {
|
342 |
+
return '';
|
343 |
+
}*/
|
344 |
+
}
|
345 |
+
|
346 |
+
/**
|
347 |
+
* Prepares configuration options
|
348 |
+
*
|
349 |
+
* @param file $xml
|
350 |
+
* @return array $config_params
|
351 |
+
*/
|
352 |
+
public function prepareConfigOptions($xml) {
|
353 |
+
// load xml structure of parameters
|
354 |
+
$config = simplexml_load_file($xml);
|
355 |
+
$config_params = array();
|
356 |
+
foreach ($config->params->param as $param) {
|
357 |
+
// read the variables
|
358 |
+
$name = $this->checkVarFromParam($param,'name');
|
359 |
+
$type = $this->checkVarFromParam($param,'type');
|
360 |
+
$label = $this->checkVarFromParam($param,'label');
|
361 |
+
$helper = $this->checkVarFromParam($param,'helperCfs');
|
362 |
+
$module = $this->checkVarFromParam($param,'moduleCfs');
|
363 |
+
$values = $this->checkVarFromParam($param,'values');
|
364 |
+
$default = $this->checkVarFromParam($param,'default');
|
365 |
+
$description = $this->checkVarFromParam($param,'description');
|
366 |
+
if ($name == '') continue;
|
367 |
+
// fill in the variables to configuration array
|
368 |
+
$config_params[$name] = array('type'=>$type,
|
369 |
+
'label'=>$label,
|
370 |
+
'helperCfs'=>$helper,
|
371 |
+
'moduleCfs'=>$module,
|
372 |
+
'values'=>$values,
|
373 |
+
'default'=>$default,
|
374 |
+
'description'=>$description,
|
375 |
+
);
|
376 |
+
}
|
377 |
+
return $config_params;
|
378 |
+
}
|
379 |
+
public function setDescription($desc) {
|
380 |
+
$this->description = $desc;
|
381 |
+
}
|
382 |
+
public function getDescription() {
|
383 |
+
return $this->description;
|
384 |
+
}
|
385 |
+
/**
|
386 |
+
* Displays the config options for given module
|
387 |
+
*
|
388 |
+
* @param string $module
|
389 |
+
* @param array $addDefaultOptions - if you want to add some additionsl options - specify it here
|
390 |
+
*/
|
391 |
+
public function drawConfig($module, $additionalOptions = array()) {
|
392 |
+
if(!frameCfs::_()->getModule($module))
|
393 |
+
return false;
|
394 |
+
// check for xml file with params structure
|
395 |
+
if(frameCfs::_()->getModule($module)->isExternal())
|
396 |
+
$config_xml = frameCfs::_()->getModule($module)->getModDir(). 'mod.xml';
|
397 |
+
else
|
398 |
+
$config_xml = CFS_MODULES_DIR.$module.DS.'mod.xml';
|
399 |
+
|
400 |
+
if (!file_exists($config_xml)) {
|
401 |
+
// if there is no configuration file for this $module
|
402 |
+
return __('There are no configuration options for this module', CFS_LANG_CODE);
|
403 |
+
}
|
404 |
+
$output = '';
|
405 |
+
// reading params structure
|
406 |
+
$configOptions = $this->prepareConfigOptions($config_xml);
|
407 |
+
// reading params from database
|
408 |
+
//bugodel2nia..............
|
409 |
+
if(is_string($this->value))
|
410 |
+
$params = Utils::jsonDecode($this->value);
|
411 |
+
elseif(is_object($this->value) || is_array($this->value))
|
412 |
+
$params = toeObjectToArray($this->value);
|
413 |
+
//if (!empty($params)) {
|
414 |
+
if (!empty($configOptions)){
|
415 |
+
$i = 0;
|
416 |
+
if (empty($params)) {
|
417 |
+
$params = array('0'=>array());
|
418 |
+
}
|
419 |
+
if(is_array($additionalOptions) && !empty($additionalOptions)) {
|
420 |
+
$configOptions = array_merge($configOptions, $additionalOptions);
|
421 |
+
}
|
422 |
+
foreach ($params as $param) {
|
423 |
+
$output .= '<div class="module_options">';
|
424 |
+
foreach ($configOptions as $key=>$value){
|
425 |
+
$fieldValue = '';
|
426 |
+
$output .= '<div class="module_option">';
|
427 |
+
$method = $configOptions[$key]['type'];
|
428 |
+
$name = 'params['.$i.']['.$key.']';
|
429 |
+
$options = array();
|
430 |
+
// if the values attribute is set
|
431 |
+
if ($configOptions[$key]['values'] != ''){
|
432 |
+
$extract_options = explode(',', $configOptions[$key]['values']);
|
433 |
+
if (count($extract_options) > 1) {
|
434 |
+
foreach ($extract_options as $item=>$string) {
|
435 |
+
if(strpos($string, '=>')) {
|
436 |
+
$keyVal = array_map('trim', explode('=>', $string));
|
437 |
+
$options[ $keyVal[0] ] = $keyVal[1];
|
438 |
+
} else {
|
439 |
+
$options[$string] = $string;
|
440 |
+
}
|
441 |
+
}
|
442 |
+
} else {
|
443 |
+
$fieldValue = $configOptions[$key]['default'];
|
444 |
+
}
|
445 |
+
// if helper is needed to render the object
|
446 |
+
} elseif ($configOptions[$key]['helper'] != '') {
|
447 |
+
$helper_name = $configOptions[$key]['helper'];
|
448 |
+
// is helper from current module or other?
|
449 |
+
if ($configOptions[$key]['module'] != '') {
|
450 |
+
$hmodule = $configOptions[$key]['module'];
|
451 |
+
} else {
|
452 |
+
$hmodule = $module;
|
453 |
+
}
|
454 |
+
// calling the helper class
|
455 |
+
$helper = frameCfs::_()->getModule($hmodule)->getHelper();
|
456 |
+
if ($helper) {
|
457 |
+
// calling the helper method for current option
|
458 |
+
if (method_exists($helper, $helper_name))
|
459 |
+
$options = $helper->$helper_name();
|
460 |
+
}
|
461 |
+
}
|
462 |
+
if (isset($param[$key])) {
|
463 |
+
$fieldValue = $param[$key];
|
464 |
+
} else {
|
465 |
+
if ($fieldValue == '')
|
466 |
+
$fieldValue = $configOptions[$key]['default'];
|
467 |
+
}
|
468 |
+
// filling the parameters to build html element
|
469 |
+
$htmlParams = array('value'=>$fieldValue,'optionsCfs'=>$options);
|
470 |
+
if($method == 'checkbox') {
|
471 |
+
$htmlParams['value'] = 1;
|
472 |
+
$htmlParams['checked'] = (bool)$fieldValue;
|
473 |
+
}
|
474 |
+
if(!empty($configOptions[$key]['htmlParams']) && is_array($configOptions[$key]['htmlParams'])) {
|
475 |
+
$htmlParams = array_merge($htmlParams, $configOptions[$key]['htmlParams']);
|
476 |
+
}
|
477 |
+
// output label and html element
|
478 |
+
$output .= '<label>'.__($configOptions[$key]['label']);
|
479 |
+
if ($configOptions[$key]['description'] != '') {
|
480 |
+
$output .= '<a class="toeOptTip" tip="'.__($configOptions[$key]['description']).'"></a>';
|
481 |
+
}
|
482 |
+
$output .= '</label><br />';
|
483 |
+
$output .= htmlCfs::$method($name,$htmlParams).'<br />';
|
484 |
+
$output .= '</div>';
|
485 |
+
}
|
486 |
+
$i++;
|
487 |
+
$output .= '</div>';
|
488 |
+
}
|
489 |
+
}
|
490 |
+
return $output;
|
491 |
+
}
|
492 |
+
|
493 |
+
public function displayConfig($module) {
|
494 |
+
echo $this->drawConfig($module);
|
495 |
+
}
|
496 |
+
/**
|
497 |
+
* This method will prepare internal value to it's type
|
498 |
+
* @see $this->type
|
499 |
+
* @return mixed - prepared value on the basis of $this->type
|
500 |
+
*/
|
501 |
+
public function valToType() {
|
502 |
+
switch($this->type) {
|
503 |
+
case 'int':
|
504 |
+
case 'mediumint':
|
505 |
+
case 'smallint':
|
506 |
+
$this->value = (int) $this->value;
|
507 |
+
break;
|
508 |
+
case 'float':
|
509 |
+
$this->value = (float) $this->value;
|
510 |
+
break;
|
511 |
+
case 'double':
|
512 |
+
case 'decimal':
|
513 |
+
$this->value = (double) $this->value;
|
514 |
+
break;
|
515 |
+
}
|
516 |
+
return $this->type;
|
517 |
+
}
|
518 |
+
}
|
classes/fieldAdapter.php
CHANGED
@@ -1,310 +1,315 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* Class to adapt field before display
|
4 |
-
* return ONLY htmlParams property
|
5 |
-
* @see field
|
6 |
-
*/
|
7 |
-
class fieldAdapterCfs {
|
8 |
-
const DB = 'dbCfs';
|
9 |
-
const HTML = 'htmlCfs';
|
10 |
-
const STR = 'str';
|
11 |
-
static public $userfieldDest = array('registration', 'shipping', 'billing');
|
12 |
-
static public $countries = array();
|
13 |
-
static public $states = array();
|
14 |
-
/**
|
15 |
-
* Executes field Adaption process
|
16 |
-
* @param object type field or value $fieldOrValue if DB adaption - this must be a value of field, elase if html - field object
|
17 |
-
*/
|
18 |
-
static public function _($fieldOrValue, $method, $type) {
|
19 |
-
if(method_exists('fieldAdapterCfs', $method)) {
|
20 |
-
switch($type) {
|
21 |
-
case self::DB:
|
22 |
-
return self::$method($fieldOrValue);
|
23 |
-
break;
|
24 |
-
case self::HTML:
|
25 |
-
self::$method($fieldOrValue);
|
26 |
-
break;
|
27 |
-
case self::STR:
|
28 |
-
return self::$method($fieldOrValue);
|
29 |
-
break;
|
30 |
-
}
|
31 |
-
}
|
32 |
-
return $fieldOrValue;
|
33 |
-
}
|
34 |
-
static public function userFieldDestHtml($field) {
|
35 |
-
$field->htmlParams['optionsCfs'] = array();
|
36 |
-
if(!is_array($field->value)) {
|
37 |
-
if(empty($field->value))
|
38 |
-
$field->value = array();
|
39 |
-
else
|
40 |
-
$field->value = json_decode($field->value);
|
41 |
-
}
|
42 |
-
foreach(self::$userfieldDest as $d) {
|
43 |
-
$field->htmlParams['optionsCfs'][] = array(
|
44 |
-
'id' => $d,
|
45 |
-
'text' => $d,
|
46 |
-
'checked' => in_array($d, $field->value)
|
47 |
-
);
|
48 |
-
}
|
49 |
-
}
|
50 |
-
static public function userFieldDestToDB($value) {
|
51 |
-
return utilsCfs::jsonEncode($value);
|
52 |
-
}
|
53 |
-
static public function userFieldDestFromDB($value) {
|
54 |
-
return utilsCfs::jsonDecode($value);
|
55 |
-
}
|
56 |
-
static public function taxDataHtml($field) {
|
57 |
-
$listOfDest = array();
|
58 |
-
if(!is_array($field->value)) {
|
59 |
-
if(empty($field->value))
|
60 |
-
$field->value = array();
|
61 |
-
else
|
62 |
-
$field->value = (array)json_decode($field->value, true);
|
63 |
-
}
|
64 |
-
foreach(self::$userfieldDest as $d) {
|
65 |
-
$listOfDest[] = array(
|
66 |
-
'id' => $d,
|
67 |
-
'text' => $d,
|
68 |
-
'checked' => (is_array($field->value['dest']) && in_array($d, $field->value['dest']))
|
69 |
-
);
|
70 |
-
}
|
71 |
-
$categories = frameCfs::_()->getModule('products')->getCategories();
|
72 |
-
$brands = frameCfs::_()->getModule('products')->getBrands();
|
73 |
-
$cOptions = array();
|
74 |
-
$bOptions = array();
|
75 |
-
if(!empty($categories)) {
|
76 |
-
if(!is_array($field->value['categories']))
|
77 |
-
$field->value['categories'] = array();
|
78 |
-
foreach($categories as $c) {
|
79 |
-
$cOptions[] = array('id' => $c->term_taxonomy_id,
|
80 |
-
'text' => $c->cat_name,
|
81 |
-
'checked' => in_array($c->term_taxonomy_id, $field->value['categories']));
|
82 |
-
}
|
83 |
-
}
|
84 |
-
if(!empty($brands)) {
|
85 |
-
if(!is_array($field->value['brands']))
|
86 |
-
$field->value['brands'] = array();
|
87 |
-
foreach($brands as $b) {
|
88 |
-
$bOptions[] = array('id' => $b->term_taxonomy_id,
|
89 |
-
'text' => $b->cat_name,
|
90 |
-
'checked' => in_array($b->term_taxonomy_id, $field->value['brands']));
|
91 |
-
}
|
92 |
-
}
|
93 |
-
return '<div>'. __('Apply To', CFS_LANG_CODE). '
|
94 |
-
<div id="tax_address">
|
95 |
-
<b>'. __('Address', CFS_LANG_CODE). '</b><br />
|
96 |
-
'. __('Destination', CFS_LANG_CODE). ':'. htmlCfs::checkboxlist('params[dest]', array('optionsCfs' => $listOfDest)). '<br />
|
97 |
-
'. __('Country', CFS_LANG_CODE). ':'. htmlCfs::countryList('params[country]', array('notSelected' => true, 'value' => $field->value['country'])). '<br />
|
98 |
-
</div>
|
99 |
-
<div id="tax_category">
|
100 |
-
<b>'. __('Categories', CFS_LANG_CODE). '</b><br />
|
101 |
-
'. (empty($cOptions) ? __('You have no categories', CFS_LANG_CODE) : htmlCfs::checkboxlist('params[categories][]', array('optionsCfs' => $cOptions))). '<br />
|
102 |
-
<b>'. __('Brands', CFS_LANG_CODE). '</b><br />
|
103 |
-
'. (empty($bOptions) ? __('You have no brands', CFS_LANG_CODE) : htmlCfs::checkboxlist('params[brands][]', array('optionsCfs' => $bOptions))). '<br />
|
104 |
-
</div>
|
105 |
-
<div>'. __('Tax Rate', CFS_LANG_CODE).': '. htmlCfs::text('params[rate]', array('value' => $field->value['rate'])).'</div>
|
106 |
-
<div>'. __('Absolute', CFS_LANG_CODE).': '. htmlCfs::checkbox('params[absolute]', array('checked' => $field->value['absolute'])).'</div>
|
107 |
-
</div>';
|
108 |
-
}
|
109 |
-
static public function displayCountry($cid, $key = 'name') {
|
110 |
-
if($key == 'name') {
|
111 |
-
$countries = self::getCountries();
|
112 |
-
return $countries[$cid];
|
113 |
-
} else {
|
114 |
-
if(empty(self::$countries))
|
115 |
-
self::$countries = self::getCachedCountries();
|
116 |
-
foreach(self::$countries as $c) {
|
117 |
-
if($c['id'] == $cid)
|
118 |
-
return $c[ $key ];
|
119 |
-
}
|
120 |
-
}
|
121 |
-
return false;
|
122 |
-
}
|
123 |
-
static public function displayState($sid, $key = 'name') {
|
124 |
-
$states = self::getStates();
|
125 |
-
return empty($states[$sid]) ? $sid : $states[$sid][$key];
|
126 |
-
}
|
127 |
-
static public function getCountries($notSelected = false, $listBy = 'id') {
|
128 |
-
$options = array();
|
129 |
-
if(empty(self::$countries))
|
130 |
-
self::$countries = self::getCachedCountries();
|
131 |
-
if($notSelected) {
|
132 |
-
$options[0] = is_bool($notSelected) ? __('Not selected', CFS_LANG_CODE) : __($notSelected);
|
133 |
-
}
|
134 |
-
foreach(self::$countries as $c) {
|
135 |
-
$options[$c[ $listBy ]] = $c['name'];
|
136 |
-
}
|
137 |
-
return $options;
|
138 |
-
}
|
139 |
-
static public function getStates($notSelected = false) {
|
140 |
-
static $options = array();
|
141 |
-
if(empty($options[ $notSelected ])) {
|
142 |
-
$options[ $notSelected ] = array();
|
143 |
-
if(empty(self::$states))
|
144 |
-
self::$states = self::getCachedStates();
|
145 |
-
if($notSelected) {
|
146 |
-
$notSelectedLabel = is_bool($notSelected) ? 'Not selected' : $notSelected;
|
147 |
-
$options[ $notSelected ][0] = array('name' => __( $notSelectedLabel ), 'country_id' => NULL);
|
148 |
-
}
|
149 |
-
foreach(self::$states as $s) $options[ $notSelected ][$s['id']] = $s;
|
150 |
-
}
|
151 |
-
return $options[ $notSelected ];
|
152 |
-
}
|
153 |
-
/**
|
154 |
-
* Function to get extra field options
|
155 |
-
*
|
156 |
-
* @param object $field
|
157 |
-
* @return string
|
158 |
-
*/
|
159 |
-
static public function getExtraFieldOptions($field_id) {
|
160 |
-
$output = '';
|
161 |
-
if ($field_id == 0) return '';
|
162 |
-
$options = frameCfs::_()->getModule('optionsCfs')->getHelper()->getOptions($field_id);
|
163 |
-
if (!empty($options)) {
|
164 |
-
foreach ($options as $key=>$value) {
|
165 |
-
$output .= '<p>'.$value.'<span class="delete_option" rel="'.$key.'"></span></p>';
|
166 |
-
}
|
167 |
-
}
|
168 |
-
return $output;
|
169 |
-
}
|
170 |
-
/**
|
171 |
-
* Function to get field params
|
172 |
-
*
|
173 |
-
* @param object $params
|
174 |
-
*/
|
175 |
-
static public function getFieldAttributes($params){
|
176 |
-
$output = '';
|
177 |
-
if (!empty($params->attr)) {
|
178 |
-
foreach ($params->attr as $key=>$value) {
|
179 |
-
$output .= __($key).':<br />';
|
180 |
-
$output .= htmlCfs::text('params[attr]['.$key.']',array('value'=>$value)).'<br />';
|
181 |
-
}
|
182 |
-
} else {
|
183 |
-
$output .= __('class', CFS_LANG_CODE).':<br />';
|
184 |
-
$output .= htmlCfs::text('params[attr][class]',array('value'=>'')).'<br />';
|
185 |
-
$output .= __('id', CFS_LANG_CODE).':<br />';
|
186 |
-
$output .= htmlCfs::text('params[attr][id]',array('value'=>'')).'<br />';
|
187 |
-
}
|
188 |
-
return $output;
|
189 |
-
}
|
190 |
-
/**
|
191 |
-
* Generating the list of categories for product extra fields
|
192 |
-
*
|
193 |
-
* @param object $field
|
194 |
-
*/
|
195 |
-
static function productFieldCategories($field){
|
196 |
-
if(!empty($field->htmlParams['optionsCfs']))
|
197 |
-
return;
|
198 |
-
/*$field->htmlParams['attrs'] = 'id="select_product_field_cat" rel="0"';
|
199 |
-
$field->htmlParams['optionsCfs'] = array();
|
200 |
-
$categories = frameCfs::_()->getModule('products')->getCategories();
|
201 |
-
if(!empty($categories)) {
|
202 |
-
if(!is_array($field->value['categories']))
|
203 |
-
$field->value['categories'] = array();
|
204 |
-
$field->htmlParams['optionsCfs'][0] = in_array(0,$field->value['categories'])?__('Deselect All'):__('Select All', CFS_LANG_CODE);
|
205 |
-
foreach($categories as $c) {
|
206 |
-
$field->htmlParams['optionsCfs'][$c->term_taxonomy_id] = $c->cat_name;
|
207 |
-
}
|
208 |
-
}*/
|
209 |
-
}
|
210 |
-
static public function intToDB($val) {
|
211 |
-
return intval($val);
|
212 |
-
}
|
213 |
-
static public function floatToDB($val) {
|
214 |
-
return floatval($val);
|
215 |
-
}
|
216 |
-
/**
|
217 |
-
* Save this in static var - to futher usage
|
218 |
-
* @return array with countries
|
219 |
-
*/
|
220 |
-
static public function getCachedCountries($clearCache = false) {
|
221 |
-
if(empty(self::$countries) || $clearCache)
|
222 |
-
|
223 |
-
|
224 |
-
|
225 |
-
|
226 |
-
|
227 |
-
|
228 |
-
|
229 |
-
|
230 |
-
|
231 |
-
|
232 |
-
|
233 |
-
|
234 |
-
|
235 |
-
|
236 |
-
|
237 |
-
|
238 |
-
|
239 |
-
|
240 |
-
|
241 |
-
|
242 |
-
|
243 |
-
|
244 |
-
|
245 |
-
|
246 |
-
|
247 |
-
|
248 |
-
|
249 |
-
"
|
250 |
-
"
|
251 |
-
"
|
252 |
-
"
|
253 |
-
"
|
254 |
-
"
|
255 |
-
"
|
256 |
-
"
|
257 |
-
"
|
258 |
-
"
|
259 |
-
"
|
260 |
-
"
|
261 |
-
"
|
262 |
-
"
|
263 |
-
"
|
264 |
-
"
|
265 |
-
"
|
266 |
-
"
|
267 |
-
"
|
268 |
-
"
|
269 |
-
"
|
270 |
-
"
|
271 |
-
"
|
272 |
-
"
|
273 |
-
"
|
274 |
-
"
|
275 |
-
"
|
276 |
-
"
|
277 |
-
"
|
278 |
-
"
|
279 |
-
"
|
280 |
-
"
|
281 |
-
"
|
282 |
-
"
|
283 |
-
"
|
284 |
-
"
|
285 |
-
"
|
286 |
-
"
|
287 |
-
"
|
288 |
-
"
|
289 |
-
"
|
290 |
-
"
|
291 |
-
"
|
292 |
-
"
|
293 |
-
"
|
294 |
-
"
|
295 |
-
"
|
296 |
-
"
|
297 |
-
"
|
298 |
-
"
|
299 |
-
"
|
300 |
-
"
|
301 |
-
"
|
302 |
-
"
|
303 |
-
"
|
304 |
-
"
|
305 |
-
"
|
306 |
-
"
|
307 |
-
|
308 |
-
|
309 |
-
|
310 |
-
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Class to adapt field before display
|
4 |
+
* return ONLY htmlParams property
|
5 |
+
* @see field
|
6 |
+
*/
|
7 |
+
class fieldAdapterCfs {
|
8 |
+
const DB = 'dbCfs';
|
9 |
+
const HTML = 'htmlCfs';
|
10 |
+
const STR = 'str';
|
11 |
+
static public $userfieldDest = array('registration', 'shipping', 'billing');
|
12 |
+
static public $countries = array();
|
13 |
+
static public $states = array();
|
14 |
+
/**
|
15 |
+
* Executes field Adaption process
|
16 |
+
* @param object type field or value $fieldOrValue if DB adaption - this must be a value of field, elase if html - field object
|
17 |
+
*/
|
18 |
+
static public function _($fieldOrValue, $method, $type) {
|
19 |
+
if(method_exists('fieldAdapterCfs', $method)) {
|
20 |
+
switch($type) {
|
21 |
+
case self::DB:
|
22 |
+
return self::$method($fieldOrValue);
|
23 |
+
break;
|
24 |
+
case self::HTML:
|
25 |
+
self::$method($fieldOrValue);
|
26 |
+
break;
|
27 |
+
case self::STR:
|
28 |
+
return self::$method($fieldOrValue);
|
29 |
+
break;
|
30 |
+
}
|
31 |
+
}
|
32 |
+
return $fieldOrValue;
|
33 |
+
}
|
34 |
+
static public function userFieldDestHtml($field) {
|
35 |
+
$field->htmlParams['optionsCfs'] = array();
|
36 |
+
if(!is_array($field->value)) {
|
37 |
+
if(empty($field->value))
|
38 |
+
$field->value = array();
|
39 |
+
else
|
40 |
+
$field->value = json_decode($field->value);
|
41 |
+
}
|
42 |
+
foreach(self::$userfieldDest as $d) {
|
43 |
+
$field->htmlParams['optionsCfs'][] = array(
|
44 |
+
'id' => $d,
|
45 |
+
'text' => $d,
|
46 |
+
'checked' => in_array($d, $field->value)
|
47 |
+
);
|
48 |
+
}
|
49 |
+
}
|
50 |
+
static public function userFieldDestToDB($value) {
|
51 |
+
return utilsCfs::jsonEncode($value);
|
52 |
+
}
|
53 |
+
static public function userFieldDestFromDB($value) {
|
54 |
+
return utilsCfs::jsonDecode($value);
|
55 |
+
}
|
56 |
+
static public function taxDataHtml($field) {
|
57 |
+
$listOfDest = array();
|
58 |
+
if(!is_array($field->value)) {
|
59 |
+
if(empty($field->value))
|
60 |
+
$field->value = array();
|
61 |
+
else
|
62 |
+
$field->value = (array)json_decode($field->value, true);
|
63 |
+
}
|
64 |
+
foreach(self::$userfieldDest as $d) {
|
65 |
+
$listOfDest[] = array(
|
66 |
+
'id' => $d,
|
67 |
+
'text' => $d,
|
68 |
+
'checked' => (is_array($field->value['dest']) && in_array($d, $field->value['dest']))
|
69 |
+
);
|
70 |
+
}
|
71 |
+
$categories = frameCfs::_()->getModule('products')->getCategories();
|
72 |
+
$brands = frameCfs::_()->getModule('products')->getBrands();
|
73 |
+
$cOptions = array();
|
74 |
+
$bOptions = array();
|
75 |
+
if(!empty($categories)) {
|
76 |
+
if(!is_array($field->value['categories']))
|
77 |
+
$field->value['categories'] = array();
|
78 |
+
foreach($categories as $c) {
|
79 |
+
$cOptions[] = array('id' => $c->term_taxonomy_id,
|
80 |
+
'text' => $c->cat_name,
|
81 |
+
'checked' => in_array($c->term_taxonomy_id, $field->value['categories']));
|
82 |
+
}
|
83 |
+
}
|
84 |
+
if(!empty($brands)) {
|
85 |
+
if(!is_array($field->value['brands']))
|
86 |
+
$field->value['brands'] = array();
|
87 |
+
foreach($brands as $b) {
|
88 |
+
$bOptions[] = array('id' => $b->term_taxonomy_id,
|
89 |
+
'text' => $b->cat_name,
|
90 |
+
'checked' => in_array($b->term_taxonomy_id, $field->value['brands']));
|
91 |
+
}
|
92 |
+
}
|
93 |
+
return '<div>'. __('Apply To', CFS_LANG_CODE). '
|
94 |
+
<div id="tax_address">
|
95 |
+
<b>'. __('Address', CFS_LANG_CODE). '</b><br />
|
96 |
+
'. __('Destination', CFS_LANG_CODE). ':'. htmlCfs::checkboxlist('params[dest]', array('optionsCfs' => $listOfDest)). '<br />
|
97 |
+
'. __('Country', CFS_LANG_CODE). ':'. htmlCfs::countryList('params[country]', array('notSelected' => true, 'value' => $field->value['country'])). '<br />
|
98 |
+
</div>
|
99 |
+
<div id="tax_category">
|
100 |
+
<b>'. __('Categories', CFS_LANG_CODE). '</b><br />
|
101 |
+
'. (empty($cOptions) ? __('You have no categories', CFS_LANG_CODE) : htmlCfs::checkboxlist('params[categories][]', array('optionsCfs' => $cOptions))). '<br />
|
102 |
+
<b>'. __('Brands', CFS_LANG_CODE). '</b><br />
|
103 |
+
'. (empty($bOptions) ? __('You have no brands', CFS_LANG_CODE) : htmlCfs::checkboxlist('params[brands][]', array('optionsCfs' => $bOptions))). '<br />
|
104 |
+
</div>
|
105 |
+
<div>'. __('Tax Rate', CFS_LANG_CODE).': '. htmlCfs::text('params[rate]', array('value' => $field->value['rate'])).'</div>
|
106 |
+
<div>'. __('Absolute', CFS_LANG_CODE).': '. htmlCfs::checkbox('params[absolute]', array('checked' => $field->value['absolute'])).'</div>
|
107 |
+
</div>';
|
108 |
+
}
|
109 |
+
static public function displayCountry($cid, $key = 'name') {
|
110 |
+
if($key == 'name') {
|
111 |
+
$countries = self::getCountries();
|
112 |
+
return $countries[$cid];
|
113 |
+
} else {
|
114 |
+
if(empty(self::$countries))
|
115 |
+
self::$countries = self::getCachedCountries();
|
116 |
+
foreach(self::$countries as $c) {
|
117 |
+
if($c['id'] == $cid)
|
118 |
+
return $c[ $key ];
|
119 |
+
}
|
120 |
+
}
|
121 |
+
return false;
|
122 |
+
}
|
123 |
+
static public function displayState($sid, $key = 'name') {
|
124 |
+
$states = self::getStates();
|
125 |
+
return empty($states[$sid]) ? $sid : $states[$sid][$key];
|
126 |
+
}
|
127 |
+
static public function getCountries($notSelected = false, $listBy = 'id') {
|
128 |
+
$options = array();
|
129 |
+
if(empty(self::$countries))
|
130 |
+
self::$countries = self::getCachedCountries();
|
131 |
+
if($notSelected) {
|
132 |
+
$options[0] = is_bool($notSelected) ? __('Not selected', CFS_LANG_CODE) : __($notSelected);
|
133 |
+
}
|
134 |
+
foreach(self::$countries as $c) {
|
135 |
+
$options[$c[ $listBy ]] = $c['name'];
|
136 |
+
}
|
137 |
+
return $options;
|
138 |
+
}
|
139 |
+
static public function getStates($notSelected = false) {
|
140 |
+
static $options = array();
|
141 |
+
if(empty($options[ $notSelected ])) {
|
142 |
+
$options[ $notSelected ] = array();
|
143 |
+
if(empty(self::$states))
|
144 |
+
self::$states = self::getCachedStates();
|
145 |
+
if($notSelected) {
|
146 |
+
$notSelectedLabel = is_bool($notSelected) ? 'Not selected' : $notSelected;
|
147 |
+
$options[ $notSelected ][0] = array('name' => __( $notSelectedLabel ), 'country_id' => NULL);
|
148 |
+
}
|
149 |
+
foreach(self::$states as $s) $options[ $notSelected ][$s['id']] = $s;
|
150 |
+
}
|
151 |
+
return $options[ $notSelected ];
|
152 |
+
}
|
153 |
+
/**
|
154 |
+
* Function to get extra field options
|
155 |
+
*
|
156 |
+
* @param object $field
|
157 |
+
* @return string
|
158 |
+
*/
|
159 |
+
static public function getExtraFieldOptions($field_id) {
|
160 |
+
$output = '';
|
161 |
+
if ($field_id == 0) return '';
|
162 |
+
$options = frameCfs::_()->getModule('optionsCfs')->getHelper()->getOptions($field_id);
|
163 |
+
if (!empty($options)) {
|
164 |
+
foreach ($options as $key=>$value) {
|
165 |
+
$output .= '<p>'.$value.'<span class="delete_option" rel="'.$key.'"></span></p>';
|
166 |
+
}
|
167 |
+
}
|
168 |
+
return $output;
|
169 |
+
}
|
170 |
+
/**
|
171 |
+
* Function to get field params
|
172 |
+
*
|
173 |
+
* @param object $params
|
174 |
+
*/
|
175 |
+
static public function getFieldAttributes($params){
|
176 |
+
$output = '';
|
177 |
+
if (!empty($params->attr)) {
|
178 |
+
foreach ($params->attr as $key=>$value) {
|
179 |
+
$output .= __($key).':<br />';
|
180 |
+
$output .= htmlCfs::text('params[attr]['.$key.']',array('value'=>$value)).'<br />';
|
181 |
+
}
|
182 |
+
} else {
|
183 |
+
$output .= __('class', CFS_LANG_CODE).':<br />';
|
184 |
+
$output .= htmlCfs::text('params[attr][class]',array('value'=>'')).'<br />';
|
185 |
+
$output .= __('id', CFS_LANG_CODE).':<br />';
|
186 |
+
$output .= htmlCfs::text('params[attr][id]',array('value'=>'')).'<br />';
|
187 |
+
}
|
188 |
+
return $output;
|
189 |
+
}
|
190 |
+
/**
|
191 |
+
* Generating the list of categories for product extra fields
|
192 |
+
*
|
193 |
+
* @param object $field
|
194 |
+
*/
|
195 |
+
static function productFieldCategories($field){
|
196 |
+
if(!empty($field->htmlParams['optionsCfs']))
|
197 |
+
return;
|
198 |
+
/*$field->htmlParams['attrs'] = 'id="select_product_field_cat" rel="0"';
|
199 |
+
$field->htmlParams['optionsCfs'] = array();
|
200 |
+
$categories = frameCfs::_()->getModule('products')->getCategories();
|
201 |
+
if(!empty($categories)) {
|
202 |
+
if(!is_array($field->value['categories']))
|
203 |
+
$field->value['categories'] = array();
|
204 |
+
$field->htmlParams['optionsCfs'][0] = in_array(0,$field->value['categories'])?__('Deselect All'):__('Select All', CFS_LANG_CODE);
|
205 |
+
foreach($categories as $c) {
|
206 |
+
$field->htmlParams['optionsCfs'][$c->term_taxonomy_id] = $c->cat_name;
|
207 |
+
}
|
208 |
+
}*/
|
209 |
+
}
|
210 |
+
static public function intToDB($val) {
|
211 |
+
return intval($val);
|
212 |
+
}
|
213 |
+
static public function floatToDB($val) {
|
214 |
+
return floatval($val);
|
215 |
+
}
|
216 |
+
/**
|
217 |
+
* Save this in static var - to futher usage
|
218 |
+
* @return array with countries
|
219 |
+
*/
|
220 |
+
static public function getCachedCountries($clearCache = false) {
|
221 |
+
if(empty(self::$countries) || $clearCache)
|
222 |
+
global $wpdb;
|
223 |
+
$data = $wpdb->get_results(
|
224 |
+
"SELECT id, name, iso_code_2, iso_code_3 FROM {$wpdb->prefix}cfs_countries", ARRAY_A
|
225 |
+
);
|
226 |
+
//frameCfs::_()->getTable('countries')->getAll('id, name, iso_code_2, iso_code_3');
|
227 |
+
self::$countries = $data;
|
228 |
+
return self::$countries;
|
229 |
+
}
|
230 |
+
/**
|
231 |
+
* Save this in static var - to futher usage
|
232 |
+
* @return array with states
|
233 |
+
*/
|
234 |
+
static public function getCachedStates($clearCache = false) {
|
235 |
+
if(empty(self::$states) || $clearCache)
|
236 |
+
self::$states = frameCfs::_()->getTable('states')
|
237 |
+
->leftJoin( frameCfs::_()->getTable('countries'), 'country_id' )
|
238 |
+
->getAll('toe_states.id,
|
239 |
+
toe_states.name,
|
240 |
+
toe_states.code,
|
241 |
+
toe_states.country_id,
|
242 |
+
toe_cry.name AS c_name,
|
243 |
+
toe_cry.iso_code_2 AS c_iso_code_2,
|
244 |
+
toe_cry.iso_code_3 AS c_iso_code_3');
|
245 |
+
return self::$states;
|
246 |
+
}
|
247 |
+
static public function getFontsList() {
|
248 |
+
return array("Abel", "Abril Fatface", "Aclonica", "Acme", "Actor", "Adamina", "Advent Pro",
|
249 |
+
"Aguafina Script", "Aladin", "Aldrich", "Alegreya", "Alegreya SC", "Alex Brush", "Alfa Slab One", "Alice",
|
250 |
+
"Alike", "Alike Angular", "Allan", "Allerta", "Allerta Stencil", "Allura", "Almendra", "Almendra SC", "Amaranth",
|
251 |
+
"Amatic SC", "Amethysta", "Andada", "Andika", "Angkor", "Annie Use Your Telescope", "Anonymous Pro", "Antic",
|
252 |
+
"Antic Didone", "Antic Slab", "Anton", "Arapey", "Arbutus", "Architects Daughter", "Arimo", "Arizonia", "Armata",
|
253 |
+
"Artifika", "Arvo", "Asap", "Asset", "Astloch", "Asul", "Atomic Age", "Aubrey", "Audiowide", "Average",
|
254 |
+
"Averia Gruesa Libre", "Averia Libre", "Averia Sans Libre", "Averia Serif Libre", "Bad Script", "Balthazar",
|
255 |
+
"Bangers", "Basic", "Battambang", "Baumans", "Bayon", "Belgrano", "Belleza", "Bentham", "Berkshire Swash",
|
256 |
+
"Bevan", "Bigshot One", "Bilbo", "Bilbo Swash Caps", "Bitter", "Black Ops One", "Bokor", "Bonbon", "Boogaloo",
|
257 |
+
"Bowlby One", "Bowlby One SC", "Brawler", "Bree Serif", "Bubblegum Sans", "Buda", "Buenard", "Butcherman",
|
258 |
+
"Butterfly Kids", "Cabin", "Cabin Condensed", "Cabin Sketch", "Caesar Dressing", "Cagliostro", "Calligraffitti",
|
259 |
+
"Cambo", "Candal", "Cantarell", "Cantata One", "Cardo", "Carme", "Carter One", "Caudex", "Cedarville Cursive",
|
260 |
+
"Ceviche One", "Changa One", "Chango", "Chau Philomene One", "Chelsea Market", "Chenla", "Cherry Cream Soda",
|
261 |
+
"Chewy", "Chicle", "Chivo", "Coda", "Coda Caption", "Codystar", "Comfortaa", "Coming Soon", "Concert One",
|
262 |
+
"Condiment", "Content", "Contrail One", "Convergence", "Cookie", "Copse", "Corben", "Cousine", "Coustard",
|
263 |
+
"Covered By Your Grace", "Crafty Girls", "Creepster", "Crete Round", "Crimson Text", "Crushed", "Cuprum", "Cutive",
|
264 |
+
"Damion", "Dancing Script", "Dangrek", "Dawning of a New Day", "Days One", "Delius", "Delius Swash Caps",
|
265 |
+
"Delius Unicase", "Della Respira", "Devonshire", "Didact Gothic", "Diplomata", "Diplomata SC", "Doppio One",
|
266 |
+
"Dorsa", "Dosis", "Dr Sugiyama", "Droid Sans", "Droid Sans Mono", "Droid Serif", "Duru Sans", "Dynalight",
|
267 |
+
"EB Garamond", "Eater", "Economica", "Electrolize", "Emblema One", "Emilys Candy", "Engagement", "Enriqueta",
|
268 |
+
"Erica One", "Esteban", "Euphoria Script", "Ewert", "Exo", "Expletus Sans", "Fanwood Text", "Fascinate", "Fascinate Inline",
|
269 |
+
"Federant", "Federo", "Felipa", "Fjord One", "Flamenco", "Flavors", "Fondamento", "Fontdiner Swanky", "Forum",
|
270 |
+
"Francois One", "Fredericka the Great", "Fredoka One", "Freehand", "Fresca", "Frijole", "Fugaz One", "GFS Didot",
|
271 |
+
"GFS Neohellenic", "Galdeano", "Gentium Basic", "Gentium Book Basic", "Geo", "Geostar", "Geostar Fill", "Germania One",
|
272 |
+
"Give You Glory", "Glass Antiqua", "Glegoo", "Gloria Hallelujah", "Goblin One", "Gochi Hand", "Gorditas",
|
273 |
+
"Goudy Bookletter 1911", "Graduate", "Gravitas One", "Great Vibes", "Gruppo", "Gudea", "Habibi", "Hammersmith One",
|
274 |
+
"Handlee", "Hanuman", "Happy Monkey", "Henny Penny", "Herr Von Muellerhoff", "Holtwood One SC", "Homemade Apple",
|
275 |
+
"Homenaje", "IM Fell DW Pica", "IM Fell DW Pica SC", "IM Fell Double Pica", "IM Fell Double Pica SC",
|
276 |
+
"IM Fell English", "IM Fell English SC", "IM Fell French Canon", "IM Fell French Canon SC", "IM Fell Great Primer",
|
277 |
+
"IM Fell Great Primer SC", "Iceberg", "Iceland", "Imprima", "Inconsolata", "Inder", "Indie Flower", "Inika",
|
278 |
+
"Irish Grover", "Istok Web", "Italiana", "Italianno", "Jim Nightshade", "Jockey One", "Jolly Lodger", "Josefin Sans",
|
279 |
+
"Josefin Slab", "Judson", "Julee", "Junge", "Jura", "Just Another Hand", "Just Me Again Down Here", "Kameron",
|
280 |
+
"Karla", "Kaushan Script", "Kelly Slab", "Kenia", "Khmer", "Knewave", "Kotta One", "Koulen", "Kranky", "Kreon",
|
281 |
+
"Kristi", "Krona One", "La Belle Aurore", "Lancelot", "Lato", "League Script", "Leckerli One", "Ledger", "Lekton",
|
282 |
+
"Lemon", "Lilita One", "Limelight", "Linden Hill", "Lobster", "Lobster Two", "Londrina Outline", "Londrina Shadow",
|
283 |
+
"Londrina Sketch", "Londrina Solid", "Lora", "Love Ya Like A Sister", "Loved by the King", "Lovers Quarrel",
|
284 |
+
"Luckiest Guy", "Lusitana", "Lustria", "Macondo", "Macondo Swash Caps", "Magra", "Maiden Orange", "Mako", "Marck Script",
|
285 |
+
"Marko One", "Marmelad", "Marvel", "Mate", "Mate SC", "Maven Pro", "Meddon", "MedievalSharp", "Medula One", "Merriweather",
|
286 |
+
"Metal", "Metamorphous", "Michroma", "Miltonian", "Miltonian Tattoo", "Miniver", "Miss Fajardose", "Modern Antiqua",
|
287 |
+
"Molengo", "Monofett", "Monoton", "Monsieur La Doulaise", "Montaga", "Montez", "Montserrat", "Moul", "Moulpali",
|
288 |
+
"Mountains of Christmas", "Mr Bedfort", "Mr Dafoe", "Mr De Haviland", "Mrs Saint Delafield", "Mrs Sheppards",
|
289 |
+
"Muli", "Mystery Quest", "Neucha", "Neuton", "News Cycle", "Niconne", "Nixie One", "Nobile", "Nokora", "Norican",
|
290 |
+
"Nosifer", "Nothing You Could Do", "Noticia Text", "Nova Cut", "Nova Flat", "Nova Mono", "Nova Oval", "Nova Round",
|
291 |
+
"Nova Script", "Nova Slim", "Nova Square", "Numans", "Nunito", "Odor Mean Chey", "Old Standard TT", "Oldenburg",
|
292 |
+
"Oleo Script", "Open Sans", "Open Sans Condensed", "Orbitron", "Original Surfer", "Oswald", "Over the Rainbow",
|
293 |
+
"Overlock", "Overlock SC", "Ovo", "Oxygen", "PT Mono", "PT Sans", "PT Sans Caption", "PT Sans Narrow", "PT Serif",
|
294 |
+
"PT Serif Caption", "Pacifico", "Parisienne", "Passero One", "Passion One", "Patrick Hand", "Patua One", "Paytone One",
|
295 |
+
"Permanent Marker", "Petrona", "Philosopher", "Piedra", "Pinyon Script", "Plaster", "Play", "Playball", "Playfair Display",
|
296 |
+
"Podkova", "Poiret One", "Poller One", "Poly", "Pompiere", "Pontano Sans", "Port Lligat Sans", "Port Lligat Slab",
|
297 |
+
"Prata", "Preahvihear", "Press Start 2P", "Princess Sofia", "Prociono", "Prosto One", "Puritan", "Quantico",
|
298 |
+
"Quattrocento", "Quattrocento Sans", "Questrial", "Quicksand", "Qwigley", "Radley", "Raleway", "Rammetto One",
|
299 |
+
"Rancho", "Rationale", "Redressed", "Reenie Beanie", "Revalia", "Ribeye", "Ribeye Marrow", "Righteous", "Rochester",
|
300 |
+
"Rock Salt", "Rokkitt", "Ropa Sans", "Rosario", "Rosarivo", "Rouge Script", "Ruda", "Ruge Boogie", "Ruluko",
|
301 |
+
"Ruslan Display", "Russo One", "Ruthie", "Sail", "Salsa", "Sancreek", "Sansita One", "Sarina", "Satisfy", "Schoolbell",
|
302 |
+
"Seaweed Script", "Sevillana", "Shadows Into Light", "Shadows Into Light Two", "Shanti", "Share", "Shojumaru",
|
303 |
+
"Short Stack", "Siemreap", "Sigmar One", "Signika", "Signika Negative", "Simonetta", "Sirin Stencil", "Six Caps",
|
304 |
+
"Slackey", "Smokum", "Smythe", "Sniglet", "Snippet", "Sofia", "Sonsie One", "Sorts Mill Goudy", "Special Elite",
|
305 |
+
"Spicy Rice", "Spinnaker", "Spirax", "Squada One", "Stardos Stencil", "Stint Ultra Condensed", "Stint Ultra Expanded",
|
306 |
+
"Stoke", "Sue Ellen Francisco", "Sunshiney", "Supermercado One", "Suwannaphum", "Swanky and Moo Moo", "Syncopate",
|
307 |
+
"Tangerine", "Taprom", "Telex", "Tenor Sans", "The Girl Next Door", "Tienne", "Tinos", "Titan One", "Trade Winds",
|
308 |
+
"Trocchi", "Trochut", "Trykker", "Tulpen One", "Ubuntu", "Ubuntu Condensed", "Ubuntu Mono", "Ultra", "Uncial Antiqua",
|
309 |
+
"UnifrakturCook", "UnifrakturMaguntia", "Unkempt", "Unlock", "Unna", "VT323", "Varela", "Varela Round", "Vast Shadow",
|
310 |
+
"Vibur", "Vidaloka", "Viga", "Voces", "Volkhov", "Vollkorn", "Voltaire", "Waiting for the Sunrise", "Wallpoet",
|
311 |
+
"Walter Turncoat", "Wellfleet", "Wire One", "Yanone Kaffeesatz", "Yellowtail", "Yeseva One", "Yesteryear", "Zeyada"
|
312 |
+
);
|
313 |
+
}
|
314 |
+
}
|
315 |
+
?>
|
classes/filegenerator.php
CHANGED
@@ -1,52 +1,52 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* Class to generate fiels and output them in attachment by http (https) protocol
|
4 |
-
*/
|
5 |
-
class filegeneratorCfs {
|
6 |
-
static protected $_instances = array();
|
7 |
-
protected $_filename = '';
|
8 |
-
protected $_data = '';
|
9 |
-
protected $_type = '';
|
10 |
-
public function __construct($filename, $data, $type) {
|
11 |
-
$this->_filename = $filename;
|
12 |
-
$this->_data = $data;
|
13 |
-
$this->_type = strtolower($type);
|
14 |
-
}
|
15 |
-
static public function getInstance($filename, $data, $type) {
|
16 |
-
$name = md5($filename. $data. $type);
|
17 |
-
if(!isset(self::$_instances[$name])) {
|
18 |
-
self::$_instances[$name] = new filegeneratorCfs($filename, $data, $type);
|
19 |
-
}
|
20 |
-
return self::$_instances[$name];
|
21 |
-
}
|
22 |
-
static public function _($filename, $data, $type) {
|
23 |
-
return self::getInstance($filename, $data, $type);
|
24 |
-
}
|
25 |
-
public function generate() {
|
26 |
-
switch($this->_type) {
|
27 |
-
case 'txt':
|
28 |
-
$this->_getTxtHeader();
|
29 |
-
break;
|
30 |
-
case 'csv':
|
31 |
-
$this->_getCsvHeader();
|
32 |
-
break;
|
33 |
-
default:
|
34 |
-
$this->_getDefaultHeader();
|
35 |
-
break;
|
36 |
-
}
|
37 |
-
echo $this->_data;
|
38 |
-
exit();
|
39 |
-
}
|
40 |
-
protected function _getTxtHeader() {
|
41 |
-
header('Content-Disposition: attachment; filename="'. $this->_filename. '.txt"');
|
42 |
-
header('Content-type: text/plain');
|
43 |
-
}
|
44 |
-
protected function _getCsvHeader() {
|
45 |
-
header('Content-Disposition: attachment; filename="'. $this->_filename. '.csv"');
|
46 |
-
header('Content-type: application/csv');
|
47 |
-
}
|
48 |
-
protected function _getDefaultHeader() {
|
49 |
-
header('Content-Disposition: attachment; filename="'. $this->_filename. '"');
|
50 |
-
header('Content-type: '. $this->_type);
|
51 |
-
}
|
52 |
-
}
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Class to generate fiels and output them in attachment by http (https) protocol
|
4 |
+
*/
|
5 |
+
class filegeneratorCfs {
|
6 |
+
static protected $_instances = array();
|
7 |
+
protected $_filename = '';
|
8 |
+
protected $_data = '';
|
9 |
+
protected $_type = '';
|
10 |
+
public function __construct($filename, $data, $type) {
|
11 |
+
$this->_filename = $filename;
|
12 |
+
$this->_data = $data;
|
13 |
+
$this->_type = strtolower($type);
|
14 |
+
}
|
15 |
+
static public function getInstance($filename, $data, $type) {
|
16 |
+
$name = md5($filename. $data. $type);
|
17 |
+
if(!isset(self::$_instances[$name])) {
|
18 |
+
self::$_instances[$name] = new filegeneratorCfs($filename, $data, $type);
|
19 |
+
}
|
20 |
+
return self::$_instances[$name];
|
21 |
+
}
|
22 |
+
static public function _($filename, $data, $type) {
|
23 |
+
return self::getInstance($filename, $data, $type);
|
24 |
+
}
|
25 |
+
public function generate() {
|
26 |
+
switch($this->_type) {
|
27 |
+
case 'txt':
|
28 |
+
$this->_getTxtHeader();
|
29 |
+
break;
|
30 |
+
case 'csv':
|
31 |
+
$this->_getCsvHeader();
|
32 |
+
break;
|
33 |
+
default:
|
34 |
+
$this->_getDefaultHeader();
|
35 |
+
break;
|
36 |
+
}
|
37 |
+
echo $this->_data;
|
38 |
+
exit();
|
39 |
+
}
|
40 |
+
protected function _getTxtHeader() {
|
41 |
+
header('Content-Disposition: attachment; filename="'. $this->_filename. '.txt"');
|
42 |
+
header('Content-type: text/plain');
|
43 |
+
}
|
44 |
+
protected function _getCsvHeader() {
|
45 |
+
header('Content-Disposition: attachment; filename="'. $this->_filename. '.csv"');
|
46 |
+
header('Content-type: application/csv');
|
47 |
+
}
|
48 |
+
protected function _getDefaultHeader() {
|
49 |
+
header('Content-Disposition: attachment; filename="'. $this->_filename. '"');
|
50 |
+
header('Content-type: '. $this->_type);
|
51 |
+
}
|
52 |
+
}
|
classes/fileuploader.php
CHANGED
@@ -1,142 +1,147 @@
|
|
1 |
-
<?php
|
2 |
-
class fileuploaderCfs {
|
3 |
-
private $_error = '';
|
4 |
-
private $_dest = '';
|
5 |
-
private $_file = '';
|
6 |
-
/**
|
7 |
-
* Result filename, if empty - it will be randon generated string
|
8 |
-
*/
|
9 |
-
private $_destFilename = '';
|
10 |
-
/**
|
11 |
-
* Return last error
|
12 |
-
* @return string error message
|
13 |
-
*/
|
14 |
-
public function getError() {
|
15 |
-
return $this->_error;
|
16 |
-
}
|
17 |
-
/**
|
18 |
-
* Validate before upload
|
19 |
-
* @param string $inputname name of the input HTML document (key in $_FILES array)
|
20 |
-
* @param string $destSubDir destination for uploaded file, for wp this should be directory in wp-content/uploads/ dir
|
21 |
-
* @param string $destFilename name of a file that be uploaded
|
22 |
-
*/
|
23 |
-
public function validate($inputname, $destSubDir, $destFilename = '') {
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
$
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
$
|
76 |
-
$
|
77 |
-
$this
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
|
86 |
-
'
|
87 |
-
'
|
88 |
-
'
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
|
94 |
-
|
95 |
-
|
96 |
-
|
97 |
-
|
98 |
-
|
99 |
-
|
100 |
-
|
101 |
-
|
102 |
-
|
103 |
-
|
104 |
-
|
105 |
-
|
106 |
-
|
107 |
-
|
108 |
-
|
109 |
-
|
110 |
-
|
111 |
-
|
112 |
-
|
113 |
-
|
114 |
-
|
115 |
-
|
116 |
-
|
117 |
-
|
118 |
-
|
119 |
-
|
120 |
-
|
121 |
-
|
122 |
-
|
123 |
-
$file['name']
|
124 |
-
|
125 |
-
|
126 |
-
|
127 |
-
|
128 |
-
|
129 |
-
|
130 |
-
|
131 |
-
|
132 |
-
|
133 |
-
|
134 |
-
|
135 |
-
|
136 |
-
|
137 |
-
|
138 |
-
|
139 |
-
|
140 |
-
|
141 |
-
|
142 |
-
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
class fileuploaderCfs {
|
3 |
+
private $_error = '';
|
4 |
+
private $_dest = '';
|
5 |
+
private $_file = '';
|
6 |
+
/**
|
7 |
+
* Result filename, if empty - it will be randon generated string
|
8 |
+
*/
|
9 |
+
private $_destFilename = '';
|
10 |
+
/**
|
11 |
+
* Return last error
|
12 |
+
* @return string error message
|
13 |
+
*/
|
14 |
+
public function getError() {
|
15 |
+
return $this->_error;
|
16 |
+
}
|
17 |
+
/**
|
18 |
+
* Validate before upload
|
19 |
+
* @param string $inputname name of the input HTML document (key in $_FILES array)
|
20 |
+
* @param string $destSubDir destination for uploaded file, for wp this should be directory in wp-content/uploads/ dir
|
21 |
+
* @param string $destFilename name of a file that be uploaded
|
22 |
+
*/
|
23 |
+
public function validate($inputname, $destSubDir, $destFilename = '') {
|
24 |
+
if (is_array($inputname) && !empty($inputname['name'])) {
|
25 |
+
$inputname['name'] = sanitize_file_name($inputname['name']);
|
26 |
+
} else {
|
27 |
+
return false;
|
28 |
+
}
|
29 |
+
$file = $inputname;
|
30 |
+
$res = false;
|
31 |
+
if(!empty($file['error'])) {
|
32 |
+
switch($file['error']) {
|
33 |
+
case '1':
|
34 |
+
$this->_error = __('The uploaded file exceeds the upload_max_filesize directive in php.ini', CFS_LANG_CODE);
|
35 |
+
break;
|
36 |
+
case '2':
|
37 |
+
$this->_error = __('The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form', CFS_LANG_CODE);
|
38 |
+
break;
|
39 |
+
case '3':
|
40 |
+
$this->_error = __('The uploaded file was only partially uploaded', CFS_LANG_CODE);
|
41 |
+
break;
|
42 |
+
case '4':
|
43 |
+
$this->_error = __('No file was uploaded.', CFS_LANG_CODE);
|
44 |
+
break;
|
45 |
+
case '6':
|
46 |
+
$this->_error = __('Missing a temporary folder', CFS_LANG_CODE);
|
47 |
+
break;
|
48 |
+
case '7':
|
49 |
+
$this->_error = __('Failed to write file to disk', CFS_LANG_CODE);
|
50 |
+
break;
|
51 |
+
case '8':
|
52 |
+
$this->_error = __('File upload stopped by extension', CFS_LANG_CODE);
|
53 |
+
break;
|
54 |
+
case '999':
|
55 |
+
default:
|
56 |
+
$this->_error = __('No error code avaiable', CFS_LANG_CODE);
|
57 |
+
}
|
58 |
+
} elseif(empty($file['tmp_name']) || $file['tmp_name'] == 'none') {
|
59 |
+
$this->_error = __('No file was uploaded..', CFS_LANG_CODE);
|
60 |
+
} else {
|
61 |
+
$res = true;
|
62 |
+
}
|
63 |
+
if($res) {
|
64 |
+
//$this->_fileSize = $file['size'];
|
65 |
+
$this->_dest = $destSubDir;
|
66 |
+
$this->_file = $file;
|
67 |
+
$this->_destFilename = $destFilename;
|
68 |
+
}
|
69 |
+
return $res;
|
70 |
+
}
|
71 |
+
/**
|
72 |
+
* Upload valid file
|
73 |
+
*/
|
74 |
+
public function upload($d = array()) {
|
75 |
+
$d['ignore_db_insert'] = isset($d['ignore_db_insert']) ? $d['ignore_db_insert'] : false;
|
76 |
+
$res = false;
|
77 |
+
add_filter('upload_dir', array($this,'changeUploadDir'));
|
78 |
+
add_filter('wp_handle_upload_prefilter', array($this,'changeFileName'));
|
79 |
+
// File name will be changed during upload process - we will bring it back after upload
|
80 |
+
$fileName = $this->_file['name'];
|
81 |
+
$upload = wp_handle_upload($this->_file, array('test_form' => FALSE));
|
82 |
+
$this->_file['name'] = $fileName;
|
83 |
+
if (!empty($upload['type'])) {
|
84 |
+
if(!isset($d['ignore_db_insert']) || !$d['ignore_db_insert']) {
|
85 |
+
$saveData = array(
|
86 |
+
'fid' => (isset($d['fid']) ? $d['fid'] : 0),
|
87 |
+
'field_name' => (isset($d['field_name']) ? $d['field_name'] : ''),
|
88 |
+
'name' => $this->_file['name'],
|
89 |
+
'dest_name' => $this->_destFilename,
|
90 |
+
'path' => str_replace(DS, '\\'. DS, $this->_dest),
|
91 |
+
'mime_type' => $upload['type'],
|
92 |
+
'size' => $this->_file['size'],
|
93 |
+
'hash' => md5(mt_rand(1, 9999999)),
|
94 |
+
);
|
95 |
+
$this->_file['id'] = frameCfs::_()->getTable('files')->insert($saveData);
|
96 |
+
$this->_file['hash'] = $saveData['hash'];
|
97 |
+
$this->_file['field_name'] = $saveData['field_name'];
|
98 |
+
$this->_file['url'] = $upload['url'];
|
99 |
+
}
|
100 |
+
$res = true;
|
101 |
+
} elseif($upload['error']) {
|
102 |
+
$this->_error = $upload['error'];
|
103 |
+
}
|
104 |
+
remove_filter('upload_dir', array($this,'changeUploadDir'));
|
105 |
+
remove_filter('wp_handle_upload_prefilter', array($this,'changeFileName'));
|
106 |
+
return $res;
|
107 |
+
}
|
108 |
+
public function getFileInfo() {
|
109 |
+
return $this->_file;
|
110 |
+
}
|
111 |
+
public function changeUploadDir($uploads) {
|
112 |
+
$uploads['subdir'] = $this->_dest;
|
113 |
+
if(empty($uploads['subdir'])) {
|
114 |
+
$uploads['path'] = $uploads['basedir'];
|
115 |
+
$uploads['url'] = $uploads['baseurl'];
|
116 |
+
} else {
|
117 |
+
$uploads['path'] = $uploads['basedir'] . DS. $uploads['subdir'];
|
118 |
+
$uploads['url'] = $uploads['baseurl'] . '/'.$uploads['subdir'];
|
119 |
+
}
|
120 |
+
return $uploads;
|
121 |
+
}
|
122 |
+
public function changeFileName($file) {
|
123 |
+
$ext = pathinfo($file['name'], PATHINFO_EXTENSION);
|
124 |
+
if(empty($this->_destFilename)) {
|
125 |
+
$this->_destFilename = $this->createFileName();
|
126 |
+
}
|
127 |
+
$this->_destFilename .= '.'. $ext;
|
128 |
+
$file['name'] = $this->_destFilename;
|
129 |
+
return $file;
|
130 |
+
}
|
131 |
+
private function createFileName() {
|
132 |
+
return utilsCfs::getRandStr(). '-'. utilsCfs::getRandStr(). '-'. utilsCfs::getRandStr(). '-'. utilsCfs::getRandStr();
|
133 |
+
}
|
134 |
+
/**
|
135 |
+
* Delete uploaded file
|
136 |
+
* @param int|array $id ID of file in files table, or file row data from files table
|
137 |
+
*/
|
138 |
+
public function delete($id) {
|
139 |
+
$file = is_array($id) ? $id : frameCfs::_()->getTable('files')->get('*', array('id' => $id), '', 'row');
|
140 |
+
if($file) {
|
141 |
+
frameCfs::_()->getTable('files')->delete($file['id']);
|
142 |
+
$uploadsDir = wp_upload_dir( null, false );
|
143 |
+
@unlink( $uploadsDir['basedir']. (empty($file['path']) ? '' : DS. $file['path']). DS. $file['dest_name'] );
|
144 |
+
}
|
145 |
+
return false;
|
146 |
+
}
|
147 |
+
}
|
classes/frame.php
CHANGED
@@ -1,500 +1,509 @@
|
|
1 |
-
<?php
|
2 |
-
class frameCfs {
|
3 |
-
private $_modules = array();
|
4 |
-
private $_tables = array();
|
5 |
-
private $_allModules = array();
|
6 |
-
/**
|
7 |
-
* bool Uses to know if we are on one of the plugin pages
|
8 |
-
*/
|
9 |
-
private $_inPlugin = false;
|
10 |
-
/**
|
11 |
-
* Array to hold all scripts and add them in one time in addScripts method
|
12 |
-
*/
|
13 |
-
private $_scripts = array();
|
14 |
-
private $_scriptsInitialized = false;
|
15 |
-
private $_styles = array();
|
16 |
-
private $_stylesInitialized = false;
|
17 |
-
private $_useFootAssets = false;
|
18 |
-
|
19 |
-
private $_scriptsVars = array();
|
20 |
-
private $_mod = '';
|
21 |
-
private $_action = '';
|
22 |
-
/**
|
23 |
-
* Object with result of executing non-ajax module request
|
24 |
-
*/
|
25 |
-
private $_res = null;
|
26 |
-
|
27 |
-
public function __construct() {
|
28 |
-
$this->_res = toeCreateObjCfs('response', array());
|
29 |
-
|
30 |
-
}
|
31 |
-
static public function getInstance() {
|
32 |
-
static $instance;
|
33 |
-
if(!$instance) {
|
34 |
-
$instance = new frameCfs();
|
35 |
-
}
|
36 |
-
return $instance;
|
37 |
-
}
|
38 |
-
static public function _() {
|
39 |
-
return self::getInstance();
|
40 |
-
}
|
41 |
-
public function parseRoute() {
|
42 |
-
// Check plugin
|
43 |
-
$pl = reqCfs::getVar('pl');
|
44 |
-
if($pl == CFS_CODE) {
|
45 |
-
$mod = reqCfs::getMode();
|
46 |
-
if($mod)
|
47 |
-
$this->_mod = $mod;
|
48 |
-
$action = reqCfs::getVar('action');
|
49 |
-
if($action)
|
50 |
-
$this->_action = $action;
|
51 |
-
}
|
52 |
-
}
|
53 |
-
public function setMod($mod) {
|
54 |
-
$this->_mod = $mod;
|
55 |
-
}
|
56 |
-
public function getMod() {
|
57 |
-
return $this->_mod;
|
58 |
-
}
|
59 |
-
public function setAction($action) {
|
60 |
-
$this->_action = $action;
|
61 |
-
}
|
62 |
-
public function getAction() {
|
63 |
-
return $this->_action;
|
64 |
-
}
|
65 |
-
protected function _extractModules() {
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
|
94 |
-
|
95 |
-
|
96 |
-
|
97 |
-
|
98 |
-
}
|
99 |
-
}
|
100 |
-
|
101 |
-
|
102 |
-
|
103 |
-
|
104 |
-
$this->
|
105 |
-
|
106 |
-
|
107 |
-
|
108 |
-
|
109 |
-
|
110 |
-
|
111 |
-
|
112 |
-
|
113 |
-
$this->
|
114 |
-
|
115 |
-
|
116 |
-
|
117 |
-
|
118 |
-
|
119 |
-
|
120 |
-
|
121 |
-
|
122 |
-
|
123 |
-
|
124 |
-
|
125 |
-
|
126 |
-
|
127 |
-
|
128 |
-
|
129 |
-
|
130 |
-
|
131 |
-
|
132 |
-
|
133 |
-
|
134 |
-
|
135 |
-
|
136 |
-
|
137 |
-
|
138 |
-
|
139 |
-
|
140 |
-
|
141 |
-
|
142 |
-
|
143 |
-
|
144 |
-
|
145 |
-
|
146 |
-
|
147 |
-
|
148 |
-
|
149 |
-
|
150 |
-
|
151 |
-
|
152 |
-
|
153 |
-
|
154 |
-
|
155 |
-
|
156 |
-
|
157 |
-
|
158 |
-
|
159 |
-
|
160 |
-
|
161 |
-
|
162 |
-
|
163 |
-
|
164 |
-
|
165 |
-
|
166 |
-
|
167 |
-
|
168 |
-
|
169 |
-
|
170 |
-
|
171 |
-
|
172 |
-
|
173 |
-
|
174 |
-
|
175 |
-
|
176 |
-
|
177 |
-
|
178 |
-
|
179 |
-
|
180 |
-
|
181 |
-
|
182 |
-
|
183 |
-
|
184 |
-
|
185 |
-
|
186 |
-
|
187 |
-
|
188 |
-
|
189 |
-
|
190 |
-
|
191 |
-
|
192 |
-
|
193 |
-
|
194 |
-
|
195 |
-
|
196 |
-
|
197 |
-
|
198 |
-
|
199 |
-
|
200 |
-
|
201 |
-
|
202 |
-
|
203 |
-
|
204 |
-
|
205 |
-
|
206 |
-
|
207 |
-
|
208 |
-
|
209 |
-
|
210 |
-
|
211 |
-
|
212 |
-
|
213 |
-
|
214 |
-
|
215 |
-
|
216 |
-
|
217 |
-
|
218 |
-
|
219 |
-
|
220 |
-
|
221 |
-
|
222 |
-
|
223 |
-
|
224 |
-
|
225 |
-
|
226 |
-
|
227 |
-
|
228 |
-
|
229 |
-
|
230 |
-
|
231 |
-
|
232 |
-
|
233 |
-
|
234 |
-
|
235 |
-
|
236 |
-
|
237 |
-
|
238 |
-
|
239 |
-
|
240 |
-
|
241 |
-
|
242 |
-
|
243 |
-
|
244 |
-
|
245 |
-
|
246 |
-
|
247 |
-
|
248 |
-
|
249 |
-
|
250 |
-
|
251 |
-
|
252 |
-
|
253 |
-
|
254 |
-
|
255 |
-
|
256 |
-
|
257 |
-
|
258 |
-
|
259 |
-
|
260 |
-
|
261 |
-
|
262 |
-
|
263 |
-
|
264 |
-
|
265 |
-
|
266 |
-
|
267 |
-
|
268 |
-
|
269 |
-
|
270 |
-
|
271 |
-
|
272 |
-
|
273 |
-
|
274 |
-
|
275 |
-
|
276 |
-
|
277 |
-
|
278 |
-
|
279 |
-
|
280 |
-
|
281 |
-
|
282 |
-
|
283 |
-
|
284 |
-
|
285 |
-
|
286 |
-
|
287 |
-
|
288 |
-
|
289 |
-
|
290 |
-
|
291 |
-
|
292 |
-
|
293 |
-
|
294 |
-
|
295 |
-
|
296 |
-
|
297 |
-
|
298 |
-
|
299 |
-
|
300 |
-
|
301 |
-
|
302 |
-
|
303 |
-
|
304 |
-
|
305 |
-
|
306 |
-
|
307 |
-
|
308 |
-
|
309 |
-
|
310 |
-
|
311 |
-
|
312 |
-
$
|
313 |
-
|
314 |
-
|
315 |
-
|
316 |
-
|
317 |
-
|
318 |
-
|
319 |
-
|
320 |
-
|
321 |
-
|
322 |
-
|
323 |
-
|
324 |
-
|
325 |
-
|
326 |
-
|
327 |
-
|
328 |
-
|
329 |
-
|
330 |
-
|
331 |
-
|
332 |
-
|
333 |
-
|
334 |
-
|
335 |
-
|
336 |
-
|
337 |
-
|
338 |
-
|
339 |
-
|
340 |
-
|
341 |
-
public function
|
342 |
-
|
343 |
-
|
344 |
-
|
345 |
-
|
346 |
-
|
347 |
-
|
348 |
-
|
349 |
-
|
350 |
-
|
351 |
-
|
352 |
-
|
353 |
-
|
354 |
-
|
355 |
-
|
356 |
-
|
357 |
-
|
358 |
-
|
359 |
-
|
360 |
-
|
361 |
-
|
362 |
-
|
363 |
-
|
364 |
-
|
365 |
-
|
366 |
-
|
367 |
-
|
368 |
-
|
369 |
-
|
370 |
-
|
371 |
-
|
372 |
-
|
373 |
-
|
374 |
-
|
375 |
-
}
|
376 |
-
/**
|
377 |
-
* Push data to script array to use it all in addScripts method
|
378 |
-
* @see wp_enqueue_script definition
|
379 |
-
*/
|
380 |
-
|
381 |
-
public function addScript($handle, $src = '', $deps = array(), $ver = false, $in_footer = false, $vars = array()) {
|
382 |
-
$src = empty($src) ? $src : uriCfs::_($src);
|
383 |
-
if(!$ver)
|
384 |
-
$ver = CFS_VERSION;
|
385 |
-
if($this->_scriptsInitialized) {
|
386 |
-
wp_enqueue_script($handle, $src, $deps, $ver, $in_footer);
|
387 |
-
} else {
|
388 |
-
$this->_scripts[] = array(
|
389 |
-
'handle' => $handle,
|
390 |
-
'src' => $src,
|
391 |
-
'deps' => $deps,
|
392 |
-
'ver' => $ver,
|
393 |
-
'in_footer' => $in_footer,
|
394 |
-
'vars' => $vars
|
395 |
-
);
|
396 |
-
}
|
397 |
-
}
|
398 |
-
/**
|
399 |
-
* Add all scripts from _scripts array to worcfsess
|
400 |
-
*/
|
401 |
-
public function addScripts() {
|
402 |
-
if(!empty($this->_scripts)) {
|
403 |
-
foreach($this->_scripts as $s) {
|
404 |
-
wp_enqueue_script($s['handle'], $s['src'], $s['deps'], $s['ver'], $s['in_footer']);
|
405 |
-
|
406 |
-
if($s['vars'] || isset($this->_scriptsVars[$s['handle']])) {
|
407 |
-
$vars = array();
|
408 |
-
if($s['vars'])
|
409 |
-
$vars = $s['vars'];
|
410 |
-
if($this->_scriptsVars[$s['handle']])
|
411 |
-
$vars = array_merge($vars, $this->_scriptsVars[$s['handle']]);
|
412 |
-
if($vars) {
|
413 |
-
foreach($vars as $k => $v) {
|
414 |
-
wp_localize_script($s['handle'], $k, $v);
|
415 |
-
}
|
416 |
-
}
|
417 |
-
}
|
418 |
-
}
|
419 |
-
}
|
420 |
-
$this->_scriptsInitialized = true;
|
421 |
-
}
|
422 |
-
public function addJSVar($script, $name, $val) {
|
423 |
-
if($this->_scriptsInitialized) {
|
424 |
-
wp_localize_script($script, $name, $val);
|
425 |
-
} else {
|
426 |
-
$this->_scriptsVars[$script][$name] = $val;
|
427 |
-
}
|
428 |
-
}
|
429 |
-
|
430 |
-
public function addStyle($handle, $src = false, $deps = array(), $ver = false, $media = 'all') {
|
431 |
-
$src = empty($src) ? $src : uriCfs::_($src);
|
432 |
-
if(!$ver)
|
433 |
-
$ver = CFS_VERSION;
|
434 |
-
if($this->_stylesInitialized) {
|
435 |
-
wp_enqueue_style($handle, $src, $deps, $ver, $media);
|
436 |
-
} else {
|
437 |
-
$this->_styles[] = array(
|
438 |
-
'handle' => $handle,
|
439 |
-
'src' => $src,
|
440 |
-
'deps' => $deps,
|
441 |
-
'ver' => $ver,
|
442 |
-
'media' => $media
|
443 |
-
);
|
444 |
-
}
|
445 |
-
}
|
446 |
-
public function addStyles() {
|
447 |
-
if(!empty($this->_styles)) {
|
448 |
-
foreach($this->_styles as $s) {
|
449 |
-
wp_enqueue_style($s['handle'], $s['src'], $s['deps'], $s['ver'], $s['media']);
|
450 |
-
}
|
451 |
-
}
|
452 |
-
$this->_stylesInitialized = true;
|
453 |
-
}
|
454 |
-
//Very interesting thing going here.............
|
455 |
-
public function loadPlugins() {
|
456 |
-
require_once(ABSPATH. 'wp-includes/pluggable.php');
|
457 |
-
}
|
458 |
-
public function loadWPSettings() {
|
459 |
-
require_once(ABSPATH. 'wp-settings.php');
|
460 |
-
}
|
461 |
-
public function loadLocale() {
|
462 |
-
require_once(ABSPATH. 'wp-includes/locale.php');
|
463 |
-
}
|
464 |
-
public function moduleActive($code) {
|
465 |
-
return isset($this->_modules[$code]);
|
466 |
-
}
|
467 |
-
public function moduleExists($code) {
|
468 |
-
if($this->moduleActive($code))
|
469 |
-
return true;
|
470 |
-
return isset($this->_allModules[$code]);
|
471 |
-
}
|
472 |
-
public function isTplEditor() {
|
473 |
-
$tplEditor = reqCfs::getVar('tplEditor');
|
474 |
-
return (bool) $tplEditor;
|
475 |
-
}
|
476 |
-
/**
|
477 |
-
* This is custom method for each plugin and should be modified if you create copy from this instance.
|
478 |
-
*/
|
479 |
-
public function isAdminPlugOptsPage() {
|
480 |
-
$page = reqCfs::getVar('page');
|
481 |
-
if(is_admin() && strpos($page, frameCfs::_()->getModule('adminmenu')->getMainSlug()) !== false)
|
482 |
-
return true;
|
483 |
-
return false;
|
484 |
-
}
|
485 |
-
public function isAdminPlugPage() {
|
486 |
-
if($this->isAdminPlugOptsPage()) {
|
487 |
-
return true;
|
488 |
-
}
|
489 |
-
return false;
|
490 |
-
}
|
491 |
-
public function licenseDeactivated() {
|
492 |
-
return (!$this->getModule('license') && $this->moduleExists('license'));
|
493 |
-
}
|
494 |
-
public function savePluginActivationErrors() {
|
495 |
-
update_option(CFS_CODE. '_plugin_activation_errors', ob_get_contents());
|
496 |
-
}
|
497 |
-
public function getActivationErrors() {
|
498 |
-
return get_option(CFS_CODE. '_plugin_activation_errors');
|
499 |
-
}
|
500 |
-
}
|
1 |
+
<?php
|
2 |
+
class frameCfs {
|
3 |
+
private $_modules = array();
|
4 |
+
private $_tables = array();
|
5 |
+
private $_allModules = array();
|
6 |
+
/**
|
7 |
+
* bool Uses to know if we are on one of the plugin pages
|
8 |
+
*/
|
9 |
+
private $_inPlugin = false;
|
10 |
+
/**
|
11 |
+
* Array to hold all scripts and add them in one time in addScripts method
|
12 |
+
*/
|
13 |
+
private $_scripts = array();
|
14 |
+
private $_scriptsInitialized = false;
|
15 |
+
private $_styles = array();
|
16 |
+
private $_stylesInitialized = false;
|
17 |
+
private $_useFootAssets = false;
|
18 |
+
|
19 |
+
private $_scriptsVars = array();
|
20 |
+
private $_mod = '';
|
21 |
+
private $_action = '';
|
22 |
+
/**
|
23 |
+
* Object with result of executing non-ajax module request
|
24 |
+
*/
|
25 |
+
private $_res = null;
|
26 |
+
|
27 |
+
public function __construct() {
|
28 |
+
$this->_res = toeCreateObjCfs('response', array());
|
29 |
+
|
30 |
+
}
|
31 |
+
static public function getInstance() {
|
32 |
+
static $instance;
|
33 |
+
if(!$instance) {
|
34 |
+
$instance = new frameCfs();
|
35 |
+
}
|
36 |
+
return $instance;
|
37 |
+
}
|
38 |
+
static public function _() {
|
39 |
+
return self::getInstance();
|
40 |
+
}
|
41 |
+
public function parseRoute() {
|
42 |
+
// Check plugin
|
43 |
+
$pl = reqCfs::getVar('pl');
|
44 |
+
if($pl == CFS_CODE) {
|
45 |
+
$mod = reqCfs::getMode();
|
46 |
+
if($mod)
|
47 |
+
$this->_mod = $mod;
|
48 |
+
$action = reqCfs::getVar('action');
|
49 |
+
if($action)
|
50 |
+
$this->_action = $action;
|
51 |
+
}
|
52 |
+
}
|
53 |
+
public function setMod($mod) {
|
54 |
+
$this->_mod = $mod;
|
55 |
+
}
|
56 |
+
public function getMod() {
|
57 |
+
return $this->_mod;
|
58 |
+
}
|
59 |
+
public function setAction($action) {
|
60 |
+
$this->_action = $action;
|
61 |
+
}
|
62 |
+
public function getAction() {
|
63 |
+
return $this->_action;
|
64 |
+
}
|
65 |
+
protected function _extractModules() {
|
66 |
+
global $wpdb;
|
67 |
+
$wpPrefix = $wpdb->prefix; /* add to 0.0.3 Versiom */
|
68 |
+
if (dbCfs::exist("cfs_modules")) {
|
69 |
+
|
70 |
+
$activeModules = $wpdb->get_results(
|
71 |
+
"SELECT sup_m.*, sup_m_t.label as type_name FROM {$wpdb->prefix}cfs_modules as sup_m INNER JOIN {$wpdb->prefix}cfs_modules_type sup_m_t ON sup_m_t.id = sup_m.type_id ORDER BY id ASC", ARRAY_A
|
72 |
+
);
|
73 |
+
//$activeModules = $this->getTable('modules')
|
74 |
+
//->innerJoin( $this->getTable('modules_type'), 'type_id' )
|
75 |
+
//->orderBy('id ASC')
|
76 |
+
//->get($this->getTable('modules')->alias(). '.*, '. $this->getTable('modules_type')->alias(). '.label as type_name');
|
77 |
+
|
78 |
+
if($activeModules) {
|
79 |
+
foreach($activeModules as $m) {
|
80 |
+
$code = $m['code'];
|
81 |
+
$moduleLocationDir = CFS_MODULES_DIR;
|
82 |
+
if(!empty($m['ex_plug_dir'])) {
|
83 |
+
$moduleLocationDir = utilsCfs::getExtModDir( $m['ex_plug_dir'] );
|
84 |
+
}
|
85 |
+
if(is_dir($moduleLocationDir. $code)) {
|
86 |
+
$this->_allModules[$m['code']] = 1;
|
87 |
+
if((bool)$m['active']) {
|
88 |
+
importClassCfs($code. strFirstUp(CFS_CODE), $moduleLocationDir. $code. DS. 'mod.php');
|
89 |
+
$moduleClass = toeGetClassNameCfs($code);
|
90 |
+
if(class_exists($moduleClass)) {
|
91 |
+
$this->_modules[$code] = new $moduleClass($m);
|
92 |
+
if(is_dir($moduleLocationDir. $code. DS. 'tables')) {
|
93 |
+
$this->_extractTables($moduleLocationDir. $code. DS. 'tables'. DS);
|
94 |
+
}
|
95 |
+
}
|
96 |
+
}
|
97 |
+
}
|
98 |
+
}
|
99 |
+
}
|
100 |
+
}
|
101 |
+
//$operationTime = microtime(true) - $startTime;
|
102 |
+
}
|
103 |
+
protected function _initModules() {
|
104 |
+
if(!empty($this->_modules)) {
|
105 |
+
foreach($this->_modules as $mod) {
|
106 |
+
$mod->init();
|
107 |
+
}
|
108 |
+
}
|
109 |
+
}
|
110 |
+
public function init() {
|
111 |
+
//$startTime = microtime(true);
|
112 |
+
reqCfs::init();
|
113 |
+
$this->_extractTables();
|
114 |
+
$this->_extractModules();
|
115 |
+
|
116 |
+
$this->_initModules();
|
117 |
+
|
118 |
+
dispatcherCfs::doAction('afterModulesInit');
|
119 |
+
|
120 |
+
modInstallerCfs::checkActivationMessages();
|
121 |
+
|
122 |
+
$this->_execModules();
|
123 |
+
|
124 |
+
$addAssetsAction = $this->usePackAssets() && !is_admin() ? 'wp_footer' : 'init';
|
125 |
+
|
126 |
+
add_action($addAssetsAction, array($this, 'addScripts'));
|
127 |
+
add_action($addAssetsAction, array($this, 'addStyles'));
|
128 |
+
|
129 |
+
register_activation_hook( CFS_DIR. DS. CFS_MAIN_FILE, array('utilsCfs', 'activatePlugin') ); //See classes/install.php file
|
130 |
+
register_uninstall_hook(CFS_DIR. DS. CFS_MAIN_FILE, array('utilsCfs', 'deletePlugin'));
|
131 |
+
register_deactivation_hook(CFS_DIR. DS. CFS_MAIN_FILE, array( 'utilsCfs', 'deactivatePlugin' ) );
|
132 |
+
|
133 |
+
add_action('init', array($this, 'connectLang'));
|
134 |
+
add_filter('do_not_defer', array($this, 'excludeDeferScripts'));
|
135 |
+
add_filter('script_loader_tag', array($this, 'add_defer_attribute'), 10, 2);
|
136 |
+
//$operationTime = microtime(true) - $startTime;
|
137 |
+
}
|
138 |
+
public function add_defer_attribute($tag, $handle) {
|
139 |
+
// add script handles to the array below
|
140 |
+
switch ($handle) {
|
141 |
+
case 'google.recaptcha':
|
142 |
+
return str_replace(' src', ' defer="defer" src', $tag);
|
143 |
+
break;
|
144 |
+
case 'google.recaptcha.frontend':
|
145 |
+
return str_replace(' src', ' defer="defer" src', $tag);
|
146 |
+
break;
|
147 |
+
}
|
148 |
+
return $tag;
|
149 |
+
}
|
150 |
+
public function excludeDeferScripts($do_not_defer) {
|
151 |
+
//Need when WP deferred javaScript is activated
|
152 |
+
global $wp_scripts;
|
153 |
+
foreach($wp_scripts->queue as $handle) {
|
154 |
+
$do_not_defer[] = $handle;
|
155 |
+
}
|
156 |
+
return $do_not_defer;
|
157 |
+
}
|
158 |
+
public function connectLang() {
|
159 |
+
load_plugin_textdomain(CFS_LANG_CODE, false, CFS_PLUG_NAME. '/languages/');
|
160 |
+
}
|
161 |
+
/**
|
162 |
+
* Check permissions for action in controller by $code and made corresponding action
|
163 |
+
* @param string $code Code of controller that need to be checked
|
164 |
+
* @param string $action Action that need to be checked
|
165 |
+
* @return bool true if ok, else - should exit from application
|
166 |
+
*/
|
167 |
+
public function checkPermissions($code, $action) {
|
168 |
+
if($this->havePermissions($code, $action))
|
169 |
+
return true;
|
170 |
+
else {
|
171 |
+
exit(_e('You have no permissions to view this page', CFS_LANG_CODE));
|
172 |
+
}
|
173 |
+
}
|
174 |
+
/**
|
175 |
+
* Check permissions for action in controller by $code
|
176 |
+
* @param string $code Code of controller that need to be checked
|
177 |
+
* @param string $action Action that need to be checked
|
178 |
+
* @return bool true if ok, else - false
|
179 |
+
*/
|
180 |
+
public function havePermissions($code, $action) {
|
181 |
+
$res = true;
|
182 |
+
$mod = $this->getModule($code);
|
183 |
+
$action = strtolower($action);
|
184 |
+
if($mod) {
|
185 |
+
$permissions = $mod->getController()->getPermissions();
|
186 |
+
if(!empty($permissions)) { // Special permissions
|
187 |
+
if(isset($permissions[CFS_METHODS])
|
188 |
+
&& !empty($permissions[CFS_METHODS])
|
189 |
+
) {
|
190 |
+
foreach($permissions[CFS_METHODS] as $method => $permissions) { // Make case-insensitive
|
191 |
+
$permissions[CFS_METHODS][strtolower($method)] = $permissions;
|
192 |
+
}
|
193 |
+
if(array_key_exists($action, $permissions[CFS_METHODS])) { // Permission for this method exists
|
194 |
+
$currentUserPosition = frameCfs::_()->getModule('user')->getCurrentUserPosition();
|
195 |
+
if((is_array($permissions[ CFS_METHODS ][ $action ]) && !in_array($currentUserPosition, $permissions[ CFS_METHODS ][ $action ]))
|
196 |
+
|| (!is_array($permissions[ CFS_METHODS ][ $action ]) && $permissions[CFS_METHODS][$action] != $currentUserPosition)
|
197 |
+
) {
|
198 |
+
$res = false;
|
199 |
+
}
|
200 |
+
}
|
201 |
+
}
|
202 |
+
if(isset($permissions[CFS_USERLEVELS])
|
203 |
+
&& !empty($permissions[CFS_USERLEVELS])
|
204 |
+
) {
|
205 |
+
$currentUserPosition = frameCfs::_()->getModule('user')->getCurrentUserPosition();
|
206 |
+
// For multi-sites network admin role is undefined, let's do this here
|
207 |
+
if(is_multisite() && is_admin() && is_super_admin()) {
|
208 |
+
$currentUserPosition = CFS_ADMIN;
|
209 |
+
}
|
210 |
+
foreach($permissions[CFS_USERLEVELS] as $userlevel => $methods) {
|
211 |
+
if(is_array($methods)) {
|
212 |
+
$lowerMethods = array_map('strtolower', $methods); // Make case-insensitive
|
213 |
+
if(in_array($action, $lowerMethods)) { // Permission for this method exists
|
214 |
+
if($currentUserPosition != $userlevel)
|
215 |
+
$res = false;
|
216 |
+
break;
|
217 |
+
}
|
218 |
+
} else {
|
219 |
+
$lowerMethod = strtolower($methods); // Make case-insensitive
|
220 |
+
if($lowerMethod == $action) { // Permission for this method exists
|
221 |
+
if($currentUserPosition != $userlevel)
|
222 |
+
$res = false;
|
223 |
+
break;
|
224 |
+
}
|
225 |
+
}
|
226 |
+
}
|
227 |
+
}
|
228 |
+
}
|
229 |
+
if($res) { // Additional check for nonces
|
230 |
+
$noncedMethods = $mod->getController()->getNoncedMethods();
|
231 |
+
if(!empty($noncedMethods)) {
|
232 |
+
$noncedMethods = array_map('strtolower', $noncedMethods);
|
233 |
+
if(in_array($action, $noncedMethods)) {
|
234 |
+
$nonce = isset($_REQUEST['_wpnonce']) ? $_REQUEST['_wpnonce'] : reqCfs::getVar('_wpnonce');
|
235 |
+
if(!wp_verify_nonce( $nonce, $action )) {
|
236 |
+
$res = false;
|
237 |
+
}
|
238 |
+
}
|
239 |
+
}
|
240 |
+
}
|
241 |
+
}
|
242 |
+
return $res;
|
243 |
+
}
|
244 |
+
public function getRes() {
|
245 |
+
return $this->_res;
|
246 |
+
}
|
247 |
+
public function execAfterWpInit() {
|
248 |
+
$this->_doExec();
|
249 |
+
}
|
250 |
+
/**
|
251 |
+
* Check if method for module require some special permission. We can detect users permissions only after wp init action was done.
|
252 |
+
*/
|
253 |
+
protected function _execOnlyAfterWpInit() {
|
254 |
+
$res = false;
|
255 |
+
$mod = $this->getModule( $this->_mod );
|
256 |
+
$action = strtolower( $this->_action );
|
257 |
+
if($mod) {
|
258 |
+
$permissions = $mod->getController()->getPermissions();
|
259 |
+
if(!empty($permissions)) { // Special permissions
|
260 |
+
if(isset($permissions[CFS_METHODS])
|
261 |
+
&& !empty($permissions[CFS_METHODS])
|
262 |
+
) {
|
263 |
+
foreach($permissions[CFS_METHODS] as $method => $permissions) { // Make case-insensitive
|
264 |
+
$permissions[CFS_METHODS][strtolower($method)] = $permissions;
|
265 |
+
}
|
266 |
+
if(array_key_exists($action, $permissions[CFS_METHODS])) { // Permission for this method exists
|
267 |
+
$res = true;
|
268 |
+
}
|
269 |
+
}
|
270 |
+
if(isset($permissions[CFS_USERLEVELS])
|
271 |
+
&& !empty($permissions[CFS_USERLEVELS])
|
272 |
+
) {
|
273 |
+
foreach($permissions[CFS_USERLEVELS] as $level => $methods) {
|
274 |
+
if(!empty($methods)) {
|
275 |
+
$res = true;
|
276 |
+
break;
|
277 |
+
}
|
278 |
+
}
|
279 |
+
}
|
280 |
+
}
|
281 |
+
}
|
282 |
+
return $res;
|
283 |
+
}
|
284 |
+
protected function _execModules() {
|
285 |
+
if($this->_mod) {
|
286 |
+
// If module exist and is active
|
287 |
+
$mod = $this->getModule($this->_mod);
|
288 |
+
if($mod && !empty($this->_action)) {
|
289 |
+
if($this->_execOnlyAfterWpInit()) {
|
290 |
+
add_action('init', array($this, 'execAfterWpInit'));
|
291 |
+
} else {
|
292 |
+
$this->_doExec();
|
293 |
+
}
|
294 |
+
}
|
295 |
+
}
|
296 |
+
}
|
297 |
+
protected function _doExec() {
|
298 |
+
$mod = $this->getModule($this->_mod);
|
299 |
+
if($mod && $this->checkPermissions($this->_mod, $this->_action)) {
|
300 |
+
switch(reqCfs::getVar('reqType')) {
|
301 |
+
case 'ajax':
|
302 |
+
add_action('wp_ajax_'. $this->_action, array($mod->getController(), $this->_action));
|
303 |
+
add_action('wp_ajax_nopriv_'. $this->_action, array($mod->getController(), $this->_action));
|
304 |
+
break;
|
305 |
+
default:
|
306 |
+
$this->_res = $mod->exec($this->_action);
|
307 |
+
break;
|
308 |
+
}
|
309 |
+
}
|
310 |
+
}
|
311 |
+
protected function _extractTables($tablesDir = CFS_TABLES_DIR) {
|
312 |
+
$mDirHandle = opendir($tablesDir);
|
313 |
+
while(($file = readdir($mDirHandle)) !== false) {
|
314 |
+
if(is_file($tablesDir. $file) && $file != '.' && $file != '..' && strpos($file, '.php')) {
|
315 |
+
$this->_extractTable( str_replace('.php', '', $file), $tablesDir );
|
316 |
+
}
|
317 |
+
}
|
318 |
+
}
|
319 |
+
protected function _extractTable($tableName, $tablesDir = CFS_TABLES_DIR) {
|
320 |
+
importClassCfs('noClassNameHere', $tablesDir. $tableName. '.php');
|
321 |
+
$this->_tables[$tableName] = tableCfs::_($tableName);
|
322 |
+
}
|
323 |
+
/**
|
324 |
+
* public alias for _extractTables method
|
325 |
+
* @see _extractTables
|
326 |
+
*/
|
327 |
+
public function extractTables($tablesDir) {
|
328 |
+
if(!empty($tablesDir))
|
329 |
+
$this->_extractTables($tablesDir);
|
330 |
+
}
|
331 |
+
public function exec() {
|
332 |
+
/**
|
333 |
+
* @deprecated
|
334 |
+
*/
|
335 |
+
/*if(!empty($this->_modules)) {
|
336 |
+
foreach($this->_modules as $mod) {
|
337 |
+
$mod->exec();
|
338 |
+
}
|
339 |
+
}*/
|
340 |
+
}
|
341 |
+
public function getTables () {
|
342 |
+
return $this->_tables;
|
343 |
+
}
|
344 |
+
/**
|
345 |
+
* Return table by name
|
346 |
+
* @param string $tableName table name in database
|
347 |
+
* @return object table
|
348 |
+
* @example frameCfs::_()->getTable('products')->getAll()
|
349 |
+
*/
|
350 |
+
public function getTable($tableName) {
|
351 |
+
if(empty($this->_tables[$tableName])) {
|
352 |
+
$this->_extractTable($tableName);
|
353 |
+
}
|
354 |
+
return $this->_tables[$tableName];
|
355 |
+
}
|
356 |
+
public function getModules($filter = array()) {
|
357 |
+
$res = array();
|
358 |
+
if(empty($filter))
|
359 |
+
$res = $this->_modules;
|
360 |
+
else {
|
361 |
+
foreach($this->_modules as $code => $mod) {
|
362 |
+
if(isset($filter['type'])) {
|
363 |
+
if(is_numeric($filter['type']) && $filter['type'] == $mod->getTypeID())
|
364 |
+
$res[$code] = $mod;
|
365 |
+
elseif($filter['type'] == $mod->getType())
|
366 |
+
$res[$code] = $mod;
|
367 |
+
}
|
368 |
+
}
|
369 |
+
}
|
370 |
+
return $res;
|
371 |
+
}
|
372 |
+
|
373 |
+
public function getModule($code) {
|
374 |
+
return (isset($this->_modules[$code]) ? $this->_mo
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|