Toolset Types – Custom Post Types, Custom Fields and Taxonomies - Version 2.2.6

Version Description

  • Updated Installer to 1.7.15.
  • Fix several issues with the Styling editor.
  • Fixed a compatibility with Layouts, child themes of Layouts-integrated themes haven't been recognized as such.
  • Fixed a compatibility with WPML, where a rare ID collision caused problems on the parent post selection dropdown.
Download this release

Release Info

Developer zaantar
Plugin Icon 128x128 Toolset Types – Custom Post Types, Custom Fields and Taxonomies
Version 2.2.6
Comparing to
See all releases

Code changes from version 2.2.5 to 2.2.6

Files changed (690) hide show
  1. application/models/helper/condition/layouts/compatible.php +8 -4
  2. application/models/wpml/field_group.php +2 -1
  3. disabled_autoload_classmap.php +151 -0
  4. library/otgs/installer/README.md +63 -0
  5. library/otgs/installer/changelog.txt +8 -0
  6. library/otgs/installer/includes/installer.class.php +16 -8
  7. library/otgs/installer/installer.php +1 -1
  8. library/otgs/installer/loader.php +1 -1
  9. library/otgs/installer/res/js/admin.js +4 -0
  10. library/toolset/onthego-resources/.gitignore +72 -0
  11. library/toolset/onthego-resources/changelog.txt +47 -0
  12. library/toolset/onthego-resources/classes/onthegosystems-styles.class.php +23 -9
  13. library/toolset/onthego-resources/loader.php +1 -1
  14. library/toolset/toolset-common/loader.php +1 -1
  15. library/toolset/toolset-common/toolset-common-loader.php +2 -2
  16. library/toolset/toolset-common/toolset-forms/classes/class.credfile.php +118 -20
  17. library/toolset/toolset-common/toolset-forms/classes/submit.php +19 -31
  18. library/toolset/toolset-common/toolset-forms/js/credfile.js +9 -7
  19. library/toolset/toolset-common/toolset-forms/js/jquery_upload/file_upload.js +10 -7
  20. library/toolset/toolset-common/toolset-forms/js/validation.js +5 -3
  21. library/toolset/toolset-common/visual-editor/res/js/codemirror/.gitattributes +8 -0
  22. library/toolset/toolset-common/visual-editor/res/js/codemirror/.gitignore +8 -0
  23. library/toolset/toolset-common/visual-editor/res/js/codemirror/.npmignore +9 -0
  24. library/toolset/toolset-common/visual-editor/res/js/codemirror/.travis.yml +4 -0
  25. library/toolset/types/.travis.yml +29 -0
  26. library/toolset/types/bin/install-wp-tests.sh +118 -0
  27. library/toolset/types/disabled_autoload_classmap.php +101 -0
  28. library/toolset/types/embedded/includes/fields-post.php +47 -49
  29. library/toolset/types/embedded/includes/post-relationship.php +129 -116
  30. library/toolset/types/embedded/resources/js/custom-fields-form-filter.js +11 -22
  31. library/toolset/types/includes/classes/class.types.admin.edit.custom.fields.group.php +1 -1
  32. library/toolset/types/phpunit.xml.dist +14 -0
  33. library/twig/twig/.editorconfig +18 -0
  34. library/twig/twig/.gitignore +5 -0
  35. library/twig/twig/.php_cs.dist +15 -0
  36. library/twig/twig/.travis.yml +44 -0
  37. library/twig/twig/CHANGELOG +23 -0
  38. library/twig/twig/LICENSE +1 -1
  39. library/twig/twig/composer.json +46 -0
  40. library/twig/twig/doc/advanced.rst +957 -0
  41. library/twig/twig/doc/advanced_legacy.rst +885 -0
  42. library/twig/twig/doc/api.rst +590 -0
  43. library/twig/twig/doc/coding_standards.rst +101 -0
  44. library/twig/twig/doc/deprecated.rst +221 -0
  45. library/twig/twig/doc/filters/abs.rst +18 -0
  46. library/twig/twig/doc/filters/batch.rst +51 -0
  47. library/twig/twig/doc/filters/capitalize.rst +11 -0
  48. library/twig/twig/doc/filters/convert_encoding.rst +28 -0
  49. library/twig/twig/doc/filters/date.rst +100 -0
  50. library/twig/twig/doc/filters/date_modify.rst +23 -0
  51. library/twig/twig/doc/filters/default.rst +33 -0
  52. library/twig/twig/doc/filters/escape.rst +119 -0
  53. library/twig/twig/doc/filters/first.rst +25 -0
  54. library/twig/twig/doc/filters/format.rst +16 -0
  55. library/twig/twig/doc/filters/index.rst +37 -0
  56. library/twig/twig/doc/filters/join.rst +23 -0
  57. library/twig/twig/doc/filters/json_encode.rst +21 -0
  58. library/twig/twig/doc/filters/keys.rst +11 -0
  59. library/twig/twig/doc/filters/last.rst +25 -0
  60. library/twig/twig/doc/filters/length.rst +11 -0
  61. library/twig/twig/doc/filters/lower.rst +10 -0
  62. library/twig/twig/doc/filters/merge.rst +48 -0
  63. library/twig/twig/doc/filters/nl2br.rst +22 -0
  64. library/twig/twig/doc/filters/number_format.rst +48 -0
  65. library/twig/twig/doc/filters/raw.rst +36 -0
  66. library/twig/twig/doc/filters/replace.rst +19 -0
  67. library/twig/twig/doc/filters/reverse.rst +47 -0
  68. library/twig/twig/doc/filters/round.rst +37 -0
  69. library/twig/twig/doc/filters/slice.rst +71 -0
  70. library/twig/twig/doc/filters/sort.rst +18 -0
  71. library/twig/twig/doc/filters/split.rst +53 -0
  72. library/twig/twig/doc/filters/striptags.rst +15 -0
  73. library/twig/twig/doc/filters/title.rst +11 -0
  74. library/twig/twig/doc/filters/trim.rst +29 -0
  75. library/twig/twig/doc/filters/upper.rst +10 -0
  76. library/twig/twig/doc/filters/url_encode.rst +34 -0
  77. library/twig/twig/doc/functions/attribute.rst +26 -0
  78. library/twig/twig/doc/functions/block.rst +41 -0
  79. library/twig/twig/doc/functions/constant.rst +29 -0
  80. library/twig/twig/doc/functions/cycle.rst +28 -0
  81. library/twig/twig/doc/functions/date.rst +55 -0
  82. library/twig/twig/doc/functions/dump.rst +69 -0
  83. library/twig/twig/doc/functions/include.rst +84 -0
  84. library/twig/twig/doc/functions/index.rst +20 -0
  85. library/twig/twig/doc/functions/max.rst +20 -0
  86. library/twig/twig/doc/functions/min.rst +20 -0
  87. library/twig/twig/doc/functions/parent.rst +20 -0
  88. library/twig/twig/doc/functions/random.rst +29 -0
  89. library/twig/twig/doc/functions/range.rst +58 -0
  90. library/twig/twig/doc/functions/source.rst +32 -0
  91. library/twig/twig/doc/functions/template_from_string.rst +32 -0
  92. library/twig/twig/doc/index.rst +19 -0
  93. library/twig/twig/doc/installation.rst +116 -0
  94. library/twig/twig/doc/internals.rst +142 -0
  95. library/twig/twig/doc/intro.rst +85 -0
  96. library/twig/twig/doc/recipes.rst +568 -0
  97. library/twig/twig/doc/tags/autoescape.rst +81 -0
  98. library/twig/twig/doc/tags/block.rst +11 -0
  99. library/twig/twig/doc/tags/do.rst +12 -0
  100. library/twig/twig/doc/tags/embed.rst +178 -0
  101. library/twig/twig/doc/tags/extends.rst +272 -0
  102. library/twig/twig/doc/tags/filter.rst +21 -0
  103. library/twig/twig/doc/tags/flush.rst +17 -0
  104. library/twig/twig/doc/tags/for.rst +172 -0
  105. library/twig/twig/doc/tags/from.rst +8 -0
  106. library/twig/twig/doc/tags/if.rst +76 -0
  107. library/twig/twig/doc/tags/import.rst +57 -0
  108. library/twig/twig/doc/tags/include.rst +90 -0
  109. library/twig/twig/doc/tags/index.rst +25 -0
  110. library/twig/twig/doc/tags/macro.rst +103 -0
  111. library/twig/twig/doc/tags/sandbox.rst +30 -0
  112. library/twig/twig/doc/tags/set.rst +78 -0
  113. library/twig/twig/doc/tags/spaceless.rst +37 -0
  114. library/twig/twig/doc/tags/use.rst +124 -0
  115. library/twig/twig/doc/tags/verbatim.rst +24 -0
  116. library/twig/twig/doc/tags/with.rst +44 -0
  117. library/twig/twig/doc/templates.rst +908 -0
  118. library/twig/twig/doc/tests/constant.rst +22 -0
  119. library/twig/twig/doc/tests/defined.rst +30 -0
  120. library/twig/twig/doc/tests/divisibleby.rst +14 -0
  121. library/twig/twig/doc/tests/empty.rst +11 -0
  122. library/twig/twig/doc/tests/even.rst +10 -0
  123. library/twig/twig/doc/tests/index.rst +15 -0
  124. library/twig/twig/doc/tests/iterable.rst +19 -0
  125. library/twig/twig/doc/tests/null.rst +12 -0
  126. library/twig/twig/doc/tests/odd.rst +10 -0
  127. library/twig/twig/doc/tests/sameas.rst +14 -0
  128. library/twig/twig/ext/twig/.gitignore +30 -0
  129. library/twig/twig/ext/twig/config.m4 +8 -0
  130. library/twig/twig/ext/twig/config.w32 +8 -0
  131. library/twig/twig/ext/twig/php_twig.h +35 -0
  132. library/twig/twig/ext/twig/twig.c +1215 -0
  133. library/twig/twig/lib/Twig/Autoloader.php +3 -3
  134. library/twig/twig/lib/Twig/BaseNodeVisitor.php +0 -6
  135. library/twig/twig/lib/Twig/Cache/Filesystem.php +1 -13
  136. library/twig/twig/lib/Twig/Cache/Null.php +3 -13
  137. library/twig/twig/lib/Twig/CacheInterface.php +1 -1
  138. library/twig/twig/lib/Twig/Compiler.php +4 -2
  139. library/twig/twig/lib/Twig/CompilerInterface.php +1 -1
  140. library/twig/twig/lib/Twig/Environment.php +28 -15
  141. library/twig/twig/lib/Twig/Error.php +73 -11
  142. library/twig/twig/lib/Twig/Error/Loader.php +10 -3
  143. library/twig/twig/lib/Twig/Error/Runtime.php +2 -2
  144. library/twig/twig/lib/Twig/Error/Syntax.php +2 -2
  145. library/twig/twig/lib/Twig/ExistsLoaderInterface.php +1 -1
  146. library/twig/twig/lib/Twig/ExpressionParser.php +25 -22
  147. library/twig/twig/lib/Twig/Extension.php +1 -25
  148. library/twig/twig/lib/Twig/Extension/Core.php +63 -13
  149. library/twig/twig/lib/Twig/Extension/Debug.php +5 -1
  150. library/twig/twig/lib/Twig/Extension/Escaper.php +5 -1
  151. library/twig/twig/lib/Twig/Extension/Optimizer.php +5 -1
  152. library/twig/twig/lib/Twig/Extension/Profiler.php +1 -1
  153. library/twig/twig/lib/Twig/Extension/Sandbox.php +5 -1
  154. library/twig/twig/lib/Twig/Extension/Staging.php +18 -2
  155. library/twig/twig/lib/Twig/Extension/StringLoader.php +5 -1
  156. library/twig/twig/lib/Twig/ExtensionInterface.php +2 -2
  157. library/twig/twig/lib/Twig/FactoryRuntimeLoader.php +37 -0
  158. library/twig/twig/lib/Twig/FileExtensionEscapingStrategy.php +1 -1
  159. library/twig/twig/lib/Twig/Filter.php +1 -1
  160. library/twig/twig/lib/Twig/Filter/Function.php +1 -1
  161. library/twig/twig/lib/Twig/Filter/Method.php +1 -1
  162. library/twig/twig/lib/Twig/Filter/Node.php +1 -1
  163. library/twig/twig/lib/Twig/FilterCallableInterface.php +1 -1
  164. library/twig/twig/lib/Twig/FilterInterface.php +1 -1
  165. library/twig/twig/lib/Twig/Function.php +1 -1
  166. library/twig/twig/lib/Twig/Function/Function.php +2 -2
  167. library/twig/twig/lib/Twig/Function/Method.php +2 -2
  168. library/twig/twig/lib/Twig/Function/Node.php +1 -1
  169. library/twig/twig/lib/Twig/FunctionCallableInterface.php +1 -1
  170. library/twig/twig/lib/Twig/FunctionInterface.php +2 -2
  171. library/twig/twig/lib/Twig/Lexer.php +21 -18
  172. library/twig/twig/lib/Twig/LexerInterface.php +1 -1
  173. library/twig/twig/lib/Twig/Loader/Array.php +3 -16
  174. library/twig/twig/lib/Twig/Loader/Chain.php +3 -16
  175. library/twig/twig/lib/Twig/Loader/Filesystem.php +1 -16
  176. library/twig/twig/lib/Twig/Loader/String.php +1 -16
  177. library/twig/twig/lib/Twig/LoaderInterface.php +1 -1
  178. library/twig/twig/lib/Twig/Markup.php +1 -1
  179. library/twig/twig/lib/Twig/Node.php +2 -2
  180. library/twig/twig/lib/Twig/Node/AutoEscape.php +1 -1
  181. library/twig/twig/lib/Twig/Node/Block.php +2 -2
  182. library/twig/twig/lib/Twig/Node/BlockReference.php +2 -2
  183. library/twig/twig/lib/Twig/Node/Body.php +1 -1
  184. library/twig/twig/lib/Twig/Node/CheckSecurity.php +2 -2
  185. library/twig/twig/lib/Twig/Node/Do.php +1 -1
  186. library/twig/twig/lib/Twig/Node/Embed.php +1 -1
  187. library/twig/twig/lib/Twig/Node/Expression.php +2 -2
  188. library/twig/twig/lib/Twig/Node/Expression/Array.php +1 -1
  189. library/twig/twig/lib/Twig/Node/Expression/AssignName.php +2 -2
  190. library/twig/twig/lib/Twig/Node/Expression/Binary.php +2 -2
  191. library/twig/twig/lib/Twig/Node/Expression/Binary/Add.php +2 -2
  192. library/twig/twig/lib/Twig/Node/Expression/Binary/And.php +2 -2
  193. library/twig/twig/lib/Twig/Node/Expression/Binary/BitwiseAnd.php +2 -2
  194. library/twig/twig/lib/Twig/Node/Expression/Binary/BitwiseOr.php +2 -2
  195. library/twig/twig/lib/Twig/Node/Expression/Binary/BitwiseXor.php +2 -2
  196. library/twig/twig/lib/Twig/Node/Expression/Binary/Concat.php +2 -2
  197. library/twig/twig/lib/Twig/Node/Expression/Binary/Div.php +2 -2
  198. library/twig/twig/lib/Twig/Node/Expression/Binary/EndsWith.php +1 -1
  199. library/twig/twig/lib/Twig/Node/Expression/Binary/Equal.php +1 -1
  200. library/twig/twig/lib/Twig/Node/Expression/Binary/FloorDiv.php +1 -1
  201. library/twig/twig/lib/Twig/Node/Expression/Binary/Greater.php +1 -1
  202. library/twig/twig/lib/Twig/Node/Expression/Binary/GreaterEqual.php +1 -1
  203. library/twig/twig/lib/Twig/Node/Expression/Binary/In.php +1 -1
  204. library/twig/twig/lib/Twig/Node/Expression/Binary/Less.php +1 -1
  205. library/twig/twig/lib/Twig/Node/Expression/Binary/LessEqual.php +1 -1
  206. library/twig/twig/lib/Twig/Node/Expression/Binary/Matches.php +1 -1
  207. library/twig/twig/lib/Twig/Node/Expression/Binary/Mod.php +2 -2
  208. library/twig/twig/lib/Twig/Node/Expression/Binary/Mul.php +2 -2
  209. library/twig/twig/lib/Twig/Node/Expression/Binary/NotEqual.php +1 -1
  210. library/twig/twig/lib/Twig/Node/Expression/Binary/NotIn.php +1 -1
  211. library/twig/twig/lib/Twig/Node/Expression/Binary/Or.php +2 -2
  212. library/twig/twig/lib/Twig/Node/Expression/Binary/Power.php +1 -1
  213. library/twig/twig/lib/Twig/Node/Expression/Binary/Range.php +1 -1
  214. library/twig/twig/lib/Twig/Node/Expression/Binary/StartsWith.php +1 -1
  215. library/twig/twig/lib/Twig/Node/Expression/Binary/Sub.php +2 -2
  216. library/twig/twig/lib/Twig/Node/Expression/BlockReference.php +2 -2
  217. library/twig/twig/lib/Twig/Node/Expression/Call.php +1 -1
  218. library/twig/twig/lib/Twig/Node/Expression/Conditional.php +2 -2
  219. library/twig/twig/lib/Twig/Node/Expression/Constant.php +2 -2
  220. library/twig/twig/lib/Twig/Node/Expression/ExtensionReference.php +1 -1
  221. library/twig/twig/lib/Twig/Node/Expression/Filter.php +2 -2
  222. library/twig/twig/lib/Twig/Node/Expression/Filter/Default.php +1 -1
  223. library/twig/twig/lib/Twig/Node/Expression/Function.php +1 -1
  224. library/twig/twig/lib/Twig/Node/Expression/GetAttr.php +6 -2
  225. library/twig/twig/lib/Twig/Node/Expression/MethodCall.php +1 -1
  226. library/twig/twig/lib/Twig/Node/Expression/Name.php +2 -2
  227. library/twig/twig/lib/Twig/Node/Expression/Parent.php +2 -2
  228. library/twig/twig/lib/Twig/Node/Expression/TempName.php +1 -1
  229. library/twig/twig/lib/Twig/Node/Expression/Test.php +1 -1
  230. library/twig/twig/lib/Twig/Node/Expression/Test/Constant.php +1 -1
  231. library/twig/twig/lib/Twig/Node/Expression/Test/Defined.php +1 -1
  232. library/twig/twig/lib/Twig/Node/Expression/Test/Divisibleby.php +1 -1
  233. library/twig/twig/lib/Twig/Node/Expression/Test/Even.php +1 -1
  234. library/twig/twig/lib/Twig/Node/Expression/Test/Null.php +1 -1
  235. library/twig/twig/lib/Twig/Node/Expression/Test/Odd.php +1 -1
  236. library/twig/twig/lib/Twig/Node/Expression/Test/Sameas.php +1 -1
  237. library/twig/twig/lib/Twig/Node/Expression/Unary.php +2 -2
  238. library/twig/twig/lib/Twig/Node/Expression/Unary/Neg.php +2 -2
  239. library/twig/twig/lib/Twig/Node/Expression/Unary/Not.php +2 -2
  240. library/twig/twig/lib/Twig/Node/Expression/Unary/Pos.php +2 -2
  241. library/twig/twig/lib/Twig/Node/Flush.php +1 -1
  242. library/twig/twig/lib/Twig/Node/For.php +2 -2
  243. library/twig/twig/lib/Twig/Node/ForLoop.php +1 -1
  244. library/twig/twig/lib/Twig/Node/If.php +2 -2
  245. library/twig/twig/lib/Twig/Node/Import.php +1 -1
  246. library/twig/twig/lib/Twig/Node/Include.php +2 -2
  247. library/twig/twig/lib/Twig/Node/Macro.php +1 -1
  248. library/twig/twig/lib/Twig/Node/Module.php +2 -2
  249. library/twig/twig/lib/Twig/Node/Print.php +2 -2
  250. library/twig/twig/lib/Twig/Node/Sandbox.php +1 -1
  251. library/twig/twig/lib/Twig/Node/SandboxedPrint.php +1 -1
  252. library/twig/twig/lib/Twig/Node/Set.php +2 -2
  253. library/twig/twig/lib/Twig/Node/SetTemp.php +1 -1
  254. library/twig/twig/lib/Twig/Node/Spaceless.php +1 -1
  255. library/twig/twig/lib/Twig/Node/Text.php +2 -2
  256. library/twig/twig/lib/Twig/Node/With.php +1 -1
  257. library/twig/twig/lib/Twig/NodeCaptureInterface.php +19 -0
  258. library/twig/twig/lib/Twig/NodeInterface.php +1 -1
  259. library/twig/twig/lib/Twig/NodeOutputInterface.php +1 -1
  260. library/twig/twig/lib/Twig/NodeTraverser.php +3 -1
  261. library/twig/twig/lib/Twig/NodeVisitor/Escaper.php +3 -10
  262. library/twig/twig/lib/Twig/NodeVisitor/Optimizer.php +3 -10
  263. library/twig/twig/lib/Twig/NodeVisitor/SafeAnalysis.php +3 -9
  264. library/twig/twig/lib/Twig/NodeVisitor/Sandbox.php +3 -10
  265. library/twig/twig/lib/Twig/NodeVisitorInterface.php +1 -1
  266. library/twig/twig/lib/Twig/Parser.php +13 -16
  267. library/twig/twig/lib/Twig/ParserInterface.php +1 -1
  268. library/twig/twig/lib/Twig/Profiler/Dumper/Blackfire.php +3 -1
  269. library/twig/twig/lib/Twig/Profiler/Dumper/Html.php +3 -1
  270. library/twig/twig/lib/Twig/Profiler/Dumper/Text.php +3 -1
  271. library/twig/twig/lib/Twig/Profiler/Node/EnterProfile.php +1 -4
  272. library/twig/twig/lib/Twig/Profiler/Node/LeaveProfile.php +1 -4
  273. library/twig/twig/lib/Twig/Profiler/NodeVisitor/Profiler.php +3 -10
  274. library/twig/twig/lib/Twig/Profiler/Profile.php +3 -1
  275. library/twig/twig/lib/Twig/Sandbox/SecurityError.php +1 -1
  276. library/twig/twig/lib/Twig/Sandbox/SecurityNotAllowedFilterError.php +1 -1
  277. library/twig/twig/lib/Twig/Sandbox/SecurityNotAllowedFunctionError.php +1 -1
  278. library/twig/twig/lib/Twig/Sandbox/SecurityNotAllowedMethodError.php +1 -1
  279. library/twig/twig/lib/Twig/Sandbox/SecurityNotAllowedPropertyError.php +1 -1
  280. library/twig/twig/lib/Twig/Sandbox/SecurityNotAllowedTagError.php +1 -1
  281. library/twig/twig/lib/Twig/Sandbox/SecurityPolicy.php +3 -1
  282. library/twig/twig/lib/Twig/Sandbox/SecurityPolicyInterface.php +1 -1
  283. library/twig/twig/lib/Twig/SimpleFilter.php +3 -1
  284. library/twig/twig/lib/Twig/SimpleFunction.php +3 -1
  285. library/twig/twig/lib/Twig/SimpleTest.php +3 -1
  286. library/twig/twig/lib/Twig/Source.php +3 -1
  287. library/twig/twig/lib/Twig/SourceContextLoaderInterface.php +1 -1
  288. library/twig/twig/lib/Twig/Template.php +32 -28
  289. library/twig/twig/lib/Twig/TemplateInterface.php +1 -1
  290. library/twig/twig/lib/Twig/TemplateWrapper.php +1 -1
  291. library/twig/twig/lib/Twig/Test.php +1 -1
  292. library/twig/twig/lib/Twig/Test/Function.php +1 -1
  293. library/twig/twig/lib/Twig/Test/IntegrationTestCase.php +2 -12
  294. library/twig/twig/lib/Twig/Test/Method.php +1 -1
  295. library/twig/twig/lib/Twig/Test/Node.php +1 -1
  296. library/twig/twig/lib/Twig/TestCallableInterface.php +1 -1
  297. library/twig/twig/lib/Twig/TestInterface.php +1 -1
  298. library/twig/twig/lib/Twig/Token.php +4 -2
  299. library/twig/twig/lib/Twig/TokenParser.php +1 -1
  300. library/twig/twig/lib/Twig/TokenParser/AutoEscape.php +5 -3
  301. library/twig/twig/lib/Twig/TokenParser/Block.php +6 -4
  302. library/twig/twig/lib/Twig/TokenParser/Do.php +3 -1
  303. library/twig/twig/lib/Twig/TokenParser/Embed.php +3 -1
  304. library/twig/twig/lib/Twig/TokenParser/Extends.php +6 -4
  305. library/twig/twig/lib/Twig/TokenParser/Filter.php +3 -1
  306. library/twig/twig/lib/Twig/TokenParser/Flush.php +3 -1
  307. library/twig/twig/lib/Twig/TokenParser/For.php +6 -4
  308. library/twig/twig/lib/Twig/TokenParser/From.php +4 -2
  309. library/twig/twig/lib/Twig/TokenParser/If.php +5 -3
  310. library/twig/twig/lib/Twig/TokenParser/Import.php +3 -1
  311. library/twig/twig/lib/Twig/TokenParser/Include.php +4 -2
  312. library/twig/twig/lib/Twig/TokenParser/Macro.php +4 -2
  313. library/twig/twig/lib/Twig/TokenParser/Sandbox.php +4 -2
  314. library/twig/twig/lib/Twig/TokenParser/Set.php +5 -3
  315. library/twig/twig/lib/Twig/TokenParser/Spaceless.php +3 -1
  316. library/twig/twig/lib/Twig/TokenParser/Use.php +4 -2
  317. library/twig/twig/lib/Twig/TokenParser/With.php +3 -1
  318. library/twig/twig/lib/Twig/TokenParserBroker.php +2 -2
  319. library/twig/twig/lib/Twig/TokenParserBrokerInterface.php +2 -2
  320. library/twig/twig/lib/Twig/TokenParserInterface.php +1 -1
  321. library/twig/twig/lib/Twig/TokenStream.php +7 -5
  322. library/twig/twig/lib/Twig/Util/DeprecationCollector.php +2 -0
  323. library/twig/twig/phpunit.xml.dist +33 -0
  324. library/twig/twig/test/Twig/Tests/AutoloaderTest.php +24 -0
  325. library/twig/twig/test/Twig/Tests/Cache/FilesystemTest.php +193 -0
  326. library/twig/twig/test/Twig/Tests/CompilerTest.php +33 -0
  327. library/twig/twig/test/Twig/Tests/CustomExtensionTest.php +88 -0
  328. library/twig/twig/test/Twig/Tests/EnvironmentTest.php +652 -0
  329. library/twig/twig/test/Twig/Tests/ErrorTest.php +211 -0
  330. library/twig/twig/test/Twig/Tests/ExpressionParserTest.php +373 -0
  331. library/twig/twig/test/Twig/Tests/Extension/CoreTest.php +355 -0
  332. library/twig/twig/test/Twig/Tests/Extension/SandboxTest.php +304 -0
  333. library/twig/twig/test/Twig/Tests/FileCachingTest.php +63 -0
  334. library/twig/twig/test/Twig/Tests/FileExtensionEscapingStrategyTest.php +51 -0
  335. library/twig/twig/test/Twig/Tests/FilesystemHelper.php +30 -0
  336. library/twig/twig/test/Twig/Tests/Fixtures/autoescape/block.test +21 -0
  337. library/twig/twig/test/Twig/Tests/Fixtures/autoescape/name.test +18 -0
  338. library/twig/twig/test/Twig/Tests/Fixtures/errors/base.html +1 -0
  339. library/twig/twig/test/Twig/Tests/Fixtures/errors/index.html +7 -0
  340. library/twig/twig/test/Twig/Tests/Fixtures/exceptions/child_contents_outside_blocks.test +15 -0
  341. library/twig/twig/test/Twig/Tests/Fixtures/exceptions/multiline_array_with_undefined_variable.test +18 -0
  342. library/twig/twig/test/Twig/Tests/Fixtures/exceptions/multiline_array_with_undefined_variable_again.test +18 -0
  343. library/twig/twig/test/Twig/Tests/Fixtures/exceptions/multiline_function_with_undefined_variable.test +12 -0
  344. library/twig/twig/test/Twig/Tests/Fixtures/exceptions/multiline_function_with_unknown_argument.test +9 -0
  345. library/twig/twig/test/Twig/Tests/Fixtures/exceptions/multiline_tag_with_undefined_variable.test +12 -0
  346. library/twig/twig/test/Twig/Tests/Fixtures/exceptions/syntax_error_in_reused_template.test +10 -0
  347. library/twig/twig/test/Twig/Tests/Fixtures/exceptions/unclosed_tag.test +20 -0
  348. library/twig/twig/test/Twig/Tests/Fixtures/exceptions/undefined_parent.test +8 -0
  349. library/twig/twig/test/Twig/Tests/Fixtures/exceptions/undefined_template_in_child_template.test +15 -0
  350. library/twig/twig/test/Twig/Tests/Fixtures/exceptions/undefined_trait.test +9 -0
  351. library/twig/twig/test/Twig/Tests/Fixtures/expressions/_self.test +8 -0
  352. library/twig/twig/test/Twig/Tests/Fixtures/expressions/array.test +61 -0
  353. library/twig/twig/test/Twig/Tests/Fixtures/expressions/array_call.test +14 -0
  354. library/twig/twig/test/Twig/Tests/Fixtures/expressions/binary.test +46 -0
  355. library/twig/twig/test/Twig/Tests/Fixtures/expressions/bitwise.test +14 -0
  356. library/twig/twig/test/Twig/Tests/Fixtures/expressions/comparison.test +14 -0
  357. library/twig/twig/test/Twig/Tests/Fixtures/expressions/divisibleby.test +17 -0
  358. library/twig/twig/test/Twig/Tests/Fixtures/expressions/dotdot.test +20 -0
  359. library/twig/twig/test/Twig/Tests/Fixtures/expressions/ends_with.test +26 -0
  360. library/twig/twig/test/Twig/Tests/Fixtures/expressions/grouping.test +8 -0
  361. library/twig/twig/test/Twig/Tests/Fixtures/expressions/literals.test +22 -0
  362. library/twig/twig/test/Twig/Tests/Fixtures/expressions/magic_call.test +27 -0
  363. library/twig/twig/test/Twig/Tests/Fixtures/expressions/matches.test +12 -0
  364. library/twig/twig/test/Twig/Tests/Fixtures/expressions/method_call.test +28 -0
  365. library/twig/twig/test/Twig/Tests/Fixtures/expressions/negative_numbers.test +18 -0
  366. library/twig/twig/test/Twig/Tests/Fixtures/expressions/operators_as_variables.test +16 -0
  367. library/twig/twig/test/Twig/Tests/Fixtures/expressions/postfix.test +22 -0
  368. library/twig/twig/test/Twig/Tests/Fixtures/expressions/power.test +20 -0
  369. library/twig/twig/test/Twig/Tests/Fixtures/expressions/sameas.test +21 -0
  370. library/twig/twig/test/Twig/Tests/Fixtures/expressions/starts_with.test +27 -0
  371. library/twig/twig/test/Twig/Tests/Fixtures/expressions/strings.test +10 -0
  372. library/twig/twig/test/Twig/Tests/Fixtures/expressions/ternary_operator.test +18 -0
  373. library/twig/twig/test/Twig/Tests/Fixtures/expressions/ternary_operator_noelse.test +10 -0
  374. library/twig/twig/test/Twig/Tests/Fixtures/expressions/ternary_operator_nothen.test +10 -0
  375. library/twig/twig/test/Twig/Tests/Fixtures/expressions/two_word_operators_as_variables.test +8 -0
  376. library/twig/twig/test/Twig/Tests/Fixtures/expressions/unary.test +12 -0
  377. library/twig/twig/test/Twig/Tests/Fixtures/expressions/unary_macro_arguments.test +22 -0
  378. library/twig/twig/test/Twig/Tests/Fixtures/expressions/unary_precedence.test +14 -0
  379. library/twig/twig/test/Twig/Tests/Fixtures/filters/abs.test +30 -0
  380. library/twig/twig/test/Twig/Tests/Fixtures/filters/batch.test +31 -0
  381. library/twig/twig/test/Twig/Tests/Fixtures/filters/batch_float.test +29 -0
  382. library/twig/twig/test/Twig/Tests/Fixtures/filters/batch_with_empty_fill.test +37 -0
  383. library/twig/twig/test/Twig/Tests/Fixtures/filters/batch_with_exact_elements.test +33 -0
  384. library/twig/twig/test/Twig/Tests/Fixtures/filters/batch_with_fill.test +37 -0
  385. library/twig/twig/test/Twig/Tests/Fixtures/filters/batch_with_keys.test +10 -0
  386. library/twig/twig/test/Twig/Tests/Fixtures/filters/batch_with_zero_elements.test +10 -0
  387. library/twig/twig/test/Twig/Tests/Fixtures/filters/convert_encoding.test +10 -0
  388. library/twig/twig/test/Twig/Tests/Fixtures/filters/date.test +90 -0
  389. library/twig/twig/test/Twig/Tests/Fixtures/filters/date_default_format.test +14 -0
  390. library/twig/twig/test/Twig/Tests/Fixtures/filters/date_default_format_interval.test +16 -0
  391. library/twig/twig/test/Twig/Tests/Fixtures/filters/date_immutable.test +37 -0
  392. library/twig/twig/test/Twig/Tests/Fixtures/filters/date_interval.test +19 -0
  393. library/twig/twig/test/Twig/Tests/Fixtures/filters/date_modify.test +14 -0
  394. library/twig/twig/test/Twig/Tests/Fixtures/filters/date_namedargs.test +13 -0
  395. library/twig/twig/test/Twig/Tests/Fixtures/filters/default.test +150 -0
  396. library/twig/twig/test/Twig/Tests/Fixtures/filters/dynamic_filter.test +10 -0
  397. library/twig/twig/test/Twig/Tests/Fixtures/filters/escape.test +8 -0
  398. library/twig/twig/test/Twig/Tests/Fixtures/filters/escape_html_attr.test +8 -0
  399. library/twig/twig/test/Twig/Tests/Fixtures/filters/escape_non_supported_charset.test +8 -0
  400. library/twig/twig/test/Twig/Tests/Fixtures/filters/first.test +17 -0
  401. library/twig/twig/test/Twig/Tests/Fixtures/filters/force_escape.test +18 -0
  402. library/twig/twig/test/Twig/Tests/Fixtures/filters/format.test +8 -0
  403. library/twig/twig/test/Twig/Tests/Fixtures/filters/join.test +12 -0
  404. library/twig/twig/test/Twig/Tests/Fixtures/filters/json_encode.test +12 -0
  405. library/twig/twig/test/Twig/Tests/Fixtures/filters/last.test +17 -0
  406. library/twig/twig/test/Twig/Tests/Fixtures/filters/length.test +14 -0
  407. library/twig/twig/test/Twig/Tests/Fixtures/filters/length_utf8.test +12 -0
  408. library/twig/twig/test/Twig/Tests/Fixtures/filters/merge.test +18 -0
  409. library/twig/twig/test/Twig/Tests/Fixtures/filters/nl2br.test +14 -0
  410. library/twig/twig/test/Twig/Tests/Fixtures/filters/number_format.test +18 -0
  411. library/twig/twig/test/Twig/Tests/Fixtures/filters/number_format_default.test +21 -0
  412. library/twig/twig/test/Twig/Tests/Fixtures/filters/replace.test +12 -0
  413. library/twig/twig/test/Twig/Tests/Fixtures/filters/replace_invalid_arg.test +8 -0
  414. library/twig/twig/test/Twig/Tests/Fixtures/filters/reverse.test +18 -0
  415. library/twig/twig/test/Twig/Tests/Fixtures/filters/round.test +22 -0
  416. library/twig/twig/test/Twig/Tests/Fixtures/filters/slice.test +54 -0
  417. library/twig/twig/test/Twig/Tests/Fixtures/filters/sort.test +12 -0
  418. library/twig/twig/test/Twig/Tests/Fixtures/filters/special_chars.test +8 -0
  419. library/twig/twig/test/Twig/Tests/Fixtures/filters/split.test +20 -0
  420. library/twig/twig/test/Twig/Tests/Fixtures/filters/split_utf8.test +24 -0
  421. library/twig/twig/test/Twig/Tests/Fixtures/filters/static_calls.test +10 -0
  422. library/twig/twig/test/Twig/Tests/Fixtures/filters/trim.test +12 -0
  423. library/twig/twig/test/Twig/Tests/Fixtures/filters/urlencode.test +16 -0
  424. library/twig/twig/test/Twig/Tests/Fixtures/filters/urlencode_deprecated.test +16 -0
  425. library/twig/twig/test/Twig/Tests/Fixtures/functions/attribute.test +18 -0
  426. library/twig/twig/test/Twig/Tests/Fixtures/functions/block.test +12 -0
  427. library/twig/twig/test/Twig/Tests/Fixtures/functions/block_with_template.test +22 -0
  428. library/twig/twig/test/Twig/Tests/Fixtures/functions/block_without_name.test +12 -0
  429. library/twig/twig/test/Twig/Tests/Fixtures/functions/constant.test +10 -0
  430. library/twig/twig/test/Twig/Tests/Fixtures/functions/cycle.test +16 -0
  431. library/twig/twig/test/Twig/Tests/Fixtures/functions/date.test +25 -0
  432. library/twig/twig/test/Twig/Tests/Fixtures/functions/date_namedargs.test +11 -0
  433. library/twig/twig/test/Twig/Tests/Fixtures/functions/dump.test +16 -0
  434. library/twig/twig/test/Twig/Tests/Fixtures/functions/dump_array.test +19 -0
  435. library/twig/twig/test/Twig/Tests/Fixtures/functions/dynamic_function.test +10 -0
  436. library/twig/twig/test/Twig/Tests/Fixtures/functions/include/assignment.test +13 -0
  437. library/twig/twig/test/Twig/Tests/Fixtures/functions/include/autoescaping.test +10 -0
  438. library/twig/twig/test/Twig/Tests/Fixtures/functions/include/basic.test +17 -0
  439. library/twig/twig/test/Twig/Tests/Fixtures/functions/include/expression.test +17 -0
  440. library/twig/twig/test/Twig/Tests/Fixtures/functions/include/ignore_missing.test +10 -0
  441. library/twig/twig/test/Twig/Tests/Fixtures/functions/include/missing.test +8 -0
  442. library/twig/twig/test/Twig/Tests/Fixtures/functions/include/missing_nested.test +16 -0
  443. library/twig/twig/test/Twig/Tests/Fixtures/functions/include/sandbox.test +13 -0
  444. library/twig/twig/test/Twig/Tests/Fixtures/functions/include/sandbox_disabling.test +16 -0
  445. library/twig/twig/test/Twig/Tests/Fixtures/functions/include/sandbox_disabling_ignore_missing.test +13 -0
  446. library/twig/twig/test/Twig/Tests/Fixtures/functions/include/template_instance.test +10 -0
  447. library/twig/twig/test/Twig/Tests/Fixtures/functions/include/templates_as_array.test +12 -0
  448. library/twig/twig/test/Twig/Tests/Fixtures/functions/include/with_context.test +16 -0
  449. library/twig/twig/test/Twig/Tests/Fixtures/functions/include/with_variables.test +12 -0
  450. library/twig/twig/test/Twig/Tests/Fixtures/functions/magic_call.test +8 -0
  451. library/twig/twig/test/Twig/Tests/Fixtures/functions/magic_call53.test +12 -0
  452. library/twig/twig/test/Twig/Tests/Fixtures/functions/max.test +12 -0
  453. library/twig/twig/test/Twig/Tests/Fixtures/functions/min.test +12 -0
  454. library/twig/twig/test/Twig/Tests/Fixtures/functions/range.test +8 -0
  455. library/twig/twig/test/Twig/Tests/Fixtures/functions/recursive_block_with_inheritance.test +21 -0
  456. library/twig/twig/test/Twig/Tests/Fixtures/functions/source.test +17 -0
  457. library/twig/twig/test/Twig/Tests/Fixtures/functions/special_chars.test +8 -0
  458. library/twig/twig/test/Twig/Tests/Fixtures/functions/static_calls.test +10 -0
  459. library/twig/twig/test/Twig/Tests/Fixtures/functions/template_from_string.test +15 -0
  460. library/twig/twig/test/Twig/Tests/Fixtures/macros/default_values.test +16 -0
  461. library/twig/twig/test/Twig/Tests/Fixtures/macros/nested_calls.test +18 -0
  462. library/twig/twig/test/Twig/Tests/Fixtures/macros/reserved_variables.test +14 -0
  463. library/twig/twig/test/Twig/Tests/Fixtures/macros/simple.test +22 -0
  464. library/twig/twig/test/Twig/Tests/Fixtures/macros/varargs.test +21 -0
  465. library/twig/twig/test/Twig/Tests/Fixtures/macros/varargs_argument.test +7 -0
  466. library/twig/twig/test/Twig/Tests/Fixtures/macros/with_filters.test +14 -0
  467. library/twig/twig/test/Twig/Tests/Fixtures/regression/combined_debug_info.test +15 -0
  468. library/twig/twig/test/Twig/Tests/Fixtures/regression/empty_token.test +8 -0
  469. library/twig/twig/test/Twig/Tests/Fixtures/regression/issue_1143.test +23 -0
  470. library/twig/twig/test/Twig/Tests/Fixtures/regression/multi_word_tests.test +10 -0
  471. library/twig/twig/test/Twig/Tests/Fixtures/regression/simple_xml_element.test +19 -0
  472. library/twig/twig/test/Twig/Tests/Fixtures/regression/strings_like_numbers.test +8 -0
  473. library/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/basic.test +26 -0
  474. library/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/blocks.test +12 -0
  475. library/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/double_escaping.test +10 -0
  476. library/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/functions.test +83 -0
  477. library/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/literal.test +45 -0
  478. library/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/nested.test +26 -0
  479. library/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/objects.test +26 -0
  480. library/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/raw.test +10 -0
  481. library/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/strategy.legacy.test +11 -0
  482. library/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/strategy.test +11 -0
  483. library/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/type.test +69 -0
  484. library/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/with_filters.test +131 -0
  485. library/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/with_filters_arguments.test +23 -0
  486. library/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/with_pre_escape_filters.test +68 -0
  487. library/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/with_preserves_safety_filters.test +50 -0
  488. library/twig/twig/test/Twig/Tests/Fixtures/tags/block/basic.test +11 -0
  489. library/twig/twig/test/Twig/Tests/Fixtures/tags/block/block_unique_name.test +11 -0
  490. library/twig/twig/test/Twig/Tests/Fixtures/tags/block/special_chars.test +10 -0
  491. library/twig/twig/test/Twig/Tests/Fixtures/tags/embed/basic.test +35 -0
  492. library/twig/twig/test/Twig/Tests/Fixtures/tags/embed/complex_dynamic_parent.test +35 -0
  493. library/twig/twig/test/Twig/Tests/Fixtures/tags/embed/dynamic_parent.test +35 -0
  494. library/twig/twig/test/Twig/Tests/Fixtures/tags/embed/error_line.test +16 -0
  495. library/twig/twig/test/Twig/Tests/Fixtures/tags/embed/multiple.test +50 -0
  496. library/twig/twig/test/Twig/Tests/Fixtures/tags/embed/nested.test +42 -0
  497. library/twig/twig/test/Twig/Tests/Fixtures/tags/embed/with_extends.test +60 -0
  498. library/twig/twig/test/Twig/Tests/Fixtures/tags/filter/basic.test +10 -0
  499. library/twig/twig/test/Twig/Tests/Fixtures/tags/filter/json_encode.test +8 -0
  500. library/twig/twig/test/Twig/Tests/Fixtures/tags/filter/multiple.test +10 -0
  501. library/twig/twig/test/Twig/Tests/Fixtures/tags/filter/nested.test +16 -0
  502. library/twig/twig/test/Twig/Tests/Fixtures/tags/filter/with_for_tag.test +13 -0
  503. library/twig/twig/test/Twig/Tests/Fixtures/tags/filter/with_if_tag.test +29 -0
  504. library/twig/twig/test/Twig/Tests/Fixtures/tags/for/condition.test +14 -0
  505. library/twig/twig/test/Twig/Tests/Fixtures/tags/for/context.test +18 -0
  506. library/twig/twig/test/Twig/Tests/Fixtures/tags/for/else.test +23 -0
  507. library/twig/twig/test/Twig/Tests/Fixtures/tags/for/inner_variables.test +17 -0
  508. library/twig/twig/test/Twig/Tests/Fixtures/tags/for/keys.test +11 -0
  509. library/twig/twig/test/Twig/Tests/Fixtures/tags/for/keys_and_values.test +11 -0
  510. library/twig/twig/test/Twig/Tests/Fixtures/tags/for/loop_context.test +19 -0
  511. library/twig/twig/test/Twig/Tests/Fixtures/tags/for/loop_context_local.test +10 -0
  512. library/twig/twig/test/Twig/Tests/Fixtures/tags/for/loop_not_defined.test +10 -0
  513. library/twig/twig/test/Twig/Tests/Fixtures/tags/for/loop_not_defined_cond.test +9 -0
  514. library/twig/twig/test/Twig/Tests/Fixtures/tags/for/nested_else.test +17 -0
  515. library/twig/twig/test/Twig/Tests/Fixtures/tags/for/objects.test +43 -0
  516. library/twig/twig/test/Twig/Tests/Fixtures/tags/for/objects_countable.test +47 -0
  517. library/twig/twig/test/Twig/Tests/Fixtures/tags/for/recursive.test +18 -0
  518. library/twig/twig/test/Twig/Tests/Fixtures/tags/for/values.test +11 -0
  519. library/twig/twig/test/Twig/Tests/Fixtures/tags/from.test +14 -0
  520. library/twig/twig/test/Twig/Tests/Fixtures/tags/if/basic.test +22 -0
  521. library/twig/twig/test/Twig/Tests/Fixtures/tags/if/expression.test +22 -0
  522. library/twig/twig/test/Twig/Tests/Fixtures/tags/include/basic.test +16 -0
  523. library/twig/twig/test/Twig/Tests/Fixtures/tags/include/expression.test +16 -0
  524. library/twig/twig/test/Twig/Tests/Fixtures/tags/include/ignore_missing.test +10 -0
  525. library/twig/twig/test/Twig/Tests/Fixtures/tags/include/missing.test +8 -0
  526. library/twig/twig/test/Twig/Tests/Fixtures/tags/include/missing_nested.test +16 -0
  527. library/twig/twig/test/Twig/Tests/Fixtures/tags/include/only.test +16 -0
  528. library/twig/twig/test/Twig/Tests/Fixtures/tags/include/template_instance.test +10 -0
  529. library/twig/twig/test/Twig/Tests/Fixtures/tags/include/templates_as_array.test +12 -0
  530. library/twig/twig/test/Twig/Tests/Fixtures/tags/include/with_variables.test +12 -0
  531. library/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/basic.test +14 -0
  532. library/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/block_expr.test +32 -0
  533. library/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/block_expr2.test +34 -0
  534. library/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/conditional.test +14 -0
  535. library/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/dynamic.test +14 -0
  536. library/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/empty.test +10 -0
  537. library/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/extends_as_array.test +12 -0
  538. library/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/extends_as_array_with_empty_name.test +12 -0
  539. library/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/extends_as_array_with_null_name.test +12 -0
  540. library/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/multiple.test +12 -0
  541. library/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/multiple_dynamic.test +22 -0
  542. library/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/nested_blocks.test +22 -0
  543. library/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/nested_blocks_parent_only.test +15 -0
  544. library/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/nested_inheritance.test +16 -0
  545. library/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/parent.test +12 -0
  546. library/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/parent_change.test +16 -0
  547. library/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/parent_in_a_block.test +8 -0
  548. library/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/parent_isolation.test +20 -0
  549. library/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/parent_nested.test +28 -0
  550. library/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/parent_without_extends.test +8 -0
  551. library/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/parent_without_extends_but_traits.test +14 -0
  552. library/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/template_instance.test +14 -0
  553. library/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/use.test +44 -0
  554. library/twig/twig/test/Twig/Tests/Fixtures/tags/macro/basic.test +17 -0
  555. library/twig/twig/test/Twig/Tests/Fixtures/tags/macro/endmacro_name.test +16 -0
  556. library/twig/twig/test/Twig/Tests/Fixtures/tags/macro/external.test +17 -0
  557. library/twig/twig/test/Twig/Tests/Fixtures/tags/macro/from.test +18 -0
  558. library/twig/twig/test/Twig/Tests/Fixtures/tags/macro/from_with_reserved_name.test +9 -0
  559. library/twig/twig/test/Twig/Tests/Fixtures/tags/macro/global.test +14 -0
  560. library/twig/twig/test/Twig/Tests/Fixtures/tags/macro/import_with_reserved_nam.test +11 -0
  561. library/twig/twig/test/Twig/Tests/Fixtures/tags/macro/reserved_name.test +10 -0
  562. library/twig/twig/test/Twig/Tests/Fixtures/tags/macro/self_import.test +17 -0
  563. library/twig/twig/test/Twig/Tests/Fixtures/tags/macro/special_chars.test +14 -0
  564. library/twig/twig/test/Twig/Tests/Fixtures/tags/macro/super_globals.test +14 -0
  565. library/twig/twig/test/Twig/Tests/Fixtures/tags/raw/basic.legacy.test +10 -0
  566. library/twig/twig/test/Twig/Tests/Fixtures/tags/raw/mixed_usage_with_raw.legacy.test +10 -0
  567. library/twig/twig/test/Twig/Tests/Fixtures/tags/raw/whitespace_control.legacy.test +56 -0
  568. library/twig/twig/test/Twig/Tests/Fixtures/tags/sandbox/not_valid1.test +11 -0
  569. library/twig/twig/test/Twig/Tests/Fixtures/tags/sandbox/not_valid2.test +14 -0
  570. library/twig/twig/test/Twig/Tests/Fixtures/tags/sandbox/simple.test +22 -0
  571. library/twig/twig/test/Twig/Tests/Fixtures/tags/set/basic.test +20 -0
  572. library/twig/twig/test/Twig/Tests/Fixtures/tags/set/capture-empty.test +9 -0
  573. library/twig/twig/test/Twig/Tests/Fixtures/tags/set/capture.test +10 -0
  574. library/twig/twig/test/Twig/Tests/Fixtures/tags/set/expression.test +12 -0
  575. library/twig/twig/test/Twig/Tests/Fixtures/tags/spaceless/simple.test +12 -0
  576. library/twig/twig/test/Twig/Tests/Fixtures/tags/special_chars.test +8 -0
  577. library/twig/twig/test/Twig/Tests/Fixtures/tags/trim_block.test +74 -0
  578. library/twig/twig/test/Twig/Tests/Fixtures/tags/use/aliases.test +12 -0
  579. library/twig/twig/test/Twig/Tests/Fixtures/tags/use/basic.test +12 -0
  580. library/twig/twig/test/Twig/Tests/Fixtures/tags/use/deep.test +22 -0
  581. library/twig/twig/test/Twig/Tests/Fixtures/tags/use/deep_empty.test +10 -0
  582. library/twig/twig/test/Twig/Tests/Fixtures/tags/use/inheritance.test +25 -0
  583. library/twig/twig/test/Twig/Tests/Fixtures/tags/use/inheritance2.test +24 -0
  584. library/twig/twig/test/Twig/Tests/Fixtures/tags/use/multiple.test +21 -0
  585. library/twig/twig/test/Twig/Tests/Fixtures/tags/use/multiple_aliases.test +23 -0
  586. library/twig/twig/test/Twig/Tests/Fixtures/tags/use/parent_block.test +24 -0
  587. library/twig/twig/test/Twig/Tests/Fixtures/tags/use/parent_block2.test +24 -0
  588. library/twig/twig/test/Twig/Tests/Fixtures/tags/use/parent_block3.test +38 -0
  589. library/twig/twig/test/Twig/Tests/Fixtures/tags/verbatim/basic.test +10 -0
  590. library/twig/twig/test/Twig/Tests/Fixtures/tags/verbatim/mixed_usage_with_raw.test +10 -0
  591. library/twig/twig/test/Twig/Tests/Fixtures/tags/verbatim/whitespace_control.test +56 -0
  592. library/twig/twig/test/Twig/Tests/Fixtures/tags/with/basic.test +13 -0
  593. library/twig/twig/test/Twig/Tests/Fixtures/tags/with/expression.test +10 -0
  594. library/twig/twig/test/Twig/Tests/Fixtures/tags/with/nested.test +15 -0
  595. library/twig/twig/test/Twig/Tests/Fixtures/tags/with/with_no_hash.test +10 -0
  596. library/twig/twig/test/Twig/Tests/Fixtures/tags/with/with_only.test +10 -0
  597. library/twig/twig/test/Twig/Tests/Fixtures/tests/array.test +24 -0
  598. library/twig/twig/test/Twig/Tests/Fixtures/tests/constant.test +14 -0
  599. library/twig/twig/test/Twig/Tests/Fixtures/tests/defined.test +129 -0
  600. library/twig/twig/test/Twig/Tests/Fixtures/tests/defined_for_attribute.test +35 -0
  601. library/twig/twig/test/Twig/Tests/Fixtures/tests/defined_for_blocks.test +38 -0
  602. library/twig/twig/test/Twig/Tests/Fixtures/tests/defined_for_blocks_with_template.test +17 -0
  603. library/twig/twig/test/Twig/Tests/Fixtures/tests/defined_for_constants.test +14 -0
  604. library/twig/twig/test/Twig/Tests/Fixtures/tests/empty.test +45 -0
  605. library/twig/twig/test/Twig/Tests/Fixtures/tests/even.test +14 -0
  606. library/twig/twig/test/Twig/Tests/Fixtures/tests/in.test +128 -0
  607. library/twig/twig/test/Twig/Tests/Fixtures/tests/in_with_objects.test +19 -0
  608. library/twig/twig/test/Twig/Tests/Fixtures/tests/iterable.test +19 -0
  609. library/twig/twig/test/Twig/Tests/Fixtures/tests/null_coalesce.test +30 -0
  610. library/twig/twig/test/Twig/Tests/Fixtures/tests/odd.test +10 -0
  611. library/twig/twig/test/Twig/Tests/IntegrationTest.php +254 -0
  612. library/twig/twig/test/Twig/Tests/LegacyFixtures/autoescape/filename.legacy.test +18 -0
  613. library/twig/twig/test/Twig/Tests/LegacyFixtures/functions/undefined_block.legacy.test +12 -0
  614. library/twig/twig/test/Twig/Tests/LegacyFixtures/test.legacy.test +8 -0
  615. library/twig/twig/test/Twig/Tests/LegacyIntegrationTest.php +54 -0
  616. library/twig/twig/test/Twig/Tests/LexerTest.php +311 -0
  617. library/twig/twig/test/Twig/Tests/Loader/ArrayTest.php +111 -0
  618. library/twig/twig/test/Twig/Tests/Loader/ChainTest.php +124 -0
  619. library/twig/twig/test/Twig/Tests/Loader/FilesystemTest.php +226 -0
  620. library/twig/twig/test/Twig/Tests/Loader/Fixtures/inheritance/array_inheritance_empty_parent.html.twig +3 -0
  621. library/twig/twig/test/Twig/Tests/Loader/Fixtures/inheritance/array_inheritance_nonexistent_parent.html.twig +3 -0
  622. library/twig/twig/test/Twig/Tests/Loader/Fixtures/inheritance/array_inheritance_null_parent.html.twig +3 -0
  623. library/twig/twig/test/Twig/Tests/Loader/Fixtures/inheritance/array_inheritance_valid_parent.html.twig +3 -0
  624. library/twig/twig/test/Twig/Tests/Loader/Fixtures/inheritance/parent.html.twig +1 -0
  625. library/twig/twig/test/Twig/Tests/Loader/Fixtures/inheritance/spare_parent.html.twig +1 -0
  626. library/twig/twig/test/Twig/Tests/Loader/Fixtures/named/index.html +1 -0
  627. library/twig/twig/test/Twig/Tests/Loader/Fixtures/named_bis/index.html +1 -0
  628. library/twig/twig/test/Twig/Tests/Loader/Fixtures/named_final/index.html +1 -0
  629. library/twig/twig/test/Twig/Tests/Loader/Fixtures/named_quater/named_absolute.html +1 -0
  630. library/twig/twig/test/Twig/Tests/Loader/Fixtures/named_ter/index.html +1 -0
  631. library/twig/twig/test/Twig/Tests/Loader/Fixtures/normal/index.html +1 -0
  632. library/twig/twig/test/Twig/Tests/Loader/Fixtures/normal_bis/index.html +1 -0
  633. library/twig/twig/test/Twig/Tests/Loader/Fixtures/normal_final/index.html +1 -0
  634. library/twig/twig/test/Twig/Tests/Loader/Fixtures/normal_ter/index.html +1 -0
  635. library/twig/twig/test/Twig/Tests/Loader/Fixtures/phar/phar-sample.phar +0 -0
  636. library/twig/twig/test/Twig/Tests/Loader/Fixtures/themes/theme1/blocks.html.twig +3 -0
  637. library/twig/twig/test/Twig/Tests/Loader/Fixtures/themes/theme2/blocks.html.twig +3 -0
  638. library/twig/twig/test/Twig/Tests/NativeExtensionTest.php +36 -0
  639. library/twig/twig/test/Twig/Tests/Node/AutoEscapeTest.php +32 -0
  640. library/twig/twig/test/Twig/Tests/Node/BlockReferenceTest.php +31 -0
  641. library/twig/twig/test/Twig/Tests/Node/BlockTest.php +39 -0
  642. library/twig/twig/test/Twig/Tests/Node/DoTest.php +32 -0
  643. library/twig/twig/test/Twig/Tests/Node/Expression/ArrayTest.php +37 -0
  644. library/twig/twig/test/Twig/Tests/Node/Expression/AssignNameTest.php +29 -0
  645. library/twig/twig/test/Twig/Tests/Node/Expression/Binary/AddTest.php +34 -0
  646. library/twig/twig/test/Twig/Tests/Node/Expression/Binary/AndTest.php +34 -0
  647. library/twig/twig/test/Twig/Tests/Node/Expression/Binary/ConcatTest.php +34 -0
  648. library/twig/twig/test/Twig/Tests/Node/Expression/Binary/DivTest.php +34 -0
  649. library/twig/twig/test/Twig/Tests/Node/Expression/Binary/FloorDivTest.php +34 -0
  650. library/twig/twig/test/Twig/Tests/Node/Expression/Binary/ModTest.php +34 -0
  651. library/twig/twig/test/Twig/Tests/Node/Expression/Binary/MulTest.php +34 -0
  652. library/twig/twig/test/Twig/Tests/Node/Expression/Binary/OrTest.php +34 -0
  653. library/twig/twig/test/Twig/Tests/Node/Expression/Binary/SubTest.php +34 -0
  654. library/twig/twig/test/Twig/Tests/Node/Expression/CallTest.php +147 -0
  655. library/twig/twig/test/Twig/Tests/Node/Expression/ConditionalTest.php +38 -0
  656. library/twig/twig/test/Twig/Tests/Node/Expression/ConstantTest.php +30 -0
  657. library/twig/twig/test/Twig/Tests/Node/Expression/FilterTest.php +154 -0
  658. library/twig/twig/test/Twig/Tests/Node/Expression/FunctionTest.php +110 -0
  659. library/twig/twig/test/Twig/Tests/Node/Expression/GetAttrTest.php +50 -0
  660. library/twig/twig/test/Twig/Tests/Node/Expression/NameTest.php +43 -0
  661. library/twig/twig/test/Twig/Tests/Node/Expression/NullCoalesceTest.php +31 -0
  662. library/twig/twig/test/Twig/Tests/Node/Expression/PHP53/FilterInclude.php +6 -0
  663. library/twig/twig/test/Twig/Tests/Node/Expression/PHP53/FunctionInclude.php +6 -0
  664. library/twig/twig/test/Twig/Tests/Node/Expression/PHP53/TestInclude.php +6 -0
  665. library/twig/twig/test/Twig/Tests/Node/Expression/ParentTest.php +28 -0
  666. library/twig/twig/test/Twig/Tests/Node/Expression/TestTest.php +82 -0
  667. library/twig/twig/test/Twig/Tests/Node/Expression/Unary/NegTest.php +32 -0
  668. library/twig/twig/test/Twig/Tests/Node/Expression/Unary/NotTest.php +31 -0
  669. library/twig/twig/test/Twig/Tests/Node/Expression/Unary/PosTest.php +31 -0
  670. library/twig/twig/test/Twig/Tests/Node/ForTest.php +191 -0
  671. library/twig/twig/test/Twig/Tests/Node/IfTest.php +88 -0
  672. library/twig/twig/test/Twig/Tests/Node/ImportTest.php +40 -0
  673. library/twig/twig/test/Twig/Tests/Node/IncludeTest.php +83 -0
  674. library/twig/twig/test/Twig/Tests/Node/MacroTest.php +74 -0
  675. library/twig/twig/test/Twig/Tests/Node/ModuleTest.php +223 -0
  676. library/twig/twig/test/Twig/Tests/Node/PrintTest.php +29 -0
  677. library/twig/twig/test/Twig/Tests/Node/SandboxTest.php +44 -0
  678. library/twig/twig/test/Twig/Tests/Node/SandboxedPrintTest.php +33 -0
  679. library/twig/twig/test/Twig/Tests/Node/SetTest.php +69 -0
  680. library/twig/twig/test/Twig/Tests/Node/SpacelessTest.php +37 -0
  681. library/twig/twig/test/Twig/Tests/Node/TextTest.php +28 -0
  682. library/twig/twig/test/Twig/Tests/NodeVisitor/OptimizerTest.php +124 -0
  683. library/twig/twig/test/Twig/Tests/ParserTest.php +196 -0
  684. library/twig/twig/test/Twig/Tests/Profiler/Dumper/AbstractTest.php +101 -0
  685. library/twig/twig/test/Twig/Tests/Profiler/Dumper/BlackfireTest.php +32 -0
  686. library/twig/twig/test/Twig/Tests/Profiler/Dumper/HtmlTest.php +30 -0
  687. library/twig/twig/test/Twig/Tests/Profiler/Dumper/TextTest.php +30 -0
  688. library/twig/twig/test/Twig/Tests/Profiler/ProfileTest.php +100 -0
  689. library/twig/twig/test/Twig/Tests/RuntimeFactoryLoaderTest.php +32 -0
  690. library/twig/twig/test/Twig/Tests/TemplateTest.php +231 -0
application/models/helper/condition/layouts/compatible.php CHANGED
@@ -21,16 +21,20 @@ class Types_Helper_Condition_Layouts_Compatible extends Types_Helper_Condition_T
21
 
22
  public function valid() {
23
  // theme + theme integration running
24
- if( defined( 'LAYOUTS_INTEGRATION_THEME_NAME' ) )
25
  return true;
 
26
 
27
  $filesystem = new Toolset_Filesystem_File();
28
- foreach( $this->templates as $name => $file ) {
29
  // file exists
30
- if( $filesystem->open( get_stylesheet_directory() . '/' . $file ) ) {
 
 
31
  // supports layouts
32
- if( $filesystem->search( 'the_ddlayout') )
33
  return true;
 
34
 
35
  // if for example single.php exists and it does not support Layouts we don't need to look at index.php
36
  return false;
21
 
22
  public function valid() {
23
  // theme + theme integration running
24
+ if ( defined( 'LAYOUTS_INTEGRATION_THEME_NAME' ) ) {
25
  return true;
26
+ }
27
 
28
  $filesystem = new Toolset_Filesystem_File();
29
+ foreach ( $this->templates as $name => $file ) {
30
  // file exists
31
+ if ( $filesystem->open( get_template_directory() . '/' . $file )
32
+ || $filesystem->open( get_stylesheet_directory() . '/' . $file )
33
+ ) {
34
  // supports layouts
35
+ if ( $filesystem->search( 'the_ddlayout' ) ) {
36
  return true;
37
+ }
38
 
39
  // if for example single.php exists and it does not support Layouts we don't need to look at index.php
40
  return false;
application/models/wpml/field_group.php CHANGED
@@ -32,7 +32,8 @@ class Types_Wpml_Field_Group implements Types_Wpml_Interface {
32
  *
33
  * @param Types_Field_Group $group
34
  */
35
- public function __construct( Types_Field_Group $group ) {
 
36
  $this->group = $group;
37
 
38
  // todo get rid of these hard dependencies
32
  *
33
  * @param Types_Field_Group $group
34
  */
35
+ public function __construct( $group ) {
36
+
37
  $this->group = $group;
38
 
39
  // todo get rid of these hard dependencies
disabled_autoload_classmap.php ADDED
@@ -0,0 +1,151 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ // Generated by ZF2's ./bin/classmap_generator.php
3
+ return array(
4
+ 'Types_Api' => TYPES_ABSPATH . '/application/api.php',
5
+ 'Types_Admin' => TYPES_ABSPATH . '/application/controllers/admin.php',
6
+ 'Types_Admin_Menu' => TYPES_ABSPATH . '/application/controllers/admin_menu.php',
7
+ 'Types_Ajax_Handler_Abstract' => TYPES_ABSPATH . '/application/controllers/ajax/handler/abstract.php',
8
+ 'Types_Ajax_Handler_Check_Slug_Conflicts' => TYPES_ABSPATH . '/application/controllers/ajax/handler/check_slug_conflicts.php',
9
+ 'Types_Ajax_Handler_Field_Control_Action' => TYPES_ABSPATH . '/application/controllers/ajax/handler/field_control_action.php',
10
+ 'Types_Ajax_Handler_Settings_Action' => TYPES_ABSPATH . '/application/controllers/ajax/handler/settings_action.php',
11
+ 'Types_Ajax_Handler_Interface' => TYPES_ABSPATH . '/application/controllers/ajax/handler_interface.php',
12
+ 'Types_Ajax' => TYPES_ABSPATH . '/application/controllers/ajax.php',
13
+ 'Types_Asset_Help_Tab_Loader' => TYPES_ABSPATH . '/application/controllers/asset/help_tab_loader.php',
14
+ 'Types_Asset_Manager' => TYPES_ABSPATH . '/application/controllers/asset/manager.php',
15
+ 'Types_Assets' => TYPES_ABSPATH . '/application/controllers/assets.php',
16
+ 'Types_Dialog_Box' => TYPES_ABSPATH . '/application/controllers/dialog_box.php',
17
+ 'Types_Embedded' => TYPES_ABSPATH . '/application/controllers/embedded.php',
18
+ 'Types_Field_Type_Converter' => TYPES_ABSPATH . '/application/controllers/field/type_converter.php',
19
+ 'Types_Field_Utils' => TYPES_ABSPATH . '/application/controllers/field/utils.php',
20
+ 'Types_Frontend' => TYPES_ABSPATH . '/application/controllers/frontend.php',
21
+ 'Types_Import_Export' => TYPES_ABSPATH . '/application/controllers/import_export.php',
22
+ 'Types_Information_Controller' => TYPES_ABSPATH . '/application/controllers/information/controller.php',
23
+ 'Types_Main' => TYPES_ABSPATH . '/application/controllers/main.php',
24
+ 'Types_Page_Abstract' => TYPES_ABSPATH . '/application/controllers/page/abstract.php',
25
+ 'Types_Page_Dashboard' => TYPES_ABSPATH . '/application/controllers/page/dashboard.php',
26
+ 'Types_Page_Extension_Edit_Post' => TYPES_ABSPATH . '/application/controllers/page/extension/edit_post.php',
27
+ 'Types_Page_Extension_Edit_Post_Fields' => TYPES_ABSPATH . '/application/controllers/page/extension/edit_post_fields.php',
28
+ 'Types_Page_Extension_Edit_Post_Type' => TYPES_ABSPATH . '/application/controllers/page/extension/edit_post_type.php',
29
+ 'Types_Page_Extension_Settings' => TYPES_ABSPATH . '/application/controllers/page/extension/settings.php',
30
+ 'Types_Page_Field_Control' => TYPES_ABSPATH . '/application/controllers/page/field_control.php',
31
+ 'Types_Page_Hidden_Helper' => TYPES_ABSPATH . '/application/controllers/page/hidden/helper.php',
32
+ 'Types_Twig_Autoloader' => TYPES_ABSPATH . '/application/controllers/twig_autoloader.php',
33
+ 'Types_Upgrade' => TYPES_ABSPATH . '/application/controllers/upgrade.php',
34
+ 'Types_Utils' => TYPES_ABSPATH . '/application/controllers/utils.php',
35
+ 'Types_Api_Helper' => TYPES_ABSPATH . '/application/models/api/helper.php',
36
+ 'Types_Field_Group_Factory' => TYPES_ABSPATH . '/application/models/field/group/factory.php',
37
+ 'Types_Field_Group_Post' => TYPES_ABSPATH . '/application/models/field/group/post.php',
38
+ 'Types_Field_Group_Post_Factory' => TYPES_ABSPATH . '/application/models/field/group/post_factory.php',
39
+ 'Types_Field_Group_Term' => TYPES_ABSPATH . '/application/models/field/group/term.php',
40
+ 'Types_Field_Group_Term_Factory' => TYPES_ABSPATH . '/application/models/field/group/term_factory.php',
41
+ 'Types_Field_Group_User' => TYPES_ABSPATH . '/application/models/field/group/user.php',
42
+ 'Types_Field_Group_User_Factory' => TYPES_ABSPATH . '/application/models/field/group/user_factory.php',
43
+ 'Types_Field_Group' => TYPES_ABSPATH . '/application/models/field/group.php',
44
+ 'Types_Field_Type_Definition_Checkbox' => TYPES_ABSPATH . '/application/models/field/type/definition/checkbox.php',
45
+ 'Types_Field_Type_Definition_Checkboxes' => TYPES_ABSPATH . '/application/models/field/type/definition/checkboxes.php',
46
+ 'Types_Field_Type_Definition_Date' => TYPES_ABSPATH . '/application/models/field/type/definition/date.php',
47
+ 'Types_Field_Type_Definition_Numeric' => TYPES_ABSPATH . '/application/models/field/type/definition/numeric.php',
48
+ 'Types_Field_Type_Definition_Radio' => TYPES_ABSPATH . '/application/models/field/type/definition/radio.php',
49
+ 'Types_Field_Type_Definition_Select' => TYPES_ABSPATH . '/application/models/field/type/definition/select.php',
50
+ 'Types_Field_Type_Definition_Singular' => TYPES_ABSPATH . '/application/models/field/type/definition/singular.php',
51
+ 'Types_Field_Type_Definition' => TYPES_ABSPATH . '/application/models/field/type/definition.php',
52
+ 'Types_Field_Type_Definition_Factory' => TYPES_ABSPATH . '/application/models/field/type/definition_factory.php',
53
+ 'Types_Helper_Condition_Archive_Exists' => TYPES_ABSPATH . '/application/models/helper/condition/archive/exists.php',
54
+ 'Types_Helper_Condition_Archive_Has_Fields' => TYPES_ABSPATH . '/application/models/helper/condition/archive/has_fields.php',
55
+ 'Types_Helper_Condition_Archive_Missing' => TYPES_ABSPATH . '/application/models/helper/condition/archive/missing.php',
56
+ 'Types_Helper_Condition_Archive_No_Fields' => TYPES_ABSPATH . '/application/models/helper/condition/archive/no_fields.php',
57
+ 'Types_Helper_Condition_Archive_No_Support' => TYPES_ABSPATH . '/application/models/helper/condition/archive/no_support.php',
58
+ 'Types_Helper_Condition_Archive_Support' => TYPES_ABSPATH . '/application/models/helper/condition/archive/support.php',
59
+ 'Types_Helper_Condition_Cred_Active' => TYPES_ABSPATH . '/application/models/helper/condition/cred/active.php',
60
+ 'Types_Helper_Condition_Cred_Forms_Exist' => TYPES_ABSPATH . '/application/models/helper/condition/cred/forms_exist.php',
61
+ 'Types_Helper_Condition_Cred_Forms_Missing' => TYPES_ABSPATH . '/application/models/helper/condition/cred/forms_missing.php',
62
+ 'Types_Helper_Condition_Cred_Missing' => TYPES_ABSPATH . '/application/models/helper/condition/cred/missing.php',
63
+ 'Types_Helper_Condition_Layouts_Active' => TYPES_ABSPATH . '/application/models/helper/condition/layouts/active.php',
64
+ 'Types_Helper_Condition_Layouts_Archive_Exists' => TYPES_ABSPATH . '/application/models/helper/condition/layouts/archive_exists.php',
65
+ 'Types_Helper_Condition_Layouts_Archive_Missing' => TYPES_ABSPATH . '/application/models/helper/condition/layouts/archive_missing.php',
66
+ 'Types_Helper_Condition_Layouts_Compatible' => TYPES_ABSPATH . '/application/models/helper/condition/layouts/compatible.php',
67
+ 'Types_Helper_Condition_Layouts_Missing' => TYPES_ABSPATH . '/application/models/helper/condition/layouts/missing.php',
68
+ 'Types_Helper_Condition_Layouts_Template_Exists' => TYPES_ABSPATH . '/application/models/helper/condition/layouts/template_exists.php',
69
+ 'Types_Helper_Condition_Layouts_Template_Missing' => TYPES_ABSPATH . '/application/models/helper/condition/layouts/template_missing.php',
70
+ 'Types_Helper_Condition_Screen' => TYPES_ABSPATH . '/application/models/helper/condition/screen.php',
71
+ 'Types_Helper_Condition_Single_Exists' => TYPES_ABSPATH . '/application/models/helper/condition/single/exists.php',
72
+ 'Types_Helper_Condition_Single_Has_Fields' => TYPES_ABSPATH . '/application/models/helper/condition/single/has_fields.php',
73
+ 'Types_Helper_Condition_Single_Missing' => TYPES_ABSPATH . '/application/models/helper/condition/single/missing.php',
74
+ 'Types_Helper_Condition_Single_No_Fields' => TYPES_ABSPATH . '/application/models/helper/condition/single/no_fields.php',
75
+ 'Types_Helper_Condition_Template' => TYPES_ABSPATH . '/application/models/helper/condition/template.php',
76
+ 'Types_Helper_Condition_Type_Fields_Assigned' => TYPES_ABSPATH . '/application/models/helper/condition/type/fields_assigned.php',
77
+ 'Types_Helper_Condition_Views_Active' => TYPES_ABSPATH . '/application/models/helper/condition/views/active.php',
78
+ 'Types_Helper_Condition_Views_Archive_Exists' => TYPES_ABSPATH . '/application/models/helper/condition/views/archive_exists.php',
79
+ 'Types_Helper_Condition_Views_Archive_Missing' => TYPES_ABSPATH . '/application/models/helper/condition/views/archive_missing.php',
80
+ 'Types_Helper_Condition_Views_Missing' => TYPES_ABSPATH . '/application/models/helper/condition/views/missing.php',
81
+ 'Types_Helper_Condition_Views_Template_Exists' => TYPES_ABSPATH . '/application/models/helper/condition/views/template_exists.php',
82
+ 'Types_Helper_Condition_Views_Template_Missing' => TYPES_ABSPATH . '/application/models/helper/condition/views/template_missing.php',
83
+ 'Types_Helper_Condition_Views_Views_Exist' => TYPES_ABSPATH . '/application/models/helper/condition/views/views_exist.php',
84
+ 'Types_Helper_Condition_Views_Views_Missing' => TYPES_ABSPATH . '/application/models/helper/condition/views/views_missing.php',
85
+ 'Types_Helper_Condition' => TYPES_ABSPATH . '/application/models/helper/condition.php',
86
+ 'Types_Helper_Create_Content_Template' => TYPES_ABSPATH . '/application/models/helper/create/content_template.php',
87
+ 'Types_Helper_Create_Form' => TYPES_ABSPATH . '/application/models/helper/create/form.php',
88
+ 'Types_Helper_Create_Layout' => TYPES_ABSPATH . '/application/models/helper/create/layout.php',
89
+ 'Types_Helper_Create_View' => TYPES_ABSPATH . '/application/models/helper/create/view.php',
90
+ 'Types_Helper_Create_Wordpress_Archive' => TYPES_ABSPATH . '/application/models/helper/create/wordpress_archive.php',
91
+ 'Types_Helper_Output_Interface' => TYPES_ABSPATH . '/application/models/helper/output/interface.php',
92
+ 'Types_Helper_Output_Meta_Box' => TYPES_ABSPATH . '/application/models/helper/output/meta_box.php',
93
+ 'Types_Helper_Placeholder' => TYPES_ABSPATH . '/application/models/helper/placeholder.php',
94
+ 'Types_Helper_Twig' => TYPES_ABSPATH . '/application/models/helper/twig.php',
95
+ 'Types_Helper_Url' => TYPES_ABSPATH . '/application/models/helper/url.php',
96
+ 'Types_Information_Container' => TYPES_ABSPATH . '/application/models/information/container.php',
97
+ 'Types_Information_Message_Post_Type' => TYPES_ABSPATH . '/application/models/information/message/post_type.php',
98
+ 'Types_Information_Message' => TYPES_ABSPATH . '/application/models/information/message.php',
99
+ 'Types_Information_Table' => TYPES_ABSPATH . '/application/models/information/table.php',
100
+ 'Types_Post_Type' => TYPES_ABSPATH . '/application/models/post_type.php',
101
+ 'Types_Setting_Boolean' => TYPES_ABSPATH . '/application/models/setting/boolean.php',
102
+ 'Types_Setting_Interface' => TYPES_ABSPATH . '/application/models/setting/interface.php',
103
+ 'Types_Setting_Option_Interface' => TYPES_ABSPATH . '/application/models/setting/option/interface.php',
104
+ 'Types_Setting_Option' => TYPES_ABSPATH . '/application/models/setting/option.php',
105
+ 'Types_Setting_Preset_Information_Table' => TYPES_ABSPATH . '/application/models/setting/preset/information_table.php',
106
+ 'Types_Setting' => TYPES_ABSPATH . '/application/models/setting.php',
107
+ 'Types_Taxonomy' => TYPES_ABSPATH . '/application/models/taxonomy.php',
108
+ 'Toolset_Autoloader' => TYPES_ABSPATH . '/library/toolset/autoloader/autoloader.php',
109
+ 'Toolset_Filesystem_Directory' => TYPES_ABSPATH . '/library/toolset/filesystem/directory.php',
110
+ 'Toolset_Filesystem_Exception' => TYPES_ABSPATH . '/library/toolset/filesystem/exception.php',
111
+ 'Toolset_Filesystem_File' => TYPES_ABSPATH . '/library/toolset/filesystem/file.php',
112
+ 'WPToolset_Forms_Bootstrap' => TYPES_ABSPATH . '/library/toolset/toolset-common/toolset-forms/bootstrap.php',
113
+ 'WPToolset_Field_Audio' => TYPES_ABSPATH . '/library/toolset/toolset-common/toolset-forms/classes/class.audio.php',
114
+ 'WPToolset_Field_Button' => TYPES_ABSPATH . '/library/toolset/toolset-common/toolset-forms/classes/class.button.php',
115
+ 'WPToolset_Field_Checkbox' => TYPES_ABSPATH . '/library/toolset/toolset-common/toolset-forms/classes/class.checkbox.php',
116
+ 'WPToolset_Field_Checkboxes' => TYPES_ABSPATH . '/library/toolset/toolset-common/toolset-forms/classes/class.checkboxes.php',
117
+ 'WPToolset_Field_Colorpicker' => TYPES_ABSPATH . '/library/toolset/toolset-common/toolset-forms/classes/class.colorpicker.php',
118
+ 'WPToolset_Forms_Conditional' => TYPES_ABSPATH . '/library/toolset/toolset-common/toolset-forms/classes/class.conditional.php',
119
+ 'WPToolset_Cred' => TYPES_ABSPATH . '/library/toolset/toolset-common/toolset-forms/classes/class.cred.php',
120
+ 'WPToolset_Field_Credaudio' => TYPES_ABSPATH . '/library/toolset/toolset-common/toolset-forms/classes/class.credaudio.php',
121
+ 'WPToolset_Field_Credfile' => TYPES_ABSPATH . '/library/toolset/toolset-common/toolset-forms/classes/class.credfile.php',
122
+ 'WPToolset_Field_Credimage' => TYPES_ABSPATH . '/library/toolset/toolset-common/toolset-forms/classes/class.credimage.php',
123
+ 'WPToolset_Field_Credvideo' => TYPES_ABSPATH . '/library/toolset/toolset-common/toolset-forms/classes/class.credvideo.php',
124
+ 'WPToolset_Field_Date' => TYPES_ABSPATH . '/library/toolset/toolset-common/toolset-forms/classes/class.date.php',
125
+ 'WPToolset_Field_Date_Scripts' => TYPES_ABSPATH . '/library/toolset/toolset-common/toolset-forms/classes/class.date.scripts.php',
126
+ 'WPToolset_Field_Email' => TYPES_ABSPATH . '/library/toolset/toolset-common/toolset-forms/classes/class.email.php',
127
+ 'WPToolset_Field_Embed' => TYPES_ABSPATH . '/library/toolset/toolset-common/toolset-forms/classes/class.embed.php',
128
+ 'WPToolset_Field_File' => TYPES_ABSPATH . '/library/toolset/toolset-common/toolset-forms/classes/class.file.php',
129
+ 'WPToolset_Field_Hidden' => TYPES_ABSPATH . '/library/toolset/toolset-common/toolset-forms/classes/class.hidden.php',
130
+ 'WPToolset_Field_Image' => TYPES_ABSPATH . '/library/toolset/toolset-common/toolset-forms/classes/class.image.php',
131
+ 'WPToolset_Field_Integer' => TYPES_ABSPATH . '/library/toolset/toolset-common/toolset-forms/classes/class.integer.php',
132
+ 'WPToolset_Field_Numeric' => TYPES_ABSPATH . '/library/toolset/toolset-common/toolset-forms/classes/class.numeric.php',
133
+ 'WPToolset_Field_Password' => TYPES_ABSPATH . '/library/toolset/toolset-common/toolset-forms/classes/class.password.php',
134
+ 'WPToolset_Field_Phone' => TYPES_ABSPATH . '/library/toolset/toolset-common/toolset-forms/classes/class.phone.php',
135
+ 'WPToolset_Field_Radios' => TYPES_ABSPATH . '/library/toolset/toolset-common/toolset-forms/classes/class.radios.php',
136
+ 'WPToolset_Field_Recaptcha' => TYPES_ABSPATH . '/library/toolset/toolset-common/toolset-forms/classes/class.recaptcha.php',
137
+ 'WPToolset_Forms_Repetitive' => TYPES_ABSPATH . '/library/toolset/toolset-common/toolset-forms/classes/class.repetitive.php',
138
+ 'WPToolset_Field_Select' => TYPES_ABSPATH . '/library/toolset/toolset-common/toolset-forms/classes/class.select.php',
139
+ 'WPToolset_Field_Skype' => TYPES_ABSPATH . '/library/toolset/toolset-common/toolset-forms/classes/class.skype.php',
140
+ 'WPToolset_Field_Submit' => TYPES_ABSPATH . '/library/toolset/toolset-common/toolset-forms/classes/class.submit.php',
141
+ 'WPToolset_Field_Taxonomy' => TYPES_ABSPATH . '/library/toolset/toolset-common/toolset-forms/classes/class.taxonomy.php',
142
+ 'WPToolset_Field_Taxonomyhierarchical' => TYPES_ABSPATH . '/library/toolset/toolset-common/toolset-forms/classes/class.taxonomyhierarchical.php',
143
+ 'WPToolset_Field_Textarea' => TYPES_ABSPATH . '/library/toolset/toolset-common/toolset-forms/classes/class.textarea.php',
144
+ 'WPToolset_Field_Textfield' => TYPES_ABSPATH . '/library/toolset/toolset-common/toolset-forms/classes/class.textfield.php',
145
+ 'WPToolset_Types' => TYPES_ABSPATH . '/library/toolset/toolset-common/toolset-forms/classes/class.types.php',
146
+ 'WPToolset_Field_Url' => TYPES_ABSPATH . '/library/toolset/toolset-common/toolset-forms/classes/class.url.php',
147
+ 'WPToolset_Forms_Validation' => TYPES_ABSPATH . '/library/toolset/toolset-common/toolset-forms/classes/class.validation.php',
148
+ 'WPToolset_Field_Video' => TYPES_ABSPATH . '/library/toolset/toolset-common/toolset-forms/classes/class.video.php',
149
+ 'WPToolset_Field_Wysiwyg' => TYPES_ABSPATH . '/library/toolset/toolset-common/toolset-forms/classes/class.wysiwyg.php',
150
+ 'WPToolset_Cake_Validation' => TYPES_ABSPATH . '/library/toolset/toolset-common/toolset-forms/lib/CakePHP-Validation.php',
151
+ );
library/otgs/installer/README.md ADDED
@@ -0,0 +1,63 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # OTGS WP Installer
2
+
3
+ OTGS WP Installer is a library that allows you to install and upgrade plugins and themes developed by OnTheGoSystems.
4
+
5
+ ## Installation
6
+
7
+ First, add OTGS WP Installer as a dependency with [Composer](http://getcomposer.org):
8
+
9
+ ```bash
10
+ composer require --dev otgs/installer:dev-master
11
+ ```
12
+
13
+ Make sure that your bootstrap file is loading the composer autoloader:
14
+
15
+ ```php
16
+ require_once 'vendor/autoload.php';
17
+ ```
18
+
19
+ Then, load the OTGS WP Installer bootstrap. Before the `plugins_loaded` action add:
20
+
21
+ ```php
22
+ include 'vendor/otgs/installer/loader.php';
23
+ ```
24
+
25
+ If you're not using composer to install this library, just unpack the archive anywhere inside the plugin or theme folder and then include the bootstrap file and mentioned in the paragraph above.
26
+
27
+ Optionally, you can specify parameters to configure showing a dedicated UI under `Plugins -> Install New` or to load specific repositories.
28
+ By default, all repositories configrede in `repositories.xml` will be loaded:
29
+ * wpml - [WPML.org](http://wpml.org)
30
+ * toolset - [WP-Types.com](http://wp-types.com)
31
+
32
+ ```php
33
+ WP_Installer_Setup( $wp_installer_instance,
34
+ array(
35
+ 'plugins_install_tab' => '1', // optional, default value: 0
36
+ 'repositories_include' => array( 'wpml' ) // optional, default to empty (show all)
37
+ )
38
+ );
39
+ ```
40
+
41
+ After `init`, configure display the OTGS WP Installer UI like in teh example below:
42
+
43
+ ```php
44
+ WP_Installer_Show_Products(
45
+ array(
46
+ 'template' => 'compact', //required
47
+ 'product_name' => 'WPML',
48
+ 'box_title' => 'Multilingual Avada',
49
+ 'name' => 'Avada', //name of theme/plugin
50
+ 'box_description' => 'Avada theme is fully compatible with WPML - the WordPress Multilingual plugin. WPML lets
51
+ you add languages to your existing sites and includes advanced translation management.',
52
+ 'repository' => 'wpml', // required
53
+ 'package' => 'multilingual-cms', // required
54
+ 'product' => 'multilingual-cms' // required
55
+ )
56
+ );
57
+ ```
58
+
59
+ * `template` two options available: default and compact. Default will be the same GUI as on the Plugins -> Install new page while compact is a smaller version that can be fit in a different already existing screen
60
+ * `repository` only one product of a specific product package from a specific repository can be shown
61
+ * `package` only one product of a specific product package from a specific repository can be shown
62
+ * `product` only one product of a specific product package from a specific repository can be shown
63
+
library/otgs/installer/changelog.txt CHANGED
@@ -1,3 +1,11 @@
 
 
 
 
 
 
 
 
1
  = 1.7.13 =
2
  * Added sanitization for some inputs
3
  * Fixed PHP notice being logged when installing a plugin from the WP plugins directory
1
+ = 1.7.15 =
2
+ * Bug fix: New search, results not visible with WordPress 4.6 when searching from installer page
3
+ * Bug fix: A js error was showing on the admin pages: `pagenow` is undefined
4
+ * Added support for equivalent subscriptions
5
+
6
+ = 1.7.14 =
7
+ * Refactoring for compliance with Envato market
8
+
9
  = 1.7.13 =
10
  * Added sanitization for some inputs
11
  * Fixed PHP notice being logged when installing a plugin from the WP plugins directory
library/otgs/installer/includes/installer.class.php CHANGED
@@ -165,15 +165,18 @@ final class WP_Installer{
165
  // Extra information about the source of Installer
166
  $package_source_file = $this->plugin_path() . '/installer-source.json';
167
  if( file_exists( $package_source_file ) ){
168
- $this->package_source = json_decode( file_get_contents( $package_source_file ) );
 
 
169
  }
170
  }
171
 
172
  protected function log($message){
 
 
 
173
  if( defined('WPML_INSTALLER_LOGGING') && WPML_INSTALLER_LOGGING ){
174
- if($fh = @fopen( $this->plugin_path() . '/installer.log', 'a' )){
175
- fwrite($fh, current_time( 'mysql' ) . "\t" . $message . "\n");
176
- }
177
  }
178
  }
179
 
@@ -925,6 +928,11 @@ final class WP_Installer{
925
  continue;
926
  }
927
 
 
 
 
 
 
928
  // buy base
929
  if(empty($subscription_type) || $expired) {
930
 
@@ -937,7 +945,7 @@ final class WP_Installer{
937
  $row['products'][] = $p;
938
 
939
  // renew
940
- } elseif(isset($subscription_type) && $product['subscription_type'] == $subscription_type){
941
 
942
  if($product['renewals']) {
943
  foreach ($product['renewals'] as $renewal) {
@@ -969,7 +977,7 @@ final class WP_Installer{
969
  }
970
 
971
  // downloads
972
- if(isset($subscription_type) && !$expired && $product['subscription_type'] == $subscription_type){
973
  foreach($product['plugins'] as $plugin_slug){
974
 
975
  $row['downloads'][] = $this->settings['repositories'][$repository_id]['data']['downloads']['plugins'][$plugin_slug];
@@ -2651,8 +2659,8 @@ final class WP_Installer{
2651
 
2652
 
2653
  echo '<div class="wrap">';
2654
- echo '<h2>' . __('Update Plugin') . '</h2>';
2655
- echo '<a href="' . admin_url('plugins.php') . '">' . __('Return to the plugins page') . '</a>';
2656
  echo '</div>';
2657
  require_once(ABSPATH . 'wp-admin/admin-footer.php');
2658
  exit;
165
  // Extra information about the source of Installer
166
  $package_source_file = $this->plugin_path() . '/installer-source.json';
167
  if( file_exists( $package_source_file ) ){
168
+ WP_Filesystem();
169
+ global $wp_filesystem;
170
+ $this->package_source = json_decode( $wp_filesystem->get_contents( $package_source_file ) );
171
  }
172
  }
173
 
174
  protected function log($message){
175
+ require_once ABSPATH . 'wp-admin/includes/file.php';
176
+ WP_Filesystem();
177
+ global $wp_filesystem;
178
  if( defined('WPML_INSTALLER_LOGGING') && WPML_INSTALLER_LOGGING ){
179
+ $wp_filesystem->put_contents( $this->plugin_path() . '/installer.log', current_time( 'mysql' ) . "\t" . $message . "\n" );
 
 
180
  }
181
  }
182
 
928
  continue;
929
  }
930
 
931
+ //consider equivalent subscriptions
932
+ if( empty($product['subscription_type_equivalent'])){
933
+ $product['subscription_type_equivalent'] = '';
934
+ }
935
+
936
  // buy base
937
  if(empty($subscription_type) || $expired) {
938
 
945
  $row['products'][] = $p;
946
 
947
  // renew
948
+ } elseif(isset($subscription_type) && ($product['subscription_type'] == $subscription_type || $product['subscription_type_equivalent'] == $subscription_type)){
949
 
950
  if($product['renewals']) {
951
  foreach ($product['renewals'] as $renewal) {
977
  }
978
 
979
  // downloads
980
+ if(isset($subscription_type) && !$expired && ($product['subscription_type'] == $subscription_type || $product['subscription_type_equivalent'] == $subscription_type)){
981
  foreach($product['plugins'] as $plugin_slug){
982
 
983
  $row['downloads'][] = $this->settings['repositories'][$repository_id]['data']['downloads']['plugins'][$plugin_slug];
2659
 
2660
 
2661
  echo '<div class="wrap">';
2662
+ echo '<h2>' . __( 'Update Plugin', 'installer' ) . '</h2>';
2663
+ echo '<a href="' . admin_url('plugins.php') . '">' . __( 'Return to the plugins page', 'installer' ) . '</a>';
2664
  echo '</div>';
2665
  require_once(ABSPATH . 'wp-admin/admin-footer.php');
2666
  exit;
library/otgs/installer/installer.php CHANGED
@@ -1,5 +1,5 @@
1
  <?php
2
- define('WP_INSTALLER_VERSION', '1.7.13');
3
 
4
  include_once dirname(__FILE__) . '/includes/installer.class.php';
5
 
1
  <?php
2
+ define('WP_INSTALLER_VERSION', '1.7.15');
3
 
4
  include_once dirname(__FILE__) . '/includes/installer.class.php';
5
 
library/otgs/installer/loader.php CHANGED
@@ -19,7 +19,7 @@ $wp_installer_instance = dirname(__FILE__) . '/installer.php';
19
  global $wp_installer_instances;
20
  $wp_installer_instances[$wp_installer_instance] = array(
21
  'bootfile' => $wp_installer_instance,
22
- 'version' => '1.7.13'
23
  );
24
 
25
 
19
  global $wp_installer_instances;
20
  $wp_installer_instances[$wp_installer_instance] = array(
21
  'bootfile' => $wp_installer_instance,
22
+ 'version' => '1.7.15'
23
  );
24
 
25
 
library/otgs/installer/res/js/admin.js CHANGED
@@ -34,6 +34,10 @@
34
 
35
  }
36
 
 
 
 
 
37
  },
38
 
39
  getQueryParameters : function(str) {
34
 
35
  }
36
 
37
+ if( typeof pagenow != 'undefined' && pagenow == 'plugin-install' ){
38
+ jQuery( '.plugin-install-tab-commercial .search-plugins' ).remove();
39
+ }
40
+
41
  },
42
 
43
  getQueryParameters : function(str) {
library/toolset/onthego-resources/.gitignore ADDED
@@ -0,0 +1,72 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Ignore test results
2
+ actual
3
+ results
4
+
5
+ # Ignore compiled docs
6
+ _gh_pages
7
+ _gh-pages
8
+ _site
9
+
10
+ # Numerous always-ignore extensions
11
+ *.csv
12
+ *.dat
13
+ *.diff
14
+ *.err
15
+ *.gz
16
+ *.log
17
+ *.log
18
+ *.orig
19
+ *.out
20
+ *.pid
21
+ *.rej
22
+ *.ruby-version
23
+ *.sass-cache
24
+ *.seed
25
+ *.swo
26
+ *.swp
27
+ *.vi
28
+ *.zip
29
+ *~
30
+ lib-cov
31
+
32
+ # OS or Editor folders
33
+ .DS_Store
34
+ ._*
35
+ Thumbs.db
36
+ .cache
37
+ .project
38
+ .settings
39
+ .tmproj
40
+ *.esproj
41
+ nbproject
42
+ *.sublime-*
43
+ .editorconfig
44
+
45
+ # Komodo
46
+ *.komodoproject
47
+ .komodotools
48
+
49
+ # Folders to ignore
50
+ .hg
51
+ .svn
52
+ .CVS
53
+ .idea
54
+ tmp
55
+ pids
56
+ build
57
+ src
58
+ node_modules
59
+ installer
60
+ .sass-cache
61
+ composer
62
+ embedded/toolset
63
+ embedded/toolset/toolset-common
64
+ embedded/toolset/onthego-resources
65
+
66
+ # Types
67
+ embedded/autoload.php
68
+
69
+ # Files to ignore
70
+ npm-debug.log
71
+ composer.lock
72
+ composer.json
library/toolset/onthego-resources/changelog.txt CHANGED
@@ -1,12 +1,59 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  OnTheGo Resources 1.2 (August 17, 2015)
2
  - Added new Views icons
3
 
 
4
  OnTheGo Resources 1.1 (June 11, 2015)
5
  - Added Toolset Packager icons
6
 
7
  -------------------------------------------------------------------------------------------------------------------
8
  OnTheGo Resources 1.0 (Apr 1, 2014)
9
  - Added WPML icons
 
10
  -------------------------------------------------------------------------------------------------------------------
11
  OnTheGo Resources 0.9.1 (Feb 2 2014)
12
  - Created advanced resources loader with version control
1
+ OnTheGo Resources 2.0 (December 22, 2016)
2
+ - - Improved assets loading so it can also happen in the frontend on demand
3
+
4
+ -------------------------------------------------------------------------------------------------------------------
5
+ OnTheGo Resources 1.9 (December 5, 2016)
6
+ - Added helper class for background colors
7
+ - Fixed color and background styles on hover
8
+
9
+ -------------------------------------------------------------------------------------------------------------------
10
+ OnTheGo Resources 1.8 (September 13, 2016)
11
+ - Fixed the flat Toolset menu icon when only Types embeddd is active
12
+ - Fixed a sourceMappingURL reference
13
+
14
+ -------------------------------------------------------------------------------------------------------------------
15
+ OnTheGo Resources 1.7 (August 24, 2016)
16
+ - Added Bootstrap components icons
17
+ - Updated the ont-btn styles
18
+ - Added helper class for floats
19
+ - Added helper class for indents
20
+ - Added helper class for font sizes
21
+ - Updated name for pagination icon
22
+ - Fixed some alignment issues
23
+
24
+ -------------------------------------------------------------------------------------------------------------------
25
+ OnTheGo Resources 1.6 (April 8, 2016)
26
+ - Added new flat Toolset icon and use it in the Toolset shared menu
27
+ - Added agnostic rule for padding
28
+ - Adjust the flat Toolset menu icon usage in the shared menu
29
+
30
+ -------------------------------------------------------------------------------------------------------------------
31
+ OnTheGo Resources 1.5 (January 26, 2016)
32
+ - Added the Genesis icon
33
+ - Added rule to enforce colors for icons
34
+
35
+ -------------------------------------------------------------------------------------------------------------------
36
+ OnTheGo Resources 1.4 (November 11, 2015)
37
+ - Added new Toolset Maps icon
38
+
39
+ -------------------------------------------------------------------------------------------------------------------
40
+ OnTheGo Resources 1.3 (September 28, 2015)
41
+ - Added dynamic widths for elements to 1024 resolution
42
+ - Added pad-top, pad-bot, from-top and from-bot classes
43
+ - Added ont-btn ont-btn-group to resources
44
+
45
+ -------------------------------------------------------------------------------------------------------------------
46
  OnTheGo Resources 1.2 (August 17, 2015)
47
  - Added new Views icons
48
 
49
+ -------------------------------------------------------------------------------------------------------------------
50
  OnTheGo Resources 1.1 (June 11, 2015)
51
  - Added Toolset Packager icons
52
 
53
  -------------------------------------------------------------------------------------------------------------------
54
  OnTheGo Resources 1.0 (Apr 1, 2014)
55
  - Added WPML icons
56
+
57
  -------------------------------------------------------------------------------------------------------------------
58
  OnTheGo Resources 0.9.1 (Feb 2 2014)
59
  - Created advanced resources loader with version control
library/toolset/onthego-resources/classes/onthegosystems-styles.class.php CHANGED
@@ -11,21 +11,35 @@ class OnTheGoSystemsStyles_Class{
11
  */
12
  private function __construct( )
13
  {
14
- // load wp-admin
15
- add_action( 'admin_enqueue_scripts', array(&$this, 'register_and_enqueue_styles') );
16
- // load front-end
17
- if (!is_admin()) {
18
- add_action( 'admin_bar_init', array(&$this, 'register_and_enqueue_styles') );
19
- }
 
 
20
  }
 
 
 
 
21
 
22
- public function register_and_enqueue_styles()
23
  {
24
- if ( is_admin() || defined('WPDDL_VERSION') ) {
25
- wp_register_style('onthego-admin-styles', ON_THE_GO_SYSTEMS_BRANDING_REL_PATH .'onthego-styles/onthego-styles.css');
 
 
26
  wp_enqueue_style( 'onthego-admin-styles' );
27
  }
28
  }
 
 
 
 
 
 
29
 
30
  public static function getInstance( )
31
  {
11
  */
12
  private function __construct( )
13
  {
14
+ // Register on wp_loaded:10 because this is instantiated after init
15
+ add_action( 'wp_loaded', array( &$this, 'register_styles' ) );
16
+ // Load in wp-admin
17
+ add_action( 'admin_enqueue_scripts', array( &$this, 'enqueue_styles' ) );
18
+ // Load in front-end
19
+ add_action( 'wp_enqueue_scripts', array( &$this, 'enqueue_styles' ) );
20
+ // Load on demand
21
+ add_action( 'otg_action_otg_enforce_styles', array( &$this, 'enforce_enqueue_styles' ) );
22
  }
23
+
24
+ public function register_styles() {
25
+ wp_register_style('onthego-admin-styles', ON_THE_GO_SYSTEMS_BRANDING_REL_PATH .'onthego-styles/onthego-styles.css');
26
+ }
27
 
28
+ public function enqueue_styles()
29
  {
30
+ if (
31
+ is_admin()
32
+ || defined('WPDDL_VERSION')
33
+ ) {
34
  wp_enqueue_style( 'onthego-admin-styles' );
35
  }
36
  }
37
+
38
+ public function enforce_enqueue_styles() {
39
+ if ( ! wp_style_is( 'onthego-admin-styles' ) ) {
40
+ wp_enqueue_style( 'onthego-admin-styles' );
41
+ }
42
+ }
43
 
44
  public static function getInstance( )
45
  {
library/toolset/onthego-resources/loader.php CHANGED
@@ -16,7 +16,7 @@
16
  // is made to the onthego-resources code.
17
  // The version number will then be used to work out which plugin has the latest
18
  // version of the code.
19
- $onthegosystems_branding_version = 20;
20
 
21
 
22
  // ----------------------------------------------------------------------//
16
  // is made to the onthego-resources code.
17
  // The version number will then be used to work out which plugin has the latest
18
  // version of the code.
19
+ $onthegosystems_branding_version = 21;
20
 
21
 
22
  // ----------------------------------------------------------------------//
library/toolset/toolset-common/loader.php CHANGED
@@ -30,7 +30,7 @@
30
  * Now that we have a unique version for all plugins
31
  * we define the version here
32
  */
33
- $toolset_common_version = 226000;
34
 
35
 
36
  // ----------------------------------------------------------------------//
30
  * Now that we have a unique version for all plugins
31
  * we define the version here
32
  */
33
+ $toolset_common_version = 228000;
34
 
35
 
36
  // ----------------------------------------------------------------------//
library/toolset/toolset-common/toolset-common-loader.php CHANGED
@@ -5,11 +5,11 @@ if ( class_exists( 'Toolset_Common_Bootstrap' ) ) {
5
  };
6
 
7
  if( !defined('TOOLSET_VERSION') ){
8
- define('TOOLSET_VERSION', '2.2.6');
9
  }
10
 
11
  if ( ! defined('TOOLSET_COMMON_VERSION' ) ) {
12
- define( 'TOOLSET_COMMON_VERSION', '2.2.6' );
13
  }
14
 
15
  if ( ! defined('TOOLSET_COMMON_PATH' ) ) {
5
  };
6
 
7
  if( !defined('TOOLSET_VERSION') ){
8
+ define('TOOLSET_VERSION', '2.2.8');
9
  }
10
 
11
  if ( ! defined('TOOLSET_COMMON_VERSION' ) ) {
12
+ define( 'TOOLSET_COMMON_VERSION', '2.2.8' );
13
  }
14
 
15
  if ( ! defined('TOOLSET_COMMON_PATH' ) ) {
library/toolset/toolset-common/toolset-forms/classes/class.credfile.php CHANGED
@@ -1,15 +1,9 @@
1
  <?php
2
 
3
- /**
4
- *
5
- *
6
- */
7
  require_once 'class.textfield.php';
8
 
9
  /**
10
- * Description of class
11
- *
12
- * @author Francesco / Srdjan
13
  */
14
  class WPToolset_Field_Credfile extends WPToolset_Field_Textfield {
15
 
@@ -53,9 +47,18 @@ class WPToolset_Field_Credfile extends WPToolset_Field_Textfield {
53
  return $sizes;
54
  }
55
 
 
 
 
 
 
 
 
 
 
56
  public function init() {
57
  wp_register_script('wpt-field-credfile', WPTOOLSET_FORMS_RELPATH . '/js/credfile.js', array('wptoolset-forms'), WPTOOLSET_FORMS_VERSION, true);
58
- wp_enqueue_script('wpt-field-credfile');
59
  $this->disable_progress_bar = version_compare(CRED_FE_VERSION, '1.3.6.2', '<=');
60
  $this->disable_progress_bar = apply_filters('cred_file_upload_disable_progress_bar', $this->disable_progress_bar);
61
  if ($this->disable_progress_bar) {
@@ -89,7 +92,7 @@ class WPToolset_Field_Credfile extends WPToolset_Field_Textfield {
89
  //require_once WPTOOLSET_COMMON_PATH . "/utility/utils.php";
90
  //wp_localize_script('my_ajax_file_uploader_thing', 'settings', array('ajaxurl' => admin_url('admin-ajax.php'), 'nonce' => wp_create_nonce('uploader_nonce')));
91
  wp_localize_script('my_ajax_file_uploader', 'settings', array('media_settings' => self::get_image_sizes('thumbnail'),
92
- 'ajaxurl' => plugins_url("submit.php", __FILE__),
93
  'delete_confirm_text' => __('Are you sure to delete this file ?', 'wpv-views'),
94
  'delete_alert_text' => __('Generic Error in deleting file', 'wpv-views'),
95
  'delete_text' => __('delete', 'wpv-views'),
@@ -122,7 +125,7 @@ class WPToolset_Field_Credfile extends WPToolset_Field_Textfield {
122
  $title = $name;
123
  }
124
 
125
- $id = str_replace(array("[", "]"), "", $name);
126
  $preview_span_input_showhide = '';
127
  $button_extra_classnames = '';
128
 
@@ -138,7 +141,7 @@ class WPToolset_Field_Credfile extends WPToolset_Field_Textfield {
138
  if (!$is_empty) {
139
  $pathinfo = pathinfo($value);
140
  // TODO we should check against the allowed mime types, not file extensions
141
- if (($this->_data['type'] == 'credimage' || $this->_data['type'] == 'credfile') &&
142
  isset($pathinfo['extension']) && in_array(strtolower($pathinfo['extension']), array('png', 'gif', 'jpg', 'jpeg', 'bmp', 'tif'))) {
143
  $has_image = true;
144
  }
@@ -179,16 +182,16 @@ class WPToolset_Field_Credfile extends WPToolset_Field_Textfield {
179
  //Attachment id for _featured_image if exists
180
  //if it does not exists file_upload.js will handle it after file is uploaded
181
  if ($name == '_featured_image') {
182
- global $post;
183
- $post_id = $post->ID;
184
- $post_thumbnail_id = get_post_thumbnail_id( $post_id );
185
  if (!empty($post_thumbnail_id))
186
  $form[] = array(
187
  '#type' => 'markup',
188
- '#markup' => "<input id='attachid_" .$id. "' name='attachid_" .$id. "' type='hidden' value='" .$post_thumbnail_id. "'>"
189
- );
190
  }
191
-
192
  $form[] = array(
193
  '#type' => 'hidden',
194
  '#name' => $name,
@@ -214,24 +217,119 @@ class WPToolset_Field_Credfile extends WPToolset_Field_Textfield {
214
  '#markup' => '<div id="progress_' . $id . '" class="meter" style="display:none;"><span class = "progress-bar" style="width:0;"></span></div>',
215
  );
216
  }
217
-
218
  $delete_butt = '<input type="button" data-action="delete" class="js-wpt-credfile-delete wpt-credfile-delete' . $button_extra_classnames . '" value="' . __('delete', 'wpv-views') . '" style="width:100%;margin-top:2px;margin-bottom:2px;" />';
219
  if ($has_image) {
220
  //$delete_butt = "<input id='butt_{$id}' style='width:100%;margin-top:2px;margin-bottom:2px;' type='button' value='" . __('delete', 'wpv-views') . "' rel='{$preview_file}' class='delete_ajax_file'>";
221
 
222
  $form[] = array(
223
  '#type' => 'markup',
224
- '#markup' => '<span class="js-wpt-credfile-preview wpt-credfile-preview" '.$preview_span_input_showhide.'><img id="' . $id . '_image" src="' . $preview_file . '" title="' . $preview_file . '" alt="' . $preview_file . '" class="js-wpt-credfile-preview-item wpt-credfile-preview-item" style="max-width:150px"/>' . $delete_butt . '</span>',
225
  );
226
  } else {
227
 
228
  //if ( !$is_empty )
229
  $form[] = array(
230
  '#type' => 'markup',
231
- '#markup' => '<span class="js-wpt-credfile-preview wpt-credfile-preview" '.$preview_span_input_showhide.'>' . $preview_file . $delete_butt . '</span>',
232
  );
233
  }
234
  return $form;
235
  }
236
 
237
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  <?php
2
 
 
 
 
 
3
  require_once 'class.textfield.php';
4
 
5
  /**
6
+ * WPToolset_Field_Credfile
 
 
7
  */
8
  class WPToolset_Field_Credfile extends WPToolset_Field_Textfield {
9
 
47
  return $sizes;
48
  }
49
 
50
+ public static function get_correct_submit_url() {
51
+ $correct_submit_url = http_build_url(
52
+ plugins_url('submit.php', __FILE__), array(
53
+ 'host' => $_SERVER['HTTP_HOST'],
54
+ 'scheme' => ( is_ssl() ? 'https' : 'http' ))
55
+ );
56
+ return $correct_submit_url;
57
+ }
58
+
59
  public function init() {
60
  wp_register_script('wpt-field-credfile', WPTOOLSET_FORMS_RELPATH . '/js/credfile.js', array('wptoolset-forms'), WPTOOLSET_FORMS_VERSION, true);
61
+ wp_enqueue_script('wpt-field-credfile');
62
  $this->disable_progress_bar = version_compare(CRED_FE_VERSION, '1.3.6.2', '<=');
63
  $this->disable_progress_bar = apply_filters('cred_file_upload_disable_progress_bar', $this->disable_progress_bar);
64
  if ($this->disable_progress_bar) {
92
  //require_once WPTOOLSET_COMMON_PATH . "/utility/utils.php";
93
  //wp_localize_script('my_ajax_file_uploader_thing', 'settings', array('ajaxurl' => admin_url('admin-ajax.php'), 'nonce' => wp_create_nonce('uploader_nonce')));
94
  wp_localize_script('my_ajax_file_uploader', 'settings', array('media_settings' => self::get_image_sizes('thumbnail'),
95
+ 'ajaxurl' => apply_filters('cred_file_upload_submit_url', self::get_correct_submit_url()),
96
  'delete_confirm_text' => __('Are you sure to delete this file ?', 'wpv-views'),
97
  'delete_alert_text' => __('Generic Error in deleting file', 'wpv-views'),
98
  'delete_text' => __('delete', 'wpv-views'),
125
  $title = $name;
126
  }
127
 
128
+ $id = $this->_data['id']; //str_replace(array("[", "]"), "", $name);
129
  $preview_span_input_showhide = '';
130
  $button_extra_classnames = '';
131
 
141
  if (!$is_empty) {
142
  $pathinfo = pathinfo($value);
143
  // TODO we should check against the allowed mime types, not file extensions
144
+ if (($this->_data['type'] == 'credimage' || $this->_data['type'] == 'credfile') &&
145
  isset($pathinfo['extension']) && in_array(strtolower($pathinfo['extension']), array('png', 'gif', 'jpg', 'jpeg', 'bmp', 'tif'))) {
146
  $has_image = true;
147
  }
182
  //Attachment id for _featured_image if exists
183
  //if it does not exists file_upload.js will handle it after file is uploaded
184
  if ($name == '_featured_image') {
185
+ global $post;
186
+ $post_id = $post->ID;
187
+ $post_thumbnail_id = get_post_thumbnail_id($post_id);
188
  if (!empty($post_thumbnail_id))
189
  $form[] = array(
190
  '#type' => 'markup',
191
+ '#markup' => "<input id='attachid_" . $id . "' name='attachid_" . $id . "' type='hidden' value='" . $post_thumbnail_id . "'>"
192
+ );
193
  }
194
+
195
  $form[] = array(
196
  '#type' => 'hidden',
197
  '#name' => $name,
217
  '#markup' => '<div id="progress_' . $id . '" class="meter" style="display:none;"><span class = "progress-bar" style="width:0;"></span></div>',
218
  );
219
  }
220
+
221
  $delete_butt = '<input type="button" data-action="delete" class="js-wpt-credfile-delete wpt-credfile-delete' . $button_extra_classnames . '" value="' . __('delete', 'wpv-views') . '" style="width:100%;margin-top:2px;margin-bottom:2px;" />';
222
  if ($has_image) {
223
  //$delete_butt = "<input id='butt_{$id}' style='width:100%;margin-top:2px;margin-bottom:2px;' type='button' value='" . __('delete', 'wpv-views') . "' rel='{$preview_file}' class='delete_ajax_file'>";
224
 
225
  $form[] = array(
226
  '#type' => 'markup',
227
+ '#markup' => '<span class="js-wpt-credfile-preview wpt-credfile-preview" ' . $preview_span_input_showhide . '><img id="' . $id . '_image" src="' . $preview_file . '" title="' . $preview_file . '" alt="' . $preview_file . '" class="js-wpt-credfile-preview-item wpt-credfile-preview-item" style="max-width:150px"/>' . $delete_butt . '</span>',
228
  );
229
  } else {
230
 
231
  //if ( !$is_empty )
232
  $form[] = array(
233
  '#type' => 'markup',
234
+ '#markup' => '<span class="js-wpt-credfile-preview wpt-credfile-preview" ' . $preview_span_input_showhide . '>' . $preview_file . $delete_butt . '</span>',
235
  );
236
  }
237
  return $form;
238
  }
239
 
240
  }
241
+
242
+ if (!function_exists('http_build_url')) {
243
+
244
+ /**
245
+ * compatible http_build_url
246
+ * @param mixed $url
247
+ * @param mixed $parts
248
+ * @return string
249
+ */
250
+ function http_build_url($url, $parts = array()) {
251
+ is_array($url) || $url = parse_url($url);
252
+ is_array($parts) || $parts = parse_url($parts);
253
+
254
+ isset($url['query']) && is_string($url['query']) || $url['query'] = null;
255
+ isset($parts['query']) && is_string($parts['query']) || $parts['query'] = null;
256
+
257
+ $keys = array('user', 'pass', 'port', 'path', 'query', 'fragment');
258
+
259
+ // Schema and host are alwasy replaced
260
+ foreach (array('scheme', 'host') as $part) {
261
+ if (isset($parts[$part])) {
262
+ $url[$part] = $parts[$part];
263
+ }
264
+ }
265
+
266
+ if (isset($parts['path'])) {
267
+ if (isset($url['path']) && substr($parts['path'], 0, 1) !== '/') {
268
+ // Workaround for trailing slashes
269
+ $url['path'] .= 'a';
270
+ $url['path'] = rtrim(
271
+ str_replace(basename($url['path']), '', $url['path']), '/'
272
+ ) . '/' . ltrim($parts['path'], '/');
273
+ } else {
274
+ $url['path'] = $parts['path'];
275
+ }
276
+ }
277
+
278
+ if (isset($parts['query'])) {
279
+ if (isset($url['query'])) {
280
+ parse_str($url['query'], $url_query);
281
+ parse_str($parts['query'], $parts_query);
282
+
283
+ $url['query'] = http_build_query(
284
+ array_replace_recursive(
285
+ $url_query, $parts_query
286
+ )
287
+ );
288
+ } else {
289
+ $url['query'] = $parts['query'];
290
+ }
291
+ }
292
+
293
+ if (isset($url['path']) && $url['path'] !== '' && substr($url['path'], 0, 1) !== '/') {
294
+ $url['path'] = '/' . $url['path'];
295
+ }
296
+
297
+ $parsed_string = '';
298
+
299
+ if (!empty($url['scheme'])) {
300
+ $parsed_string .= $url['scheme'] . '://';
301
+ }
302
+
303
+ if (!empty($url['user'])) {
304
+ $parsed_string .= $url['user'];
305
+
306
+ if (isset($url['pass'])) {
307
+ $parsed_string .= ':' . $url['pass'];
308
+ }
309
+
310
+ $parsed_string .= '@';
311
+ }
312
+
313
+ if (!empty($url['host'])) {
314
+ $parsed_string .= $url['host'];
315
+ }
316
+
317
+ if (!empty($url['port'])) {
318
+ $parsed_string .= ':' . $url['port'];
319
+ }
320
+
321
+ if (!empty($url['path'])) {
322
+ $parsed_string .= $url['path'];
323
+ }
324
+
325
+ if (!empty($url['query'])) {
326
+ $parsed_string .= '?' . $url['query'];
327
+ }
328
+
329
+ if (!empty($url['fragment'])) {
330
+ $parsed_string .= '#' . $url['fragment'];
331
+ }
332
+ return $parsed_string;
333
+ }
334
+
335
+ }
library/toolset/toolset-common/toolset-forms/classes/submit.php CHANGED
@@ -1,5 +1,17 @@
1
  <?php
2
 
 
 
 
 
 
 
 
 
 
 
 
 
3
  function cred_find_wp_config_path($dir, $file2search) {
4
  if (file_exists($dir . "/" . $file2search)) {
5
  return $dir . "/";
@@ -17,7 +29,7 @@ function cred_find_wp_config_path($dir, $file2search) {
17
  }
18
 
19
  function cred_get_root_path() {
20
- return cred_find_wp_config_path($_SERVER['DOCUMENT_ROOT'], "wp-load.php");
21
  }
22
 
23
  function cred_get_local($url) {
@@ -30,21 +42,13 @@ function cred_clean($string) {
30
  return preg_replace('/[^A-Za-z0-9\-]/', '', $string); // Removes special chars.
31
  }
32
 
33
- /**
34
- * Executing AJAX process.
35
- *
36
- * @since 2.1.0
37
- */
38
  define('WP_USE_THEMES', false);
39
  define('DOING_AJAX', true);
40
- //if (!defined('WP_ADMIN')) {
41
- // define('WP_ADMIN', true);
42
- //}
43
 
44
  require_once( cred_get_root_path() . 'wp-load.php' );
45
- require_once( cred_get_root_path() . 'wp-admin/includes/file.php' );
46
- require_once( cred_get_root_path() . 'wp-admin/includes/media.php' );
47
- require_once( cred_get_root_path() . 'wp-admin/includes/image.php' );
48
 
49
  /** Allow for cross-domain requests (from the frontend). */
50
  send_origin_headers();
@@ -54,44 +58,28 @@ $data = array();
54
  if (isset($_REQUEST['nonce']) && check_ajax_referer('ajax_nonce', 'nonce', false)) {
55
 
56
  if (isset($_POST['action']) && $_POST['action'] == 'delete' && isset($_POST['file'])) {
57
- $file = esc_url_raw( $_POST['file'] );
58
  $id = isset($_POST['id']) ? (int) $_POST['id'] : 0;
59
-
60
  $data = array('result' => true);
61
-
62
  $local_file = cred_get_local($file);
63
-
64
- //get all image attachments
65
  $attachments = get_children(
66
  array(
67
  'post_parent' => $id,
68
- //'post_mime_type' => 'image',
69
  'post_type' => 'attachment'
70
  )
71
  );
72
-
73
- //loop through the array
74
  if (!empty($attachments)) {
75
  foreach ($attachments as $attachment) {
76
  $attach_file = strtolower(basename($attachment->guid));
77
  $my_local_file = strtolower(basename($local_file));
78
  if ($attach_file == $my_local_file)
79
  wp_delete_attachment($attachment->ID);
80
-
81
- // Update the post into the database
82
- // wp_update_post( array(
83
- // 'ID' => $attachment->ID,
84
- // 'post_parent' => 0
85
- // )
86
- // );
87
  }
88
  }
89
-
90
-
91
  // if (file_exists($local_file)) {
92
  // $res = unlink($local_file);
93
  // }
94
- //$data = ($res) ? array('result' => $res) : array('result' => $res, 'error' => 'Error Deleting ' . $file);
95
  } else {
96
  if (isset($_GET['id'])) {
97
  $post_id = intval($_GET['id']);
@@ -121,7 +109,7 @@ if (isset($_REQUEST['nonce']) && check_ajax_referer('ajax_nonce', 'nonce', false
121
  break;
122
  }
123
  }
124
-
125
  //If no size errors
126
  if (empty($data)) {
127
 
1
  <?php
2
 
3
+ define("CRED_WP_REF_FILE", "wp-blog-header.php");
4
+
5
+ function cred_find_abspath($dir, $file2search) {
6
+ if (file_exists($dir . "/" . $file2search)) {
7
+ return $dir . "/";
8
+ }
9
+ $search_in_dir = cred_find_wp_config_path($dir, CRED_WP_REF_FILE);
10
+ if (!empty($search_in_dir))
11
+ return $search_in_dir;
12
+ return cred_find_abspath(dirname($dir), $file2search);
13
+ }
14
+
15
  function cred_find_wp_config_path($dir, $file2search) {
16
  if (file_exists($dir . "/" . $file2search)) {
17
  return $dir . "/";
29
  }
30
 
31
  function cred_get_root_path() {
32
+ return cred_find_abspath(dirname(__FILE__), CRED_WP_REF_FILE);
33
  }
34
 
35
  function cred_get_local($url) {
42
  return preg_replace('/[^A-Za-z0-9\-]/', '', $string); // Removes special chars.
43
  }
44
 
 
 
 
 
 
45
  define('WP_USE_THEMES', false);
46
  define('DOING_AJAX', true);
 
 
 
47
 
48
  require_once( cred_get_root_path() . 'wp-load.php' );
49
+ require_once( ABSPATH . 'wp-admin/includes/file.php' );
50
+ require_once( ABSPATH . 'wp-admin/includes/media.php' );
51
+ require_once( ABSPATH . 'wp-admin/includes/image.php' );
52
 
53
  /** Allow for cross-domain requests (from the frontend). */
54
  send_origin_headers();
58
  if (isset($_REQUEST['nonce']) && check_ajax_referer('ajax_nonce', 'nonce', false)) {
59
 
60
  if (isset($_POST['action']) && $_POST['action'] == 'delete' && isset($_POST['file'])) {
61
+ $file = esc_url_raw($_POST['file']);
62
  $id = isset($_POST['id']) ? (int) $_POST['id'] : 0;
 
63
  $data = array('result' => true);
 
64
  $local_file = cred_get_local($file);
 
 
65
  $attachments = get_children(
66
  array(
67
  'post_parent' => $id,
 
68
  'post_type' => 'attachment'
69
  )
70
  );
 
 
71
  if (!empty($attachments)) {
72
  foreach ($attachments as $attachment) {
73
  $attach_file = strtolower(basename($attachment->guid));
74
  $my_local_file = strtolower(basename($local_file));
75
  if ($attach_file == $my_local_file)
76
  wp_delete_attachment($attachment->ID);
 
 
 
 
 
 
 
77
  }
78
  }
 
 
79
  // if (file_exists($local_file)) {
80
  // $res = unlink($local_file);
81
  // }
82
+ // $data = ($res) ? array('result' => $res) : array('result' => $res, 'error' => 'Error Deleting ' . $file);
83
  } else {
84
  if (isset($_GET['id'])) {
85
  $post_id = intval($_GET['id']);
109
  break;
110
  }
111
  }
112
+
113
  //If no size errors
114
  if (empty($data)) {
115
 
library/toolset/toolset-common/toolset-forms/js/credfile.js CHANGED
@@ -27,12 +27,13 @@ var wptCredfile = (function ($) {
27
  thiz_undo_button.hide();
28
  }
29
  if (myid == '_featured_image') {
30
- $('#attachid_' + myid).val('');
31
  } else {
32
  if (thiz.closest('.js-wpt-repetitive').length > 0) {
33
- } else
34
  $('#' + myid).prop('disabled', false);
35
- //$("<input type='hidden' id='" + myid + "' name='" + myid + "' value=''>").insertAfter('#' + thiz_hidden_input.attr('id'));
 
36
  }
37
  thiz_file_input.trigger('change');
38
  } else if (credfile_action == 'undo') {
@@ -42,12 +43,13 @@ var wptCredfile = (function ($) {
42
  thiz_preview.show();
43
  //thiz_delete_button.show();
44
  thiz_undo_button.hide();
45
- if (myid == '_featured_image')
46
- $('#attachid_' + myid).val($("input[name='_cred_cred_prefix_post_id']").val());
47
- else {
48
  if (thiz.closest('.js-wpt-repetitive').length > 0) {
49
- } else
50
  $('#' + myid).prop('disabled', false);
 
51
  }
52
  }
53
  });
27
  thiz_undo_button.hide();
28
  }
29
  if (myid == '_featured_image') {
30
+ $('#attachid_' + myid).prop('disabled', true);
31
  } else {
32
  if (thiz.closest('.js-wpt-repetitive').length > 0) {
33
+ } else {
34
  $('#' + myid).prop('disabled', false);
35
+ }
36
+ //$("<input type='hidden' id='" + myid + "' name='" + myid + "' value=''>").insertAfter('#' + thiz_hidden_input.attr('id'));
37
  }
38
  thiz_file_input.trigger('change');
39
  } else if (credfile_action == 'undo') {
43
  thiz_preview.show();
44
  //thiz_delete_button.show();
45
  thiz_undo_button.hide();
46
+ if (myid == '_featured_image') {
47
+ $('#attachid_' + myid).prop('disabled', false);
48
+ } else {
49
  if (thiz.closest('.js-wpt-repetitive').length > 0) {
50
+ } else {
51
  $('#' + myid).prop('disabled', false);
52
+ }
53
  }
54
  }
55
  });
library/toolset/toolset-common/toolset-forms/js/jquery_upload/file_upload.js CHANGED
@@ -101,8 +101,9 @@ jQuery(function () {
101
  var new_num = number - 1;
102
  //console.log("new_num: " + new_num);
103
  var hidden_id = "wpt-form-el" + new_num;
104
- } else
105
  var hidden_id = wpt_id + '_hidden';
 
106
 
107
  //console.log("hidden_id: " + hidden_id);
108
 
@@ -144,12 +145,13 @@ jQuery(function () {
144
  //append new image and delete button to the span
145
  jQuery("<img id='loaded_" + myid + "' src='" + preview + "'>").prependTo(preview_span);
146
  }
147
-
148
- if (myid == '_featured_image') {
149
- if (jQuery("#attachid_" + myid).lenght > 0) {
150
- jQuery("#attachid_" + myid).attr("value", attachid);
 
151
  } else {
152
- jQuery("<input id='attachid_" + myid + "' name='attachid_" + myid + "' type='hidden' value='" + attachid + "'>").appendTo(preview_span.parent());
153
  }
154
  }
155
  }
@@ -158,8 +160,9 @@ jQuery(function () {
158
  //<input id='butt_" + myid + "' style='width:100%;margin-top:2px;margin-bottom:2px;' type='button' value='" + settings.delete_text + "' rel='" + file + "' class='delete_ajax_file'>
159
  jQuery("<a id='loaded_" + myid + "' href='" + file + "' target='_blank'>" + file + "</a></label>").insertAfter('#' + jQuery(curr_file).attr('id'));
160
  }
161
- if (typeof preview_span !== undefined)
162
  jQuery(preview_span).show();
 
163
 
164
  wptCredfile.init('body');
165
  });
101
  var new_num = number - 1;
102
  //console.log("new_num: " + new_num);
103
  var hidden_id = "wpt-form-el" + new_num;
104
+ } else {
105
  var hidden_id = wpt_id + '_hidden';
106
+ }
107
 
108
  //console.log("hidden_id: " + hidden_id);
109
 
145
  //append new image and delete button to the span
146
  jQuery("<img id='loaded_" + myid + "' src='" + preview + "'>").prependTo(preview_span);
147
  }
148
+
149
+ if (jQuery('#' + hidden_id).attr('name') == '_featured_image') {
150
+ var _featured_image_name = jQuery('#' + hidden_id).attr('name');
151
+ if (jQuery("#attachid_" + _featured_image_name).lenght > 0) {
152
+ jQuery("#attachid_" + _featured_image_name).attr("value", attachid);
153
  } else {
154
+ jQuery("<input id='attachid_" + _featured_image_name + "' name='attachid_" + _featured_image_name + "' type='hidden' value='" + attachid + "'>").appendTo(preview_span.parent());
155
  }
156
  }
157
  }
160
  //<input id='butt_" + myid + "' style='width:100%;margin-top:2px;margin-bottom:2px;' type='button' value='" + settings.delete_text + "' rel='" + file + "' class='delete_ajax_file'>
161
  jQuery("<a id='loaded_" + myid + "' href='" + file + "' target='_blank'>" + file + "</a></label>").insertAfter('#' + jQuery(curr_file).attr('id'));
162
  }
163
+ if (typeof preview_span !== undefined) {
164
  jQuery(preview_span).show();
165
+ }
166
 
167
  wptCredfile.init('body');
168
  });
library/toolset/toolset-common/toolset-forms/js/validation.js CHANGED
@@ -55,15 +55,15 @@ var wptValidation = (function ($) {
55
  case 'select':
56
  return _value && $.trim(_value).length > 0;
57
  case 'input':
58
- //Fixing YT cred-196
59
  if (jQuery(element).hasClass("wpt-form-radio")) {
60
  var val = jQuery('input[name="' + _name + '"]:checked').val();
61
- if (wptValidationDebug)
 
62
  console.log("radio " + (typeof val != 'undefined' && val && $.trim(val).length > 0));
 
63
  return typeof val != 'undefined' && val && $.trim(val).length > 0;
64
  }
65
 
66
- //Fixing YT cred-104
67
  element = jQuery(element).siblings('input[type="hidden"]');
68
  if (element[0] &&
69
  !jQuery(element[0]).prop("disabled") &&
@@ -72,8 +72,10 @@ var wptValidation = (function ($) {
72
  jQuery(element[0]).attr('data-wpt-type') == 'image'
73
  )) {
74
  var val = jQuery(element[0]).val();
 
75
  if (wptValidationDebug)
76
  console.log("hidden " + (val && $.trim(val).length > 0));
 
77
  return val && $.trim(val).length > 0;
78
  }
79
 
55
  case 'select':
56
  return _value && $.trim(_value).length > 0;
57
  case 'input':
 
58
  if (jQuery(element).hasClass("wpt-form-radio")) {
59
  var val = jQuery('input[name="' + _name + '"]:checked').val();
60
+
61
+ if (wptValidationDebug)
62
  console.log("radio " + (typeof val != 'undefined' && val && $.trim(val).length > 0));
63
+
64
  return typeof val != 'undefined' && val && $.trim(val).length > 0;
65
  }
66
 
 
67
  element = jQuery(element).siblings('input[type="hidden"]');
68
  if (element[0] &&
69
  !jQuery(element[0]).prop("disabled") &&
72
  jQuery(element[0]).attr('data-wpt-type') == 'image'
73
  )) {
74
  var val = jQuery(element[0]).val();
75
+
76
  if (wptValidationDebug)
77
  console.log("hidden " + (val && $.trim(val).length > 0));
78
+
79
  return val && $.trim(val).length > 0;
80
  }
81
 
library/toolset/toolset-common/visual-editor/res/js/codemirror/.gitattributes ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
1
+ *.txt text
2
+ *.js text
3
+ *.html text
4
+ *.md text
5
+ *.json text
6
+ *.yml text
7
+ *.css text
8
+ *.svg text
library/toolset/toolset-common/visual-editor/res/js/codemirror/.gitignore ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
1
+ /node_modules
2
+ /npm-debug.log
3
+ /test*.html
4
+ .tern-*
5
+ *~
6
+ *.swp
7
+ .idea
8
+ *.iml
library/toolset/toolset-common/visual-editor/res/js/codemirror/.npmignore ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ /node_modules
2
+ /demo
3
+ /doc
4
+ /test
5
+ /index.html
6
+ /mode/*/*test.js
7
+ /mode/*/*.html
8
+ /mode/index.html
9
+ .*
library/toolset/toolset-common/visual-editor/res/js/codemirror/.travis.yml ADDED
@@ -0,0 +1,4 @@
 
 
 
 
1
+ language: node_js
2
+ node_js:
3
+ - stable
4
+ sudo: false
library/toolset/types/.travis.yml ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ language: php
2
+
3
+ notifications:
4
+ email:
5
+ on_success: never
6
+ on_failure: change
7
+
8
+ branches:
9
+ only:
10
+ - master
11
+
12
+ php:
13
+ - 5.3
14
+ - 5.6
15
+
16
+ env:
17
+ - WP_VERSION=latest WP_MULTISITE=0
18
+ - WP_VERSION=3.7 WP_MULTISITE=0
19
+ - WP_VERSION=4.4.1 WP_MULTISITE=0
20
+
21
+ matrix:
22
+ include:
23
+ - php: 5.3
24
+ env: WP_VERSION=latest WP_MULTISITE=1
25
+
26
+ before_script:
27
+ - bash bin/install-wp-tests.sh wordpress_test root '' localhost $WP_VERSION
28
+
29
+ script: phpunit
library/toolset/types/bin/install-wp-tests.sh ADDED
@@ -0,0 +1,118 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env bash
2
+
3
+ if [ $# -lt 3 ]; then
4
+ echo "usage: $0 <db-name> <db-user> <db-pass> [db-host] [wp-version]"
5
+ exit 1
6
+ fi
7
+
8
+ DB_NAME=$1
9
+ DB_USER=$2
10
+ DB_PASS=$3
11
+ DB_HOST=${4-localhost}
12
+ WP_VERSION=${5-latest}
13
+
14
+ WP_TESTS_DIR=${WP_TESTS_DIR-/tmp/wordpress-tests-lib}
15
+ WP_CORE_DIR=${WP_CORE_DIR-/tmp/wordpress/}
16
+
17
+ download() {
18
+ if [ `which curl` ]; then
19
+ curl -s "$1" > "$2";
20
+ elif [ `which wget` ]; then
21
+ wget -nv -O "$2" "$1"
22
+ fi
23
+ }
24
+
25
+ if [[ $WP_VERSION =~ [0-9]+\.[0-9]+(\.[0-9]+)? ]]; then
26
+ WP_TESTS_TAG="tags/$WP_VERSION"
27
+ elif [[ $WP_VERSION == 'nightly' || $WP_VERSION == 'trunk' ]]; then
28
+ WP_TESTS_TAG="trunk"
29
+ else
30
+ # http serves a single offer, whereas https serves multiple. we only want one
31
+ download http://api.wordpress.org/core/version-check/1.7/ /tmp/wp-latest.json
32
+ grep '[0-9]+\.[0-9]+(\.[0-9]+)?' /tmp/wp-latest.json
33
+ LATEST_VERSION=$(grep -o '"version":"[^"]*' /tmp/wp-latest.json | sed 's/"version":"//')
34
+ if [[ -z "$LATEST_VERSION" ]]; then
35
+ echo "Latest WordPress version could not be found"
36
+ exit 1
37
+ fi
38
+ WP_TESTS_TAG="tags/$LATEST_VERSION"
39
+ fi
40
+
41
+ set -ex
42
+
43
+ install_wp() {
44
+
45
+ if [ -d $WP_CORE_DIR ]; then
46
+ return;
47
+ fi
48
+
49
+ mkdir -p $WP_CORE_DIR
50
+
51
+ if [[ $WP_VERSION == 'nightly' || $WP_VERSION == 'trunk' ]]; then
52
+ mkdir -p /tmp/wordpress-nightly
53
+ download https://wordpress.org/nightly-builds/wordpress-latest.zip /tmp/wordpress-nightly/wordpress-nightly.zip
54
+ unzip -q /tmp/wordpress-nightly/wordpress-nightly.zip -d /tmp/wordpress-nightly/
55
+ mv /tmp/wordpress-nightly/wordpress/* $WP_CORE_DIR
56
+ else
57
+ if [ $WP_VERSION == 'latest' ]; then
58
+ local ARCHIVE_NAME='latest'
59
+ else
60
+ local ARCHIVE_NAME="wordpress-$WP_VERSION"
61
+ fi
62
+ download https://wordpress.org/${ARCHIVE_NAME}.tar.gz /tmp/wordpress.tar.gz
63
+ tar --strip-components=1 -zxmf /tmp/wordpress.tar.gz -C $WP_CORE_DIR
64
+ fi
65
+
66
+ download https://raw.github.com/markoheijnen/wp-mysqli/master/db.php $WP_CORE_DIR/wp-content/db.php
67
+ }
68
+
69
+ install_test_suite() {
70
+ # portable in-place argument for both GNU sed and Mac OSX sed
71
+ if [[ $(uname -s) == 'Darwin' ]]; then
72
+ local ioption='-i .bak'
73
+ else
74
+ local ioption='-i'
75
+ fi
76
+
77
+ # set up testing suite if it doesn't yet exist
78
+ if [ ! -d $WP_TESTS_DIR ]; then
79
+ # set up testing suite
80
+ mkdir -p $WP_TESTS_DIR
81
+ svn co --quiet https://develop.svn.wordpress.org/${WP_TESTS_TAG}/tests/phpunit/includes/ $WP_TESTS_DIR/includes
82
+ fi
83
+
84
+ if [ ! -f wp-tests-config.php ]; then
85
+ download https://develop.svn.wordpress.org/${WP_TESTS_TAG}/wp-tests-config-sample.php "$WP_TESTS_DIR"/wp-tests-config.php
86
+ sed $ioption "s:dirname( __FILE__ ) . '/src/':'$WP_CORE_DIR':" "$WP_TESTS_DIR"/wp-tests-config.php
87
+ sed $ioption "s/youremptytestdbnamehere/$DB_NAME/" "$WP_TESTS_DIR"/wp-tests-config.php
88
+ sed $ioption "s/yourusernamehere/$DB_USER/" "$WP_TESTS_DIR"/wp-tests-config.php
89
+ sed $ioption "s/yourpasswordhere/$DB_PASS/" "$WP_TESTS_DIR"/wp-tests-config.php
90
+ sed $ioption "s|localhost|${DB_HOST}|" "$WP_TESTS_DIR"/wp-tests-config.php
91
+ fi
92
+
93
+ }
94
+
95
+ install_db() {
96
+ # parse DB_HOST for port or socket references
97
+ local PARTS=(${DB_HOST//\:/ })
98
+ local DB_HOSTNAME=${PARTS[0]};
99
+ local DB_SOCK_OR_PORT=${PARTS[1]};
100
+ local EXTRA=""
101
+
102
+ if ! [ -z $DB_HOSTNAME ] ; then
103
+ if [ $(echo $DB_SOCK_OR_PORT | grep -e '^[0-9]\{1,\}$') ]; then
104
+ EXTRA=" --host=$DB_HOSTNAME --port=$DB_SOCK_OR_PORT --protocol=tcp"
105
+ elif ! [ -z $DB_SOCK_OR_PORT ] ; then
106
+ EXTRA=" --socket=$DB_SOCK_OR_PORT"
107
+ elif ! [ -z $DB_HOSTNAME ] ; then
108
+ EXTRA=" --host=$DB_HOSTNAME --protocol=tcp"
109
+ fi
110
+ fi
111
+
112
+ # create database
113
+ mysqladmin create $DB_NAME --user="$DB_USER" --password="$DB_PASS"$EXTRA
114
+ }
115
+
116
+ install_wp
117
+ install_test_suite
118
+ install_db
library/toolset/types/disabled_autoload_classmap.php ADDED
@@ -0,0 +1,101 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ // Generated by ZF2's ./bin/classmap_generator.php
3
+ return array(
4
+ 'WPCF_Import_Export' => WPCF_ABSPATH . '/embedded/classes/class.wpcf-import-export.php',
5
+ 'WPCF_Post_Types' => WPCF_ABSPATH . '/embedded/classes/class.wpcf-post-types.php',
6
+ 'WPCF_Conditional' => WPCF_ABSPATH . '/embedded/classes/conditional.php',
7
+ 'WPCF_Editor' => WPCF_ABSPATH . '/embedded/classes/editor.php',
8
+ 'WPCF_Evaluate' => WPCF_ABSPATH . '/embedded/classes/evaluate.php',
9
+ 'WPCF_Field_Accessor_Abstract' => WPCF_ABSPATH . '/embedded/classes/field/accessor/abstract.php',
10
+ 'WPCF_Field_Accessor_Dummy' => WPCF_ABSPATH . '/embedded/classes/field/accessor/dummy.php',
11
+ 'WPCF_Field_Accessor_Termmeta' => WPCF_ABSPATH . '/embedded/classes/field/accessor/termmeta.php',
12
+ 'WPCF_Field_Accessor_Termmeta_Field' => WPCF_ABSPATH . '/embedded/classes/field/accessor/termmeta_field.php',
13
+ 'WPCF_Field_Data_Saver' => WPCF_ABSPATH . '/embedded/classes/field/data_saver.php',
14
+ 'WPCF_Field_DataMapper_Abstract' => WPCF_ABSPATH . '/embedded/classes/field/datamapper/abstract.php',
15
+ 'WPCF_Field_DataMapper_Checkbox' => WPCF_ABSPATH . '/embedded/classes/field/datamapper/checkbox.php',
16
+ 'WPCF_Field_DataMapper_Checkboxes' => WPCF_ABSPATH . '/embedded/classes/field/datamapper/checkboxes.php',
17
+ 'WPCF_Field_DataMapper_Identity' => WPCF_ABSPATH . '/embedded/classes/field/datamapper/identity.php',
18
+ 'WPCF_Field_Definition' => WPCF_ABSPATH . '/embedded/classes/field/definition.php',
19
+ 'WPCF_Field_Definition_Abstract' => WPCF_ABSPATH . '/embedded/classes/field/definition_abstract.php',
20
+ 'WPCF_Field_Definition_Factory' => WPCF_ABSPATH . '/embedded/classes/field/definition_factory.php',
21
+ 'WPCF_Field_Definition_Factory_Post' => WPCF_ABSPATH . '/embedded/classes/field/definition_factory_post.php',
22
+ 'WPCF_Field_Definition_Factory_Term' => WPCF_ABSPATH . '/embedded/classes/field/definition_factory_term.php',
23
+ 'WPCF_Field_Definition_Factory_User' => WPCF_ABSPATH . '/embedded/classes/field/definition_factory_user.php',
24
+ 'WPCF_Field_Definition_Generic' => WPCF_ABSPATH . '/embedded/classes/field/definition_generic.php',
25
+ 'WPCF_Field_Definition_Post' => WPCF_ABSPATH . '/embedded/classes/field/definition_post.php',
26
+ 'WPCF_Field_Definition_Term' => WPCF_ABSPATH . '/embedded/classes/field/definition_term.php',
27
+ 'WPCF_Field_Definition_User' => WPCF_ABSPATH . '/embedded/classes/field/definition_user.php',
28
+ 'WPCF_Field_Hooks_API' => WPCF_ABSPATH . '/embedded/classes/field/hooks_api.php',
29
+ 'WPCF_Field_Instance' => WPCF_ABSPATH . '/embedded/classes/field/instance.php',
30
+ 'WPCF_Field_Instance_Abstract' => WPCF_ABSPATH . '/embedded/classes/field/instance_abstract.php',
31
+ 'WPCF_Field_Instance_Term' => WPCF_ABSPATH . '/embedded/classes/field/instance_term.php',
32
+ 'WPCF_Field_Instance_Unsaved' => WPCF_ABSPATH . '/embedded/classes/field/instance_unsaved.php',
33
+ 'WPCF_Field_Option_Checkboxes' => WPCF_ABSPATH . '/embedded/classes/field/option_checkboxes.php',
34
+ 'WPCF_Field_Option_Radio' => WPCF_ABSPATH . '/embedded/classes/field/option_radio.php',
35
+ 'WPCF_Field_Option_Select' => WPCF_ABSPATH . '/embedded/classes/field/option_select.php',
36
+ 'WPCF_Field_Renderer_Abstract' => WPCF_ABSPATH . '/embedded/classes/field/renderer/abstract.php',
37
+ 'WPCF_Field_Renderer_Factory' => WPCF_ABSPATH . '/embedded/classes/field/renderer/factory.php',
38
+ 'WPCF_Field_Renderer_Preview_Address' => WPCF_ABSPATH . '/embedded/classes/field/renderer/preview/address.php',
39
+ 'WPCF_Field_Renderer_Preview_Base' => WPCF_ABSPATH . '/embedded/classes/field/renderer/preview/base.php',
40
+ 'WPCF_Field_Renderer_Preview_Checkbox' => WPCF_ABSPATH . '/embedded/classes/field/renderer/preview/checkbox.php',
41
+ 'WPCF_Field_Renderer_Preview_Checkboxes' => WPCF_ABSPATH . '/embedded/classes/field/renderer/preview/checkboxes.php',
42
+ 'WPCF_Field_Renderer_Preview_Colorpicker' => WPCF_ABSPATH . '/embedded/classes/field/renderer/preview/colorpicker.php',
43
+ 'WPCF_Field_Renderer_Preview_Date' => WPCF_ABSPATH . '/embedded/classes/field/renderer/preview/date.php',
44
+ 'WPCF_Field_Renderer_Preview_File' => WPCF_ABSPATH . '/embedded/classes/field/renderer/preview/file.php',
45
+ 'WPCF_Field_Renderer_Preview_Image' => WPCF_ABSPATH . '/embedded/classes/field/renderer/preview/image.php',
46
+ 'WPCF_Field_Renderer_Preview_Radio' => WPCF_ABSPATH . '/embedded/classes/field/renderer/preview/radio.php',
47
+ 'WPCF_Field_Renderer_Preview_Skype' => WPCF_ABSPATH . '/embedded/classes/field/renderer/preview/skype.php',
48
+ 'WPCF_Field_Renderer_Preview_Textfield' => WPCF_ABSPATH . '/embedded/classes/field/renderer/preview/textfield.php',
49
+ 'WPCF_Field_Renderer_Preview_URL' => WPCF_ABSPATH . '/embedded/classes/field/renderer/preview/url.php',
50
+ 'WPCF_Field_Renderer_Toolset_Forms' => WPCF_ABSPATH . '/embedded/classes/field/renderer/toolset_forms.php',
51
+ 'WPCF_Field' => WPCF_ABSPATH . '/embedded/classes/field.php',
52
+ 'WPCF_Termmeta_Field' => WPCF_ABSPATH . '/embedded/classes/field.php',
53
+ 'WPCF_Fields' => WPCF_ABSPATH . '/embedded/classes/fields.php',
54
+ 'WPCF_GUI_Term_Field_Editing' => WPCF_ABSPATH . '/embedded/classes/gui/term_field_editing.php',
55
+ 'WPCF_Helper_Ajax' => WPCF_ABSPATH . '/embedded/classes/helper.ajax.php',
56
+ 'WPCF_Loader' => WPCF_ABSPATH . '/embedded/classes/loader.php',
57
+ 'WPCF_Path' => WPCF_ABSPATH . '/embedded/classes/path.php',
58
+ 'WPCF_Relationship_Child_Form' => WPCF_ABSPATH . '/embedded/classes/relationship/form-child.php',
59
+ 'WPCF_Relationship' => WPCF_ABSPATH . '/embedded/classes/relationship.php',
60
+ 'WPCF_Repeater' => WPCF_ABSPATH . '/embedded/classes/repeater.php',
61
+ 'WPCF_Termmeta_Repeater' => WPCF_ABSPATH . '/embedded/classes/repeater.php',
62
+ 'WPCF_Usermeta_Field' => WPCF_ABSPATH . '/embedded/classes/usermeta_field.php',
63
+ 'WPCF_Usermeta_Repeater' => WPCF_ABSPATH . '/embedded/classes/usermeta_repeater.php',
64
+ 'Wpcf_Cake_Validation' => WPCF_ABSPATH . '/embedded/classes/validation-cakephp.php',
65
+ 'WPCF_Validation' => WPCF_ABSPATH . '/embedded/classes/validation.php',
66
+ 'WPCF_WPViews' => WPCF_ABSPATH . '/embedded/classes/wpviews.php',
67
+ 'WPCF_Autoloader' => WPCF_ABSPATH . '/embedded/includes/autoloader.php',
68
+ 'Types_Data_Installer' => WPCF_ABSPATH . '/embedded/includes/classes/class.types.data.installer.php',
69
+ 'WPCF_WP_filter_state' => WPCF_ABSPATH . '/embedded/includes/fields/wysiwyg.php',
70
+ 'WPCF_Relationship_Model' => WPCF_ABSPATH . '/embedded/models/relationship.php',
71
+ 'Types_Image_View' => WPCF_ABSPATH . '/embedded/views/image.php',
72
+ 'Types_Image_Utils' => WPCF_ABSPATH . '/embedded/views/image.php',
73
+ 'Types_Image_Model' => WPCF_ABSPATH . '/embedded/views/image.php',
74
+ 'Types_Cache' => WPCF_ABSPATH . '/embedded/views/image.php',
75
+ 'Types_Error' => WPCF_ABSPATH . '/embedded/views/image.php',
76
+ 'Types_Admin_Edit_Custom_Fields_Group' => WPCF_ABSPATH . '/includes/classes/class.types.admin.edit.custom.fields.group.php',
77
+ 'Types_Admin_Edit_Fields' => WPCF_ABSPATH . '/includes/classes/class.types.admin.edit.fields.php',
78
+ 'Types_Admin_Edit_Meta_Fields_Group' => WPCF_ABSPATH . '/includes/classes/class.types.admin.edit.meta.fields.group.php',
79
+ 'Types_Admin_Edit_Post_Type' => WPCF_ABSPATH . '/includes/classes/class.types.admin.edit.post.type.php',
80
+ 'Types_Admin_Edit_Taxonomy' => WPCF_ABSPATH . '/includes/classes/class.types.admin.edit.taxonomy.php',
81
+ 'Types_Admin_Fields' => WPCF_ABSPATH . '/includes/classes/class.types.admin.fields.php',
82
+ 'Types_Admin_Page' => WPCF_ABSPATH . '/includes/classes/class.types.admin.page.php',
83
+ 'Types_Admin_Post_Type' => WPCF_ABSPATH . '/includes/classes/class.types.admin.post-type.php',
84
+ 'Types_Admin_Post_Types_List_Table' => WPCF_ABSPATH . '/includes/classes/class.types.admin.post.types.list.table.php',
85
+ 'Types_Admin_Taxonomies_List_Table' => WPCF_ABSPATH . '/includes/classes/class.types.admin.taxonomies.list.table.php',
86
+ 'Types_Admin_Taxonomies' => WPCF_ABSPATH . '/includes/classes/class.types.admin.taxonomies.php',
87
+ 'Types_Admin_Usermeta_Groups_List_Table' => WPCF_ABSPATH . '/includes/classes/class.types.admin.usermeta.groups.list.table.php',
88
+ 'Types_Admin_Usermeta_Control_Table' => WPCF_ABSPATH . '/includes/classes/class.types.admin.usermeta.table.php',
89
+ 'Types_Fields_Conditional' => WPCF_ABSPATH . '/includes/classes/class.types.fields.conditional.php',
90
+ 'WPCF_Custom_Fields_List_Table' => WPCF_ABSPATH . '/includes/classes/class.wpcf.custom.fields.list.table.php',
91
+ 'WPCF_Types_Marketing_Messages' => WPCF_ABSPATH . '/includes/classes/class.wpcf.marketing.messages.php',
92
+ 'WPCF_Types_Marketing' => WPCF_ABSPATH . '/includes/classes/class.wpcf.marketing.php',
93
+ 'WPCF_Roles' => WPCF_ABSPATH . '/includes/classes/class.wpcf.roles.php',
94
+ 'WPCF_Page_Abstract' => WPCF_ABSPATH . '/includes/classes/page/abstract.php',
95
+ 'WPCF_Page_Edit_Termmeta' => WPCF_ABSPATH . '/includes/classes/page/edit/termmeta.php',
96
+ 'WPCF_Page_Edit_Termmeta_Form' => WPCF_ABSPATH . '/includes/classes/page/edit/termmeta_form.php',
97
+ 'WPCF_Page_Listing_Abstract' => WPCF_ABSPATH . '/includes/classes/page/listing/abstract.php',
98
+ 'WPCF_Page_Listing_Table' => WPCF_ABSPATH . '/includes/classes/page/listing/table.php',
99
+ 'WPCF_Page_Listing_Termmeta' => WPCF_ABSPATH . '/includes/classes/page/listing/termmeta.php',
100
+ 'WPCF_Page_Listing_Termmeta_Table' => WPCF_ABSPATH . '/includes/classes/page/listing/termmeta_table.php',
101
+ );
library/toolset/types/embedded/includes/fields-post.php CHANGED
@@ -246,10 +246,11 @@ function wpcf_add_meta_boxes( $post_type, $post )
246
  /**
247
  * Renders meta box content (preview).
248
  *
 
 
 
249
  *
250
- *
251
- * @param type $post
252
- * @param type $group
253
  */
254
  function wpcf_admin_post_meta_box_preview( $post, $group, $echo = '' ){
255
 
@@ -257,22 +258,17 @@ function wpcf_admin_post_meta_box_preview( $post, $group, $echo = '' ){
257
  require_once WPCF_EMBEDDED_ABSPATH . '/frontend.php';
258
  global $wpcf;
259
 
260
- if ( isset( $group['args'] ) ) {
261
- $fields = $group['args']['fields'];
262
- } else {
263
- $fields = $group['fields'];
264
- }
265
- if ( isset( $group['slug'] ) ) {
266
- $slug = $group['slug'];
267
- $name = $group['name'];
268
- } else {
269
- $slug = $group['id'];
270
- $name = $group['title'];
271
- }
272
- /**
273
- * fake post object if need
274
- */
275
- $post = wpcf_admin_create_fake_post_if_need($post);
276
 
277
  $group_output = '';
278
  if ( !empty( $echo ) ) {
@@ -409,53 +405,55 @@ function wpcf_admin_post_meta_box_preview( $post, $group, $echo = '' ){
409
  * @param string $echo
410
  * @param bool $open_style_editor if true use code for open style editor when edit group
411
  *
412
- * @return string
413
  */
414
  function wpcf_admin_post_meta_box( $post, $group, $echo = '', $open_style_editor = false )
415
  {
416
 
417
- $field_group = Types_Field_Group_Post_Factory::load( $group['args']['slug'] );
418
- // todo Handle null $field_group.
419
- $group_wpml = new Types_Wpml_Field_Group( $field_group );
420
 
421
  if (
422
  false === $open_style_editor
423
  && defined( 'WPTOOLSET_FORMS_VERSION' )
 
424
  ) {
425
- if ( isset( $group['args']['html'] ) ) {
426
- /**
427
- * show group description
428
- */
429
- if ( array_key_exists('description', $group['args'] ) && !empty($group['args']['description'])) {
430
- echo '<div class="wpcf-meta-box-description">';
431
- echo wpautop( $group_wpml->translate_description() );
432
- echo '</div>';
433
- }
434
- foreach ( $group['args']['html'] as $field ) {
435
- echo is_array( $field ) ? wptoolset_form_field( 'post',
436
- $field['config'], $field['meta'] ) : $field;
437
- }
438
  }
 
 
 
 
 
439
  return;
440
  }
441
 
442
-
443
-
444
  global $wpcf;
445
- /**
446
- * fake post object if need
447
- */
448
- $post = wpcf_admin_create_fake_post_if_need($post);
449
 
450
  static $nonce_added = false;
451
  $group_output = '';
452
- if ( !isset( $group['title'] ) ) {
 
 
 
453
  $temp = $group;
454
- $group = '';
455
- $group['args'] = $temp;
456
- $group['id'] = $temp['slug'];
457
- $group['title'] = $temp['name'];
458
- $name = $temp['name'];
 
459
  }
460
  if ( !empty( $echo ) ) {
461
  $group_output = '<h3>This Preview generated for latest post "' . $post->post_title . '"</h3>' . "\n" .
@@ -474,7 +472,7 @@ function wpcf_admin_post_meta_box( $post, $group, $echo = '', $open_style_editor
474
  wp_nonce_field( $nonce_action, '_wpcf_post_wpnonce' );
475
  $nonce_added = true;
476
  }
477
- $group_output .= "\n\n" . '<div id="wpcf-group-metabox-id-' . $group['args']['slug'] . '">' . "\n";
478
  /*
479
  * TODO Move to Conditional code
480
  *
246
  /**
247
  * Renders meta box content (preview).
248
  *
249
+ * @param $post
250
+ * @param array $group
251
+ * @param string $echo
252
  *
253
+ * @return string
 
 
254
  */
255
  function wpcf_admin_post_meta_box_preview( $post, $group, $echo = '' ){
256
 
258
  require_once WPCF_EMBEDDED_ABSPATH . '/frontend.php';
259
  global $wpcf;
260
 
261
+ // $group['args']['fields'] or $group['fields'] or array().
262
+ $fields = wpcf_getnest(
263
+ $group,
264
+ array( 'args', 'fields' ),
265
+ wpcf_getarr( $group, 'fields', array() )
266
+ );
267
+
268
+ $slug = wpcf_getarr( $group, 'slug', wpcf_getarr( $group, 'id' ) );
269
+ $name = wpcf_getarr( $group, 'name', wpcf_getarr( $group, 'title' ) );
270
+
271
+ $post = wpcf_admin_create_fake_post_if_need( $post );
 
 
 
 
 
272
 
273
  $group_output = '';
274
  if ( !empty( $echo ) ) {
405
  * @param string $echo
406
  * @param bool $open_style_editor if true use code for open style editor when edit group
407
  *
408
+ * @return string|void
409
  */
410
  function wpcf_admin_post_meta_box( $post, $group, $echo = '', $open_style_editor = false )
411
  {
412
 
413
+ $field_group = Types_Field_Group_Post_Factory::load( wpcf_getnest( $group, array( 'args', 'slug' ) ) );
414
+ // Field group will not exist when we're creating a new one.
415
+ $group_wpml = ( null !== $field_group ) ? new Types_Wpml_Field_Group( $field_group ) : null;
416
 
417
  if (
418
  false === $open_style_editor
419
  && defined( 'WPTOOLSET_FORMS_VERSION' )
420
+ && isset( $group['args']['html'] )
421
  ) {
422
+
423
+ // Show group description if there's something to show.
424
+ $description = wpcf_getnest( $group, array( 'args', 'description' ), '' );
425
+ if ( ! empty( $description ) ) {
426
+ $description = ( null !== $group_wpml ? $group_wpml->translate_description() : $description );
427
+
428
+ echo '<div class="wpcf-meta-box-description">';
429
+ echo wpautop( $description );
430
+ echo '</div>';
 
 
 
 
431
  }
432
+ foreach ( $group['args']['html'] as $field ) {
433
+ echo is_array( $field ) ? wptoolset_form_field( 'post',
434
+ $field['config'], $field['meta'] ) : $field;
435
+ }
436
+
437
  return;
438
  }
439
 
 
 
440
  global $wpcf;
441
+
442
+ $post = wpcf_admin_create_fake_post_if_need( $post );
 
 
443
 
444
  static $nonce_added = false;
445
  $group_output = '';
446
+
447
+ // A compatibility fix, maybe somehow related to user fields, maybe outdated.
448
+ // Beware issues with non-existent (new) groups.
449
+ if ( ! isset( $group['title'] ) ) {
450
  $temp = $group;
451
+ $name = wpcf_getarr( $temp, 'name' );
452
+ $group = array(
453
+ 'args' => $temp,
454
+ 'id' => (int) wpcf_getarr( $temp, 'slug' ),
455
+ 'title' => $name
456
+ );
457
  }
458
  if ( !empty( $echo ) ) {
459
  $group_output = '<h3>This Preview generated for latest post "' . $post->post_title . '"</h3>' . "\n" .
472
  wp_nonce_field( $nonce_action, '_wpcf_post_wpnonce' );
473
  $nonce_added = true;
474
  }
475
+ $group_output .= "\n\n" . '<div id="wpcf-group-metabox-id-' . esc_attr( wpcf_getnest( $group, array( 'args', 'slug' ), 'new-group' ) ) . '">' . "\n";
476
  /*
477
  * TODO Move to Conditional code
478
  *
library/toolset/types/embedded/includes/post-relationship.php CHANGED
@@ -377,95 +377,102 @@ function wpcf_pr_admin_post_meta_box_belongs_form_items_helper( $item )
377
  /**
378
  * Belongs form.
379
  *
380
- * @param type $post
381
- * @param type $post_type
382
- * @param type $data
383
- * @param type $parent_post_type
384
  */
385
- function wpcf_pr_admin_post_meta_box_belongs_form( $post, $type, $belongs )
386
- {
387
- global $wpdb;
388
- $temp_type = get_post_type_object( $type );
389
- if ( empty( $temp_type ) ) {
390
- return array();
391
- }
392
- $form = array();
393
- $id = esc_attr(sprintf('wpcf_pr_belongs_%d_%s', $post->ID, $type));
394
- $belongs_id = isset( $belongs['belongs'][$type] ) ? $belongs['belongs'][$type] : 0;
395
-
396
- $options_array = array();
397
-
398
- $values_to_prepare = array();
399
-
400
- $post_status = array( 'publish', 'private' );
401
-
402
- $wpml_join = $wpml_where = "";
403
- $is_translated_post_type = apply_filters( 'wpml_is_translated_post_type', false, $type );
404
-
405
- if ( $is_translated_post_type ) {
406
- $wpml_current_language = apply_filters( 'wpml_current_language', '' );
407
- $wpml_join = " JOIN {$wpdb->prefix}icl_translations t ";
408
- $wpml_where = " AND p.ID = t.element_id AND t.language_code = %s ";
409
- $values_to_prepare[] = $wpml_current_language;
410
  }
411
-
412
- $values_to_prepare[] = sanitize_text_field( $type );
413
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
414
  $not_in_selected = '';
415
  if ( $belongs_id ) {
416
- $not_in_selected = ' AND p.ID != %d';
417
- $values_to_prepare[] = (int) $belongs_id;
418
  $options_array[ $belongs_id ] = array(
419
  '#title' => get_the_title( $belongs_id ),
420
  '#value' => $belongs_id,
421
  );
422
  } else {
423
- $options_array[ '' ] = array(
424
  '#title' => '',
425
  '#value' => '',
426
  );
427
  }
428
-
429
- $parents_available = $wpdb->get_results(
430
- $wpdb->prepare(
431
- "SELECT p.ID, p.post_title
432
  FROM {$wpdb->posts} p {$wpml_join}
433
- WHERE p.post_status IN ('" . implode( "','" , $post_status ) . "')
434
- {$wpml_where}
435
- AND p.post_type = %s
436
- {$not_in_selected}
 
437
  ORDER BY p.post_date DESC
438
  LIMIT 15",
439
- $values_to_prepare
440
- )
441
  );
442
 
 
 
443
  foreach ( $parents_available as $parent_option ) {
444
  $options_array[ $parent_option->ID ] = array(
445
  '#title' => $parent_option->post_title,
446
  '#value' => $parent_option->ID,
447
  );
448
  }
449
-
450
-
451
- $form[$type] = array(
452
- '#type' => 'select',
453
- '#name' => 'wpcf_pr_belongs[' . $post->ID . '][' . $type . ']',
454
- '#default_value' => $belongs_id,
455
- '#id' => $id,
456
  '#options' => $options_array,
457
- '#attributes' => array(
458
- 'class' => 'wpcf-pr-belongs',
459
- 'data-loading' => esc_attr__('Please Wait, Loading…', 'wpcf'),
460
- 'data-nounce' => wp_create_nonce($id),
461
- 'data-placeholder' => esc_attr( sprintf( __('Search for %s', 'wpcf'), $temp_type->labels->name ) ),
462
- 'data-post-id' => $post->ID,
463
- 'data-post-type' => esc_attr($type),
464
- 'autocomplete' => 'off'
465
- ),
466
- );
467
 
468
- return $form;
469
  }
470
 
471
  /**
@@ -707,83 +714,89 @@ function wpcf_pr_admin_wpcf_relationship_check($keys_to_check = array())
707
  }
708
  }
709
 
710
- function wpcf_pr_admin_wpcf_relationship_search()
711
- {
712
- wpcf_pr_admin_wpcf_relationship_check();
713
-
714
  global $wpdb;
715
- $values_to_prepare = array();
716
-
717
- $posts_per_page = apply_filters( 'wpcf_pr_belongs_post_numberposts', 10 );
718
- $post_type = sanitize_text_field( $_REQUEST['post_type'] );
719
- $post_status = apply_filters( 'wpcf_pr_belongs_post_status', array( 'publish', 'private' ) );
720
-
721
- $wpml_join = $wpml_where = "";
722
- $is_translated_post_type = apply_filters( 'wpml_is_translated_post_type', false, $post_type );
723
-
 
724
  if ( $is_translated_post_type ) {
725
- $wpml_current_language = apply_filters( 'wpml_current_language', '' );
726
- $wpml_join = " JOIN {$wpdb->prefix}icl_translations t ";
727
- $wpml_where = " AND p.ID = t.element_id AND t.language_code = %s ";
728
- $values_to_prepare[] = $wpml_current_language;
 
 
 
 
 
 
 
 
729
  }
730
-
731
- $values_to_prepare[] = sanitize_text_field( $post_type );
732
-
733
- $search_where = "";
734
-
735
- if (
736
- isset( $_REQUEST['s'] )
737
  && $_REQUEST['s'] != ''
738
  ) {
739
  $search_term = "";
740
- if ( method_exists( $wpdb, 'esc_like' ) ) {
741
- $search_term = '%' . $wpdb->esc_like( $_REQUEST['s'] ) . '%';
742
- } else {
743
- $search_term = '%' . like_escape( esc_sql( $_REQUEST['s'] ) ) . '%';
744
  }
745
- $search_where = " AND p.post_title LIKE %s ";
746
- $values_to_prepare[] = $search_term;
747
- $orderby = ' ORDER BY p.post_title ';
748
  } else {
749
- $orderby = ' ORDER BY p.post_date DESC ';
750
  }
751
-
752
- if (
753
- isset( $_REQUEST['page'] )
754
- && preg_match( '/^\d+$/', $_REQUEST['page'] )
755
  ) {
756
- $values_to_prepare[] = ( (int) $_REQUEST['page'] - 1 ) * $posts_per_page;
757
- } else {
758
- $values_to_prepare[] = 0;
759
  }
760
- $values_to_prepare[] = $posts_per_page;
761
-
762
  $parents_available = $wpdb->get_results(
763
  $wpdb->prepare(
764
  "SELECT SQL_CALC_FOUND_ROWS p.ID as id, p.post_title as text, p.post_type as type, p.post_status as status
765
  FROM {$wpdb->posts} p {$wpml_join}
766
- WHERE p.post_status IN ('" . implode( "','" , $post_status ) . "')
767
  {$wpml_where}
768
- AND p.post_type = %s
769
  {$search_where}
770
  {$orderby}
771
  LIMIT %d,%d",
772
  $values_to_prepare
773
  )
774
  );
775
-
776
- $parents_count = $wpdb->get_var('SELECT FOUND_ROWS()');
777
-
778
  $results = array(
779
- 'items' => $parents_available,
780
- 'total_count' => $parents_count,
781
- 'incomplete_results' => $parents_count > $posts_per_page,
782
- 'posts_per_page' => $posts_per_page,
783
  );
784
-
785
- echo json_encode( $results );
786
- die;
787
  }
788
 
789
  // Deprecated since the introduction of select v.4
377
  /**
378
  * Belongs form.
379
  *
380
+ * @param $post
381
+ * @param $type
382
+ * @param $belongs
383
+ * @return array
384
  */
385
+ function wpcf_pr_admin_post_meta_box_belongs_form( $post, $type, $belongs ) {
386
+ global $wpdb;
387
+ $temp_type = get_post_type_object( $type );
388
+ if ( empty( $temp_type ) ) {
389
+ return array();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
390
  }
391
+
392
+ $form = array();
393
+ $id = esc_attr( sprintf( 'wpcf_pr_belongs_%d_%s', $post->ID, $type ) );
394
+ $belongs_id = isset( $belongs['belongs'][ $type ] ) ? $belongs['belongs'][ $type ] : 0;
395
+
396
+ $options_array = array();
397
+
398
+ $values_to_prepare = array();
399
+
400
+ $post_status = array( 'publish', 'private' );
401
+
402
+ $wpml_join = $wpml_where = "";
403
+ $is_translated_post_type = apply_filters( 'wpml_is_translated_post_type', false, $type );
404
+
405
+ if ( $is_translated_post_type ) {
406
+ $wpml_current_language = apply_filters( 'wpml_current_language', '' );
407
+ $wpml_join = " JOIN {$wpdb->prefix}icl_translations t ";
408
+ $wpml_where = " AND p.ID = t.element_id AND t.language_code = %s AND t.element_type = concat( 'post_', %s ) ";
409
+ $values_to_prepare[] = $wpml_current_language;
410
+ $values_to_prepare[] = sanitize_text_field( $type );
411
+
412
+ // This is covered by the element_type condition in $wpml_where
413
+ $where_post_type = '';
414
+ } else {
415
+ // No WPML tables, we just query the post type directly.
416
+ $where_post_type = ' AND p.post_type = %s ';
417
+ $values_to_prepare[] = sanitize_text_field( $type );
418
+ }
419
+
420
  $not_in_selected = '';
421
  if ( $belongs_id ) {
422
+ $not_in_selected = ' AND p.ID != %d';
423
+ $values_to_prepare[] = (int) $belongs_id;
424
  $options_array[ $belongs_id ] = array(
425
  '#title' => get_the_title( $belongs_id ),
426
  '#value' => $belongs_id,
427
  );
428
  } else {
429
+ $options_array[''] = array(
430
  '#title' => '',
431
  '#value' => '',
432
  );
433
  }
434
+
435
+ $sql_query = $wpdb->prepare(
436
+ "SELECT p.ID, p.post_title
 
437
  FROM {$wpdb->posts} p {$wpml_join}
438
+ WHERE
439
+ p.post_status IN ('" . implode( "','", $post_status ) . "')
440
+ {$wpml_where}
441
+ {$where_post_type}
442
+ {$not_in_selected}
443
  ORDER BY p.post_date DESC
444
  LIMIT 15",
445
+ $values_to_prepare
 
446
  );
447
 
448
+ $parents_available = $wpdb->get_results( $sql_query );
449
+
450
  foreach ( $parents_available as $parent_option ) {
451
  $options_array[ $parent_option->ID ] = array(
452
  '#title' => $parent_option->post_title,
453
  '#value' => $parent_option->ID,
454
  );
455
  }
456
+
457
+
458
+ $form[ $type ] = array(
459
+ '#type' => 'select',
460
+ '#name' => 'wpcf_pr_belongs[' . $post->ID . '][' . $type . ']',
461
+ '#default_value' => $belongs_id,
462
+ '#id' => $id,
463
  '#options' => $options_array,
464
+ '#attributes' => array(
465
+ 'class' => 'wpcf-pr-belongs',
466
+ 'data-loading' => esc_attr__( 'Please Wait, Loading…', 'wpcf' ),
467
+ 'data-nounce' => wp_create_nonce( $id ),
468
+ 'data-placeholder' => esc_attr( sprintf( __( 'Search for %s', 'wpcf' ), $temp_type->labels->name ) ),
469
+ 'data-post-id' => $post->ID,
470
+ 'data-post-type' => esc_attr( $type ),
471
+ 'autocomplete' => 'off'
472
+ ),
473
+ );
474
 
475
+ return $form;
476
  }
477
 
478
  /**
714
  }
715
  }
716
 
717
+ function wpcf_pr_admin_wpcf_relationship_search() {
718
+ wpcf_pr_admin_wpcf_relationship_check();
719
+
 
720
  global $wpdb;
721
+ $values_to_prepare = array();
722
+
723
+ $posts_per_page = apply_filters( 'wpcf_pr_belongs_post_numberposts', 10 );
724
+ $post_type = sanitize_text_field( $_REQUEST['post_type'] );
725
+ $post_status = apply_filters( 'wpcf_pr_belongs_post_status', array( 'publish', 'private' ) );
726
+
727
+ $wpml_join = $wpml_where = "";
728
+ $is_translated_post_type = apply_filters( 'wpml_is_translated_post_type', false, $post_type );
729
+
730
+ // TODO Almost the same query is in wpcf_pr_admin_post_meta_box_belongs_form(), DRY.
731
  if ( $is_translated_post_type ) {
732
+ $wpml_current_language = apply_filters( 'wpml_current_language', '' );
733
+ $wpml_join = " JOIN {$wpdb->prefix}icl_translations t ";
734
+ $wpml_where = " AND p.ID = t.element_id AND t.language_code = %s AND t.element_type = concat( 'post_', %s ) ";
735
+ $values_to_prepare[] = $wpml_current_language;
736
+ $values_to_prepare[] = $post_type;
737
+
738
+ // This is covered by the element_type condition in $wpml_where
739
+ $where_post_type = '';
740
+ } else {
741
+ // No WPML tables, we just query the post type directly.
742
+ $where_post_type = ' AND p.post_type = %s ';
743
+ $values_to_prepare[] = $post_type;
744
  }
745
+
746
+ $search_where = "";
747
+
748
+ if (
749
+ isset( $_REQUEST['s'] )
 
 
750
  && $_REQUEST['s'] != ''
751
  ) {
752
  $search_term = "";
753
+ if ( method_exists( $wpdb, 'esc_like' ) ) {
754
+ $search_term = '%' . $wpdb->esc_like( $_REQUEST['s'] ) . '%';
755
+ } else {
756
+ $search_term = '%' . like_escape( esc_sql( $_REQUEST['s'] ) ) . '%';
757
  }
758
+ $search_where = " AND p.post_title LIKE %s ";
759
+ $values_to_prepare[] = $search_term;
760
+ $orderby = ' ORDER BY p.post_title ';
761
  } else {
762
+ $orderby = ' ORDER BY p.post_date DESC ';
763
  }
764
+
765
+ if (
766
+ isset( $_REQUEST['page'] )
767
+ && preg_match( '/^\d+$/', $_REQUEST['page'] )
768
  ) {
769
+ $values_to_prepare[] = ( (int) $_REQUEST['page'] - 1 ) * $posts_per_page;
770
+ } else {
771
+ $values_to_prepare[] = 0;
772
  }
773
+ $values_to_prepare[] = $posts_per_page;
774
+
775
  $parents_available = $wpdb->get_results(
776
  $wpdb->prepare(
777
  "SELECT SQL_CALC_FOUND_ROWS p.ID as id, p.post_title as text, p.post_type as type, p.post_status as status
778
  FROM {$wpdb->posts} p {$wpml_join}
779
+ WHERE p.post_status IN ('" . implode( "','", $post_status ) . "')
780
  {$wpml_where}
781
+ {$where_post_type}
782
  {$search_where}
783
  {$orderby}
784
  LIMIT %d,%d",
785
  $values_to_prepare
786
  )
787
  );
788
+
789
+ $parents_count = $wpdb->get_var( 'SELECT FOUND_ROWS()' );
790
+
791
  $results = array(
792
+ 'items' => $parents_available,
793
+ 'total_count' => $parents_count,
794
+ 'incomplete_results' => $parents_count > $posts_per_page,
795
+ 'posts_per_page' => $posts_per_page,
796
  );
797
+
798
+ echo json_encode( $results );
799
+ die;
800
  }
801
 
802
  // Deprecated since the introduction of select v.4
library/toolset/types/embedded/resources/js/custom-fields-form-filter.js CHANGED
@@ -394,11 +394,7 @@ function wpcfFilterCancelClick(object, edit, title, title_not_empty, title_empty
394
  .attr('checked', 'checked');
395
  }
396
  }
397
- /*
398
- *
399
- *
400
- * Set title
401
- */
402
  if (window.wpcfTaxText.length > 0) {
403
  title_not_empty = window.wpcfTaxText.join(', ');
404
  parent.find('.wpcf-filter-ajax-response').html(
@@ -409,16 +405,7 @@ function wpcfFilterCancelClick(object, edit, title, title_not_empty, title_empty
409
  _wpcfFilterTitle('empty', title, title_not_empty, title_empty)
410
  );
411
  }
412
- /*
413
- *
414
- *
415
- *
416
- *
417
- *
418
- *
419
- *
420
- * Do templates
421
- */
422
  } else if (edit == 'templates') {
423
  toggle.slideUp().find('input').removeAttr('checked');
424
  if (window.wpcfFormGroupsTemplatesState.length > 0) {
@@ -435,13 +422,15 @@ function wpcfFilterCancelClick(object, edit, title, title_not_empty, title_empty
435
  parent.find('.wpcf-filter-ajax-response')
436
  .html(_wpcfFilterTitle('empty', title, title_not_empty, title_empty));
437
  }
438
- }
439
- // Do admin styles
440
- else if (edit == 'admin_styles') {
441
- jQuery("#wpcf-admin-styles-box").css({width:'400px','border-color':'#dfdfdf','box-shadow':'none','z-index':'0'});
442
- jQuery('html, body').animate({scrollTop:jQuery('#wpcf-admin-styles-box').position().top}, 'fast');
443
- CSSLayoutEditor.setValue( typesBase64.decode(wpcfDefaultCss) );
444
- toggle.slideUp();
 
 
445
  }
446
 
447
  parent.children('a').css('visibility', 'visible');
394
  .attr('checked', 'checked');
395
  }
396
  }
397
+ // Set title
 
 
 
 
398
  if (window.wpcfTaxText.length > 0) {
399
  title_not_empty = window.wpcfTaxText.join(', ');
400
  parent.find('.wpcf-filter-ajax-response').html(
405
  _wpcfFilterTitle('empty', title, title_not_empty, title_empty)
406
  );
407
  }
408
+ // Do templates
 
 
 
 
 
 
 
 
 
409
  } else if (edit == 'templates') {
410
  toggle.slideUp().find('input').removeAttr('checked');
411
  if (window.wpcfFormGroupsTemplatesState.length > 0) {
422
  parent.find('.wpcf-filter-ajax-response')
423
  .html(_wpcfFilterTitle('empty', title, title_not_empty, title_empty));
424
  }
425
+ } else if (edit == 'admin_styles') {
426
+
427
+ // Close the Styling editor and slide up
428
+ var stylingEditorBox = jQuery('#wpcf-admin-styles-box, #types_styling_editor');
429
+ if(stylingEditorBox.length) {
430
+ jQuery('html, body').animate({scrollTop:stylingEditorBox.position().top}, 'fast');
431
+ CSSLayoutEditor.setValue(typesBase64.decode(wpcfDefaultCss));
432
+ toggle.slideUp();
433
+ }
434
  }
435
 
436
  parent.children('a').css('visibility', 'visible');
library/toolset/types/includes/classes/class.types.admin.edit.custom.fields.group.php CHANGED
@@ -673,7 +673,7 @@ class Types_Admin_Edit_Custom_Fields_Group extends Types_Admin_Edit_Fields {
673
  }
674
  $preview_profile = wpcf_admin_post_meta_box_preview( $post, $this->update, 1 );
675
  $group = $this->update;
676
- $group['fields'] = wpcf_admin_post_process_fields( $post, $group['fields'], true, false );
677
  $edit_profile = wpcf_admin_post_meta_box( $post, $group, 1, true );
678
  add_action( 'admin_enqueue_scripts', 'wpcf_admin_fields_form_fix_styles', PHP_INT_MAX );
679
  }
673
  }
674
  $preview_profile = wpcf_admin_post_meta_box_preview( $post, $this->update, 1 );
675
  $group = $this->update;
676
+ $group['fields'] = wpcf_admin_post_process_fields( $post, wpcf_getarr( $group, 'fields', array() ), true, false );
677
  $edit_profile = wpcf_admin_post_meta_box( $post, $group, 1, true );
678
  add_action( 'admin_enqueue_scripts', 'wpcf_admin_fields_form_fix_styles', PHP_INT_MAX );
679
  }
library/toolset/types/phpunit.xml.dist ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <phpunit
2
+ bootstrap="tests/bootstrap.php"
3
+ backupGlobals="false"
4
+ colors="true"
5
+ convertErrorsToExceptions="true"
6
+ convertNoticesToExceptions="true"
7
+ convertWarningsToExceptions="true"
8
+ >
9
+ <testsuites>
10
+ <testsuite>
11
+ <directory prefix="test-" suffix=".php">./tests/</directory>
12
+ </testsuite>
13
+ </testsuites>
14
+ </phpunit>
library/twig/twig/.editorconfig ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ; top-most EditorConfig file
2
+ root = true
3
+
4
+ ; Unix-style newlines
5
+ [*]
6
+ end_of_line = LF
7
+
8
+ [*.php]
9
+ indent_style = space
10
+ indent_size = 4
11
+
12
+ [*.test]
13
+ indent_style = space
14
+ indent_size = 4
15
+
16
+ [*.rst]
17
+ indent_style = space
18
+ indent_size = 4
library/twig/twig/.gitignore ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
1
+ /build
2
+ /composer.lock
3
+ /ext/twig/autom4te.cache/
4
+ /phpunit.xml
5
+ /vendor
library/twig/twig/.php_cs.dist ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ return PhpCsFixer\Config::create()
4
+ ->setRules(array(
5
+ '@Symfony' => true,
6
+ '@Symfony:risky' => true,
7
+ 'array_syntax' => array('syntax' => 'long'),
8
+ 'php_unit_fqcn_annotation' => false,
9
+ 'no_unreachable_default_argument_value' => false,
10
+ 'braces' => array('allow_single_line_closure' => true),
11
+ 'heredoc_to_nowdoc' => false,
12
+ ))
13
+ ->setRiskyAllowed(true)
14
+ ->setFinder(PhpCsFixer\Finder::create()->in(__DIR__))
15
+ ;
library/twig/twig/.travis.yml ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ language: php
2
+
3
+ sudo: false
4
+
5
+ cache:
6
+ directories:
7
+ - vendor
8
+ - $HOME/.composer/cache/files
9
+
10
+ php:
11
+ - 5.2
12
+ - 5.3
13
+ - 5.4
14
+ - 5.5
15
+ - 5.6
16
+ - 7.0
17
+ - 7.1
18
+ - hhvm
19
+
20
+ env:
21
+ - TWIG_EXT=no
22
+ - TWIG_EXT=yes
23
+
24
+ before_install:
25
+ - if [[ ! $TRAVIS_PHP_VERSION = hhvm* ]]; then phpenv config-rm xdebug.ini || echo "xdebug not available"; fi
26
+
27
+ install:
28
+ # Composer is not available on PHP 5.2
29
+ - if [ ${TRAVIS_PHP_VERSION:0:3} != "5.2" ]; then travis_retry composer install; fi
30
+
31
+ before_script:
32
+ - if [ "$TWIG_EXT" == "yes" ]; then sh -c "cd ext/twig && phpize && ./configure --enable-twig && make && make install"; fi
33
+ - if [ "$TWIG_EXT" == "yes" ]; then echo "extension=twig.so" >> `php --ini | grep "Loaded Configuration" | sed -e "s|.*:\s*||"`; fi
34
+ - if [ ${TRAVIS_PHP_VERSION:0:3} == "5.2" ]; then sed -i.bak "s|vendor/autoload.php|test/bootstrap.php|" phpunit.xml.dist; fi
35
+
36
+ matrix:
37
+ fast_finish: true
38
+ exclude:
39
+ - php: hhvm
40
+ env: TWIG_EXT=yes
41
+ - php: 7.0
42
+ env: TWIG_EXT=yes
43
+ - php: 7.1
44
+ env: TWIG_EXT=yes
library/twig/twig/CHANGELOG CHANGED
@@ -1,3 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  * 1.28.2 (2016-11-23)
2
 
3
  * fixed precedence between getFoo() and isFoo() in Twig_Template::getAttribute()
1
+ * 1.31.0 (2017-01-11)
2
+
3
+ * added Twig_NodeCaptureInterface for nodes that capture all output
4
+ * fixed marking the environment as initialized too early
5
+ * fixed C89 compat for the C extension
6
+ * turned fatal error into exception when a previously generated cache is corrupted
7
+ * fixed offline cache warm-ups for embedded templates
8
+
9
+ * 1.30.0 (2016-12-23)
10
+
11
+ * added Twig_FactoryRuntimeLoader
12
+ * deprecated function/test/filter/tag overriding
13
+ * deprecated the "disable_c_ext" attribute on Twig_Node_Expression_GetAttr
14
+
15
+ * 1.29.0 (2016-12-13)
16
+
17
+ * fixed sandbox being left enabled if an exception is thrown while rendering
18
+ * marked some classes as being final (via @final)
19
+ * made Twig_Error report real source path when possible
20
+ * added support for {{ _self }} to provide an upgrade path from 1.x to 2.0 (replaces {{ _self.templateName }})
21
+ * deprecated silent display of undefined blocks
22
+ * deprecated support for mbstring.func_overload != 0
23
+
24
  * 1.28.2 (2016-11-23)
25
 
26
  * fixed precedence between getFoo() and isFoo() in Twig_Template::getAttribute()
library/twig/twig/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2009-2016 by the Twig Team.
2
 
3
  Some rights reserved.
4
 
1
+ Copyright (c) 2009-2017 by the Twig Team.
2
 
3
  Some rights reserved.
4
 
library/twig/twig/composer.json ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "twig/twig",
3
+ "type": "library",
4
+ "description": "Twig, the flexible, fast, and secure template language for PHP",
5
+ "keywords": ["templating"],
6
+ "homepage": "http://twig.sensiolabs.org",
7
+ "license": "BSD-3-Clause",
8
+ "authors": [
9
+ {
10
+ "name": "Fabien Potencier",
11
+ "email": "fabien@symfony.com",
12
+ "homepage": "http://fabien.potencier.org",
13
+ "role": "Lead Developer"
14
+ },
15
+ {
16
+ "name": "Twig Team",
17
+ "homepage": "http://twig.sensiolabs.org/contributors",
18
+ "role": "Contributors"
19
+ },
20
+ {
21
+ "name": "Armin Ronacher",
22
+ "email": "armin.ronacher@active-4.com",
23
+ "role": "Project Founder"
24
+ }
25
+ ],
26
+ "support": {
27
+ "forum": "https://groups.google.com/forum/#!forum/twig-users"
28
+ },
29
+ "require": {
30
+ "php": ">=5.2.7"
31
+ },
32
+ "require-dev": {
33
+ "symfony/phpunit-bridge": "~3.2",
34
+ "symfony/debug": "~2.7"
35
+ },
36
+ "autoload": {
37
+ "psr-0" : {
38
+ "Twig_" : "lib/"
39
+ }
40
+ },
41
+ "extra": {
42
+ "branch-alias": {
43
+ "dev-master": "1.31-dev"
44
+ }
45
+ }
46
+ }
library/twig/twig/doc/advanced.rst ADDED
@@ -0,0 +1,957 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Extending Twig
2
+ ==============
3
+
4
+ .. caution::
5
+
6
+ This section describes how to extend Twig as of **Twig 1.12**. If you are
7
+ using an older version, read the :doc:`legacy<advanced_legacy>` chapter
8
+ instead.
9
+
10
+ Twig can be extended in many ways; you can add extra tags, filters, tests,
11
+ operators, global variables, and functions. You can even extend the parser
12
+ itself with node visitors.
13
+
14
+ .. note::
15
+
16
+ The first section of this chapter describes how to extend Twig easily. If
17
+ you want to reuse your changes in different projects or if you want to
18
+ share them with others, you should then create an extension as described
19
+ in the following section.
20
+
21
+ .. caution::
22
+
23
+ When extending Twig without creating an extension, Twig won't be able to
24
+ recompile your templates when the PHP code is updated. To see your changes
25
+ in real-time, either disable template caching or package your code into an
26
+ extension (see the next section of this chapter).
27
+
28
+ Before extending Twig, you must understand the differences between all the
29
+ different possible extension points and when to use them.
30
+
31
+ First, remember that Twig has two main language constructs:
32
+
33
+ * ``{{ }}``: used to print the result of an expression evaluation;
34
+
35
+ * ``{% %}``: used to execute statements.
36
+
37
+ To understand why Twig exposes so many extension points, let's see how to
38
+ implement a *Lorem ipsum* generator (it needs to know the number of words to
39
+ generate).
40
+
41
+ You can use a ``lipsum`` *tag*:
42
+
43
+ .. code-block:: jinja
44
+
45
+ {% lipsum 40 %}
46
+
47
+ That works, but using a tag for ``lipsum`` is not a good idea for at least
48
+ three main reasons:
49
+
50
+ * ``lipsum`` is not a language construct;
51
+ * The tag outputs something;
52
+ * The tag is not flexible as you cannot use it in an expression:
53
+
54
+ .. code-block:: jinja
55
+
56
+ {{ 'some text' ~ {% lipsum 40 %} ~ 'some more text' }}
57
+
58
+ In fact, you rarely need to create tags; and that's good news because tags are
59
+ the most complex extension point of Twig.
60
+
61
+ Now, let's use a ``lipsum`` *filter*:
62
+
63
+ .. code-block:: jinja
64
+
65
+ {{ 40|lipsum }}
66
+
67
+ Again, it works, but it looks weird. A filter transforms the passed value to
68
+ something else but here we use the value to indicate the number of words to
69
+ generate (so, ``40`` is an argument of the filter, not the value we want to
70
+ transform).
71
+
72
+ Next, let's use a ``lipsum`` *function*:
73
+
74
+ .. code-block:: jinja
75
+
76
+ {{ lipsum(40) }}
77
+
78
+ Here we go. For this specific example, the creation of a function is the
79
+ extension point to use. And you can use it anywhere an expression is accepted:
80
+
81
+ .. code-block:: jinja
82
+
83
+ {{ 'some text' ~ lipsum(40) ~ 'some more text' }}
84
+
85
+ {% set lipsum = lipsum(40) %}
86
+
87
+ Last but not the least, you can also use a *global* object with a method able
88
+ to generate lorem ipsum text:
89
+
90
+ .. code-block:: jinja
91
+
92
+ {{ text.lipsum(40) }}
93
+
94
+ As a rule of thumb, use functions for frequently used features and global
95
+ objects for everything else.
96
+
97
+ Keep in mind the following when you want to extend Twig:
98
+
99
+ ========== ========================== ========== =========================
100
+ What? Implementation difficulty? How often? When?
101
+ ========== ========================== ========== =========================
102
+ *macro* trivial frequent Content generation
103
+ *global* trivial frequent Helper object
104
+ *function* trivial frequent Content generation
105
+ *filter* trivial frequent Value transformation
106
+ *tag* complex rare DSL language construct
107
+ *test* trivial rare Boolean decision
108
+ *operator* trivial rare Values transformation
109
+ ========== ========================== ========== =========================
110
+
111
+ Globals
112
+ -------
113
+
114
+ A global variable is like any other template variable, except that it's
115
+ available in all templates and macros::
116
+
117
+ $twig = new Twig_Environment($loader);
118
+ $twig->addGlobal('text', new Text());
119
+
120
+ You can then use the ``text`` variable anywhere in a template:
121
+
122
+ .. code-block:: jinja
123
+
124
+ {{ text.lipsum(40) }}
125
+
126
+ Filters
127
+ -------
128
+
129
+ Creating a filter is as simple as associating a name with a PHP callable::
130
+
131
+ // an anonymous function
132
+ $filter = new Twig_SimpleFilter('rot13', function ($string) {
133
+ return str_rot13($string);
134
+ });
135
+
136
+ // or a simple PHP function
137
+ $filter = new Twig_SimpleFilter('rot13', 'str_rot13');
138
+
139
+ // or a class static method
140
+ $filter = new Twig_SimpleFilter('rot13', array('SomeClass', 'rot13Filter'));
141
+ $filter = new Twig_SimpleFilter('rot13', 'SomeClass::rot13Filter');
142
+
143
+ // or a class method
144
+ $filter = new Twig_SimpleFilter('rot13', array($this, 'rot13Filter'));
145
+ // the one below needs a runtime implementation (see below for more information)
146
+ $filter = new Twig_SimpleFilter('rot13', array('SomeClass', 'rot13Filter'));
147
+
148
+ The first argument passed to the ``Twig_SimpleFilter`` constructor is the name
149
+ of the filter you will use in templates and the second one is the PHP callable
150
+ to associate with it.
151
+
152
+ Then, add the filter to your Twig environment::
153
+
154
+ $twig = new Twig_Environment($loader);
155
+ $twig->addFilter($filter);
156
+
157
+ And here is how to use it in a template:
158
+
159
+ .. code-block:: jinja
160
+
161
+ {{ 'Twig'|rot13 }}
162
+
163
+ {# will output Gjvt #}
164
+
165
+ When called by Twig, the PHP callable receives the left side of the filter
166
+ (before the pipe ``|``) as the first argument and the extra arguments passed
167
+ to the filter (within parentheses ``()``) as extra arguments.
168
+
169
+ For instance, the following code:
170
+
171
+ .. code-block:: jinja
172
+
173
+ {{ 'TWIG'|lower }}
174
+ {{ now|date('d/m/Y') }}
175
+
176
+ is compiled to something like the following::
177
+
178
+ <?php echo strtolower('TWIG') ?>
179
+ <?php echo twig_date_format_filter($now, 'd/m/Y') ?>
180
+
181
+ The ``Twig_SimpleFilter`` class takes an array of options as its last
182
+ argument::
183
+
184
+ $filter = new Twig_SimpleFilter('rot13', 'str_rot13', $options);
185
+
186
+ Environment-aware Filters
187
+ ~~~~~~~~~~~~~~~~~~~~~~~~~
188
+
189
+ If you want to access the current environment instance in your filter, set the
190
+ ``needs_environment`` option to ``true``; Twig will pass the current
191
+ environment as the first argument to the filter call::
192
+
193
+ $filter = new Twig_SimpleFilter('rot13', function (Twig_Environment $env, $string) {
194
+ // get the current charset for instance
195
+ $charset = $env->getCharset();
196
+
197
+ return str_rot13($string);
198
+ }, array('needs_environment' => true));
199
+
200
+ Context-aware Filters
201
+ ~~~~~~~~~~~~~~~~~~~~~
202
+
203
+ If you want to access the current context in your filter, set the
204
+ ``needs_context`` option to ``true``; Twig will pass the current context as
205
+ the first argument to the filter call (or the second one if
206
+ ``needs_environment`` is also set to ``true``)::
207
+
208
+ $filter = new Twig_SimpleFilter('rot13', function ($context, $string) {
209
+ // ...
210
+ }, array('needs_context' => true));
211
+
212
+ $filter = new Twig_SimpleFilter('rot13', function (Twig_Environment $env, $context, $string) {
213
+ // ...
214
+ }, array('needs_context' => true, 'needs_environment' => true));
215
+
216
+ Automatic Escaping
217
+ ~~~~~~~~~~~~~~~~~~
218
+
219
+ If automatic escaping is enabled, the output of the filter may be escaped
220
+ before printing. If your filter acts as an escaper (or explicitly outputs HTML
221
+ or JavaScript code), you will want the raw output to be printed. In such a
222
+ case, set the ``is_safe`` option::
223
+
224
+ $filter = new Twig_SimpleFilter('nl2br', 'nl2br', array('is_safe' => array('html')));
225
+
226
+ Some filters may need to work on input that is already escaped or safe, for
227
+ example when adding (safe) HTML tags to originally unsafe output. In such a
228
+ case, set the ``pre_escape`` option to escape the input data before it is run
229
+ through your filter::
230
+
231
+ $filter = new Twig_SimpleFilter('somefilter', 'somefilter', array('pre_escape' => 'html', 'is_safe' => array('html')));
232
+
233
+ Variadic Filters
234
+ ~~~~~~~~~~~~~~~~
235
+
236
+ .. versionadded:: 1.19
237
+ Support for variadic filters was added in Twig 1.19.
238
+
239
+ When a filter should accept an arbitrary number of arguments, set the
240
+ ``is_variadic`` option to ``true``; Twig will pass the extra arguments as the
241
+ last argument to the filter call as an array::
242
+
243
+ $filter = new Twig_SimpleFilter('thumbnail', function ($file, array $options = array()) {
244
+ // ...
245
+ }, array('is_variadic' => true));
246
+
247
+ Be warned that named arguments passed to a variadic filter cannot be checked
248
+ for validity as they will automatically end up in the option array.
249
+
250
+ Dynamic Filters
251
+ ~~~~~~~~~~~~~~~
252
+
253
+ A filter name containing the special ``*`` character is a dynamic filter as
254
+ the ``*`` can be any string::
255
+
256
+ $filter = new Twig_SimpleFilter('*_path', function ($name, $arguments) {
257
+ // ...
258
+ });
259
+
260
+ The following filters will be matched by the above defined dynamic filter:
261
+
262
+ * ``product_path``
263
+ * ``category_path``
264
+
265
+ A dynamic filter can define more than one dynamic parts::
266
+
267
+ $filter = new Twig_SimpleFilter('*_path_*', function ($name, $suffix, $arguments) {
268
+ // ...
269
+ });
270
+
271
+ The filter will receive all dynamic part values before the normal filter
272
+ arguments, but after the environment and the context. For instance, a call to
273
+ ``'foo'|a_path_b()`` will result in the following arguments to be passed to
274
+ the filter: ``('a', 'b', 'foo')``.
275
+
276
+ Deprecated Filters
277
+ ~~~~~~~~~~~~~~~~~~
278
+
279
+ .. versionadded:: 1.21
280
+ Support for deprecated filters was added in Twig 1.21.
281
+
282
+ You can mark a filter as being deprecated by setting the ``deprecated`` option
283
+ to ``true``. You can also give an alternative filter that replaces the
284
+ deprecated one when that makes sense::
285
+
286
+ $filter = new Twig_SimpleFilter('obsolete', function () {
287
+ // ...
288
+ }, array('deprecated' => true, 'alternative' => 'new_one'));
289
+
290
+ When a filter is deprecated, Twig emits a deprecation notice when compiling a
291
+ template using it. See :ref:`deprecation-notices` for more information.
292
+
293
+ Functions
294
+ ---------
295
+
296
+ Functions are defined in the exact same way as filters, but you need to create
297
+ an instance of ``Twig_SimpleFunction``::
298
+
299
+ $twig = new Twig_Environment($loader);
300
+ $function = new Twig_SimpleFunction('function_name', function () {
301
+ // ...
302
+ });
303
+ $twig->addFunction($function);
304
+
305
+ Functions support the same features as filters, except for the ``pre_escape``
306
+ and ``preserves_safety`` options.
307
+
308
+ Tests
309
+ -----
310
+
311
+ Tests are defined in the exact same way as filters and functions, but you need
312
+ to create an instance of ``Twig_SimpleTest``::
313
+
314
+ $twig = new Twig_Environment($loader);
315
+ $test = new Twig_SimpleTest('test_name', function () {
316
+ // ...
317
+ });
318
+ $twig->addTest($test);
319
+
320
+ Tests allow you to create custom application specific logic for evaluating
321
+ boolean conditions. As a simple example, let's create a Twig test that checks if
322
+ objects are 'red'::
323
+
324
+ $twig = new Twig_Environment($loader);
325
+ $test = new Twig_SimpleTest('red', function ($value) {
326
+ if (isset($value->color) && $value->color == 'red') {
327
+ return true;
328
+ }
329
+ if (isset($value->paint) && $value->paint == 'red') {
330
+ return true;
331
+ }
332
+ return false;
333
+ });
334
+ $twig->addTest($test);
335
+
336
+ Test functions should always return true/false.
337
+
338
+ When creating tests you can use the ``node_class`` option to provide custom test
339
+ compilation. This is useful if your test can be compiled into PHP primitives.
340
+ This is used by many of the tests built into Twig::
341
+
342
+ $twig = new Twig_Environment($loader);
343
+ $test = new Twig_SimpleTest(
344
+ 'odd',
345
+ null,
346
+ array('node_class' => 'Twig_Node_Expression_Test_Odd'));
347
+ $twig->addTest($test);
348
+
349
+ class Twig_Node_Expression_Test_Odd extends Twig_Node_Expression_Test
350
+ {
351
+ public function compile(Twig_Compiler $compiler)
352
+ {
353
+ $compiler
354
+ ->raw('(')
355
+ ->subcompile($this->getNode('node'))
356
+ ->raw(' % 2 == 1')
357
+ ->raw(')')
358
+ ;
359
+ }
360
+ }
361
+
362
+ The above example shows how you can create tests that use a node class. The
363
+ node class has access to one sub-node called 'node'. This sub-node contains the
364
+ value that is being tested. When the ``odd`` filter is used in code such as:
365
+
366
+ .. code-block:: jinja
367
+
368
+ {% if my_value is odd %}
369
+
370
+ The ``node`` sub-node will contain an expression of ``my_value``. Node-based
371
+ tests also have access to the ``arguments`` node. This node will contain the
372
+ various other arguments that have been provided to your test.
373
+
374
+ If you want to pass a variable number of positional or named arguments to the
375
+ test, set the ``is_variadic`` option to ``true``. Tests also support dynamic
376
+ name feature as filters and functions.
377
+
378
+ Tags
379
+ ----
380
+
381
+ One of the most exciting features of a template engine like Twig is the
382
+ possibility to define new language constructs. This is also the most complex
383
+ feature as you need to understand how Twig's internals work.
384
+
385
+ Let's create a simple ``set`` tag that allows the definition of simple
386
+ variables from within a template. The tag can be used like follows:
387
+
388
+ .. code-block:: jinja
389
+
390
+ {% set name = "value" %}
391
+
392
+ {{ name }}
393
+
394
+ {# should output value #}
395
+
396
+ .. note::
397
+
398
+ The ``set`` tag is part of the Core extension and as such is always
399
+ available. The built-in version is slightly more powerful and supports
400
+ multiple assignments by default (cf. the template designers chapter for
401
+ more information).
402
+
403
+ Three steps are needed to define a new tag:
404
+
405
+ * Defining a Token Parser class (responsible for parsing the template code);
406
+
407
+ * Defining a Node class (responsible for converting the parsed code to PHP);
408
+
409
+ * Registering the tag.
410
+
411
+ Registering a new tag
412
+ ~~~~~~~~~~~~~~~~~~~~~
413
+
414
+ Adding a tag is as simple as calling the ``addTokenParser`` method on the
415
+ ``Twig_Environment`` instance::
416
+
417
+ $twig = new Twig_Environment($loader);
418
+ $twig->addTokenParser(new Project_Set_TokenParser());
419
+
420
+ Defining a Token Parser
421
+ ~~~~~~~~~~~~~~~~~~~~~~~
422
+
423
+ Now, let's see the actual code of this class::
424
+
425
+ class Project_Set_TokenParser extends Twig_TokenParser
426
+ {
427
+ public function parse(Twig_Token $token)
428
+ {
429
+ $parser = $this->parser;
430
+ $stream = $parser->getStream();
431
+
432
+ $name = $stream->expect(Twig_Token::NAME_TYPE)->getValue();
433
+ $stream->expect(Twig_Token::OPERATOR_TYPE, '=');
434
+ $value = $parser->getExpressionParser()->parseExpression();
435
+ $stream->expect(Twig_Token::BLOCK_END_TYPE);
436
+
437
+ return new Project_Set_Node($name, $value, $token->getLine(), $this->getTag());
438
+ }
439
+
440
+ public function getTag()
441
+ {
442
+ return 'set';
443
+ }
444
+ }
445
+
446
+ The ``getTag()`` method must return the tag we want to parse, here ``set``.
447
+
448
+ The ``parse()`` method is invoked whenever the parser encounters a ``set``
449
+ tag. It should return a ``Twig_Node`` instance that represents the node (the
450
+ ``Project_Set_Node`` calls creating is explained in the next section).
451
+
452
+ The parsing process is simplified thanks to a bunch of methods you can call
453
+ from the token stream (``$this->parser->getStream()``):
454
+
455
+ * ``getCurrent()``: Gets the current token in the stream.
456
+
457
+ * ``next()``: Moves to the next token in the stream, *but returns the old one*.
458
+
459
+ * ``test($type)``, ``test($value)`` or ``test($type, $value)``: Determines whether
460
+ the current token is of a particular type or value (or both). The value may be an
461
+ array of several possible values.
462
+
463
+ * ``expect($type[, $value[, $message]])``: If the current token isn't of the given
464
+ type/value a syntax error is thrown. Otherwise, if the type and value are correct,
465
+ the token is returned and the stream moves to the next token.
466
+
467
+ * ``look()``: Looks a the next token without consuming it.
468
+
469
+ Parsing expressions is done by calling the ``parseExpression()`` like we did for
470
+ the ``set`` tag.
471
+
472
+ .. tip::
473
+
474
+ Reading the existing ``TokenParser`` classes is the best way to learn all
475
+ the nitty-gritty details of the parsing process.
476
+
477
+ Defining a Node
478
+ ~~~~~~~~~~~~~~~
479
+
480
+ The ``Project_Set_Node`` class itself is rather simple::
481
+
482
+ class Project_Set_Node extends Twig_Node
483
+ {
484
+ public function __construct($name, Twig_Node_Expression $value, $line, $tag = null)
485
+ {
486
+ parent::__construct(array('value' => $value), array('name' => $name), $line, $tag);
487
+ }
488
+
489
+ public function compile(Twig_Compiler $compiler)
490
+ {
491
+ $compiler
492
+ ->addDebugInfo($this)
493
+ ->write('$context[\''.$this->getAttribute('name').'\'] = ')
494
+ ->subcompile($this->getNode('value'))
495
+ ->raw(";\n")
496
+ ;
497
+ }
498
+ }
499
+
500
+ The compiler implements a fluid interface and provides methods that helps the
501
+ developer generate beautiful and readable PHP code:
502
+
503
+ * ``subcompile()``: Compiles a node.
504
+
505
+ * ``raw()``: Writes the given string as is.
506
+
507
+ * ``write()``: Writes the given string by adding indentation at the beginning
508
+ of each line.
509
+
510
+ * ``string()``: Writes a quoted string.
511
+
512
+ * ``repr()``: Writes a PHP representation of a given value (see
513
+ ``Twig_Node_For`` for a usage example).
514
+
515
+ * ``addDebugInfo()``: Adds the line of the original template file related to
516
+ the current node as a comment.
517
+
518
+ * ``indent()``: Indents the generated code (see ``Twig_Node_Block`` for a
519
+ usage example).
520
+
521
+ * ``outdent()``: Outdents the generated code (see ``Twig_Node_Block`` for a
522
+ usage example).
523
+
524
+ .. _creating_extensions:
525
+
526
+ Creating an Extension
527
+ ---------------------
528
+
529
+ The main motivation for writing an extension is to move often used code into a
530
+ reusable class like adding support for internationalization. An extension can
531
+ define tags, filters, tests, operators, global variables, functions, and node
532
+ visitors.
533
+
534
+ Most of the time, it is useful to create a single extension for your project,
535
+ to host all the specific tags and filters you want to add to Twig.
536
+
537
+ .. tip::
538
+
539
+ When packaging your code into an extension, Twig is smart enough to
540
+ recompile your templates whenever you make a change to it (when
541
+ ``auto_reload`` is enabled).
542
+
543
+ .. note::
544
+
545
+ Before writing your own extensions, have a look at the Twig official
546
+ extension repository: http://github.com/twigphp/Twig-extensions.
547
+
548
+ An extension is a class that implements the following interface::
549
+
550
+ interface Twig_ExtensionInterface
551
+ {
552
+ /**
553
+ * Initializes the runtime environment.
554
+ *
555
+ * This is where you can load some file that contains filter functions for instance.
556
+ *
557
+ * @deprecated since 1.23 (to be removed in 2.0), implement Twig_Extension_InitRuntimeInterface instead
558
+ */
559
+ function initRuntime(Twig_Environment $environment);
560
+
561
+ /**
562
+ * Returns the token parser instances to add to the existing list.
563
+ *
564
+ * @return (Twig_TokenParserInterface|Twig_TokenParserBrokerInterface)[]
565
+ */
566
+ function getTokenParsers();
567
+
568
+ /**
569
+ * Returns the node visitor instances to add to the existing list.
570
+ *
571
+ * @return Twig_NodeVisitorInterface[]
572
+ */
573
+ function getNodeVisitors();
574
+
575
+ /**
576
+ * Returns a list of filters to add to the existing list.
577
+ *
578
+ * @return Twig_SimpleFilter[]
579
+ */
580
+ function getFilters();
581
+
582
+ /**
583
+ * Returns a list of tests to add to the existing list.
584
+ *
585
+ * @return Twig_SimpleTest[]
586
+ */
587
+ function getTests();
588
+
589
+ /**
590
+ * Returns a list of functions to add to the existing list.
591
+ *
592
+ * @return Twig_SimpleFunction[]
593
+ */
594
+ function getFunctions();
595
+
596
+ /**
597
+ * Returns a list of operators to add to the existing list.
598
+ *
599
+ * @return array<array> First array of unary operators, second array of binary operators
600
+ */
601
+ function getOperators();
602
+
603
+ /**
604
+ * Returns a list of global variables to add to the existing list.
605
+ *
606
+ * @return array An array of global variables
607
+ *
608
+ * @deprecated since 1.23 (to be removed in 2.0), implement Twig_Extension_GlobalsInterface instead
609
+ */
610
+ function getGlobals();
611
+
612
+ /**
613
+ * Returns the name of the extension.
614
+ *
615
+ * @return string The extension name
616
+ *
617
+ * @deprecated since 1.26 (to be removed in 2.0), not used anymore internally
618
+ */
619
+ function getName();
620
+ }
621
+
622
+ To keep your extension class clean and lean, inherit from the built-in
623
+ ``Twig_Extension`` class instead of implementing the interface as it provides
624
+ empty implementations for all methods:
625
+
626
+ class Project_Twig_Extension extends Twig_Extension
627
+ {
628
+ }
629
+
630
+ Of course, this extension does nothing for now. We will customize it in the
631
+ next sections.
632
+
633
+ .. note::
634
+
635
+ Prior to Twig 1.26, you must implement the ``getName()`` method which must
636
+ return a unique identifier for the extension.
637
+
638
+ Twig does not care where you save your extension on the filesystem, as all
639
+ extensions must be registered explicitly to be available in your templates.
640
+
641
+ You can register an extension by using the ``addExtension()`` method on your
642
+ main ``Environment`` object::
643
+
644
+ $twig = new Twig_Environment($loader);
645
+ $twig->addExtension(new Project_Twig_Extension());
646
+
647
+ .. tip::
648
+
649
+ The Twig core extensions are great examples of how extensions work.
650
+
651
+ Globals
652
+ ~~~~~~~
653
+
654
+ Global variables can be registered in an extension via the ``getGlobals()``
655
+ method::
656
+
657
+ class Project_Twig_Extension extends Twig_Extension implements Twig_Extension_GlobalsInterface
658
+ {
659
+ public function getGlobals()
660
+ {
661
+ return array(
662
+ 'text' => new Text(),
663
+ );
664
+ }
665
+
666
+ // ...
667
+ }
668
+
669
+ Functions
670
+ ~~~~~~~~~
671
+
672
+ Functions can be registered in an extension via the ``getFunctions()``
673
+ method::
674
+
675
+ class Project_Twig_Extension extends Twig_Extension
676
+ {
677
+ public function getFunctions()
678
+ {
679
+ return array(
680
+ new Twig_SimpleFunction('lipsum', 'generate_lipsum'),
681
+ );
682
+ }
683
+
684
+ // ...
685
+ }
686
+
687
+ Filters
688
+ ~~~~~~~
689
+
690
+ To add a filter to an extension, you need to override the ``getFilters()``
691
+ method. This method must return an array of filters to add to the Twig
692
+ environment::
693
+
694
+ class Project_Twig_Extension extends Twig_Extension
695
+ {
696
+ public function getFilters()
697
+ {
698
+ return array(
699
+ new Twig_SimpleFilter('rot13', 'str_rot13'),
700
+ );
701
+ }
702
+
703
+ // ...
704
+ }
705
+
706
+ Tags
707
+ ~~~~
708
+
709
+ Adding a tag in an extension can be done by overriding the
710
+ ``getTokenParsers()`` method. This method must return an array of tags to add
711
+ to the Twig environment::
712
+
713
+ class Project_Twig_Extension extends Twig_Extension
714
+ {
715
+ public function getTokenParsers()
716
+ {
717
+ return array(new Project_Set_TokenParser());
718
+ }
719
+
720
+ // ...
721
+ }
722
+
723
+ In the above code, we have added a single new tag, defined by the
724
+ ``Project_Set_TokenParser`` class. The ``Project_Set_TokenParser`` class is
725
+ responsible for parsing the tag and compiling it to PHP.
726
+
727
+ Operators
728
+ ~~~~~~~~~
729
+
730
+ The ``getOperators()`` methods lets you add new operators. Here is how to add
731
+ ``!``, ``||``, and ``&&`` operators::
732
+
733
+ class Project_Twig_Extension extends Twig_Extension
734
+ {
735
+ public function getOperators()
736
+ {
737
+ return array(
738
+ array(
739
+ '!' => array('precedence' => 50, 'class' => 'Twig_Node_Expression_Unary_Not'),
740
+ ),
741
+ array(
742
+ '||' => array('precedence' => 10, 'class' => 'Twig_Node_Expression_Binary_Or', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
743
+ '&&' => array('precedence' => 15, 'class' => 'Twig_Node_Expression_Binary_And', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
744
+ ),
745
+ );
746
+ }
747
+
748
+ // ...
749
+ }
750
+
751
+ Tests
752
+ ~~~~~
753
+
754
+ The ``getTests()`` method lets you add new test functions::
755
+
756
+ class Project_Twig_Extension extends Twig_Extension
757
+ {
758
+ public function getTests()
759
+ {
760
+ return array(
761
+ new Twig_SimpleTest('even', 'twig_test_even'),
762
+ );
763
+ }
764
+
765
+ // ...
766
+ }
767
+
768
+ Definition vs Runtime
769
+ ~~~~~~~~~~~~~~~~~~~~~
770
+
771
+ Twig filters, functions, and tests runtime implementations can be defined as
772
+ any valid PHP callable:
773
+
774
+ * **functions/static methods**: Simple to implement and fast (used by all Twig
775
+ core extensions); but it is hard for the runtime to depend on external
776
+ objects;
777
+
778
+ * **closures**: Simple to implement;
779
+
780
+ * **object methods**: More flexible and required if your runtime code depends
781
+ on external objects.
782
+
783
+ The simplest way to use methods is to define them on the extension itself::
784
+
785
+ class Project_Twig_Extension extends Twig_Extension
786
+ {
787
+ private $rot13Provider;
788
+
789
+ public function __construct($rot13Provider)
790
+ {
791
+ $this->rot13Provider = $rot13Provider;
792
+ }
793
+
794
+ public function getFunctions()
795
+ {
796
+ return array(
797
+ new Twig_SimpleFunction('rot13', array($this, 'rot13')),
798
+ );
799
+ }
800
+
801
+ public function rot13($value)
802
+ {
803
+ return $rot13Provider->rot13($value);
804
+ }
805
+ }
806
+
807
+ This is very convenient but not recommended as it makes template compilation
808
+ depend on runtime dependencies even if they are not needed (think for instance
809
+ as a dependency that connects to a database engine).
810
+
811
+ As of Twig 1.26, you can easily decouple the extension definitions from their
812
+ runtime implementations by registering a ``Twig_RuntimeLoaderInterface``
813
+ instance on the environment that knows how to instantiate such runtime classes
814
+ (runtime classes must be autoload-able)::
815
+
816
+ class RuntimeLoader implements Twig_RuntimeLoaderInterface
817
+ {
818
+ public function load($class)
819
+ {
820
+ // implement the logic to create an instance of $class
821
+ // and inject its dependencies
822
+ // most of the time, it means using your dependency injection container
823
+ if ('Project_Twig_RuntimeExtension' === $class) {
824
+ return new $class(new Rot13Provider());
825
+ } else {
826
+ // ...
827
+ }
828
+ }
829
+ }
830
+
831
+ $twig->addRuntimeLoader(new RuntimeLoader());
832
+
833
+ It is now possible to move the runtime logic to a new
834
+ ``Project_Twig_RuntimeExtension`` class and use it directly in the extension::
835
+
836
+ class Project_Twig_RuntimeExtension extends Twig_Extension
837
+ {
838
+ private $rot13Provider;
839
+
840
+ public function __construct($rot13Provider)
841
+ {
842
+ $this->rot13Provider = $rot13Provider;
843
+ }
844
+
845
+ public function rot13($value)
846
+ {
847
+ return $rot13Provider->rot13($value);
848
+ }
849
+ }
850
+
851
+ class Project_Twig_Extension extends Twig_Extension
852
+ {
853
+ public function getFunctions()
854
+ {
855
+ return array(
856
+ new Twig_SimpleFunction('rot13', array('Project_Twig_RuntimeExtension', 'rot13')),
857
+ // or
858
+ new Twig_SimpleFunction('rot13', 'Project_Twig_RuntimeExtension::rot13'),
859
+ );
860
+ }
861
+ }
862
+
863
+ Overloading
864
+ -----------
865
+
866
+ To overload an already defined filter, test, operator, global variable, or
867
+ function, re-define it in an extension and register it **as late as
868
+ possible** (order matters)::
869
+
870
+ class MyCoreExtension extends Twig_Extension
871
+ {
872
+ public function getFilters()
873
+ {
874
+ return array(
875
+ new Twig_SimpleFilter('date', array($this, 'dateFilter')),
876
+ );
877
+ }
878
+
879
+ public function dateFilter($timestamp, $format = 'F j, Y H:i')
880
+ {
881
+ // do something different from the built-in date filter
882
+ }
883
+ }
884
+
885
+ $twig = new Twig_Environment($loader);
886
+ $twig->addExtension(new MyCoreExtension());
887
+
888
+ Here, we have overloaded the built-in ``date`` filter with a custom one.
889
+
890
+ If you do the same on the ``Twig_Environment`` itself, beware that it takes
891
+ precedence over any other registered extensions::
892
+
893
+ $twig = new Twig_Environment($loader);
894
+ $twig->addFilter(new Twig_SimpleFilter('date', function ($timestamp, $format = 'F j, Y H:i') {
895
+ // do something different from the built-in date filter
896
+ }));
897
+ // the date filter will come from the above registration, not
898
+ // from the registered extension below
899
+ $twig->addExtension(new MyCoreExtension());
900
+
901
+ .. caution::
902
+
903
+ Note that overloading the built-in Twig elements is not recommended as it
904
+ might be confusing.
905
+
906
+ Testing an Extension
907
+ --------------------
908
+
909
+ Functional Tests
910
+ ~~~~~~~~~~~~~~~~
911
+
912
+ You can create functional tests for extensions simply by creating the
913
+ following file structure in your test directory::
914
+
915
+ Fixtures/
916
+ filters/
917
+ foo.test
918
+ bar.test
919
+ functions/
920
+ foo.test
921
+ bar.test
922
+ tags/
923
+ foo.test
924
+ bar.test
925
+ IntegrationTest.php
926
+
927
+ The ``IntegrationTest.php`` file should look like this::
928
+
929
+ class Project_Tests_IntegrationTest extends Twig_Test_IntegrationTestCase
930
+ {
931
+ public function getExtensions()
932
+ {
933
+ return array(
934
+ new Project_Twig_Extension1(),
935
+ new Project_Twig_Extension2(),
936
+ );
937
+ }
938
+
939
+ public function getFixturesDir()
940
+ {
941
+ return dirname(__FILE__).'/Fixtures/';
942
+ }
943
+ }
944
+
945
+ Fixtures examples can be found within the Twig repository
946
+ `tests/Twig/Fixtures`_ directory.
947
+
948
+ Node Tests
949
+ ~~~~~~~~~~
950
+
951
+ Testing the node visitors can be complex, so extend your test cases from
952
+ ``Twig_Test_NodeTestCase``. Examples can be found in the Twig repository
953
+ `tests/Twig/Node`_ directory.
954
+
955
+ .. _`rot13`: http://www.php.net/manual/en/function.str-rot13.php
956
+ .. _`tests/Twig/Fixtures`: https://github.com/twigphp/Twig/tree/master/test/Twig/Tests/Fixtures
957
+ .. _`tests/Twig/Node`: https://github.com/twigphp/Twig/tree/master/test/Twig/Tests/Node
library/twig/twig/doc/advanced_legacy.rst ADDED
@@ -0,0 +1,885 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Extending Twig
2
+ ==============
3
+
4
+ .. caution::
5
+
6
+ This section describes how to extends Twig for versions **older than
7
+ 1.12**. If you are using a newer version, read the :doc:`newer<advanced>`
8
+ chapter instead.
9
+
10
+ Twig can be extended in many ways; you can add extra tags, filters, tests,
11
+ operators, global variables, and functions. You can even extend the parser
12
+ itself with node visitors.
13
+
14
+ .. note::
15
+
16
+ The first section of this chapter describes how to extend Twig easily. If
17
+ you want to reuse your changes in different projects or if you want to
18
+ share them with others, you should then create an extension as described
19
+ in the following section.
20
+
21
+ .. caution::
22
+
23
+ When extending Twig by calling methods on the Twig environment instance,
24
+ Twig won't be able to recompile your templates when the PHP code is
25
+ updated. To see your changes in real-time, either disable template caching
26
+ or package your code into an extension (see the next section of this
27
+ chapter).
28
+
29
+ Before extending Twig, you must understand the differences between all the
30
+ different possible extension points and when to use them.
31
+
32
+ First, remember that Twig has two main language constructs:
33
+
34
+ * ``{{ }}``: used to print the result of an expression evaluation;
35
+
36
+ * ``{% %}``: used to execute statements.
37
+
38
+ To understand why Twig exposes so many extension points, let's see how to
39
+ implement a *Lorem ipsum* generator (it needs to know the number of words to
40
+ generate).
41
+
42
+ You can use a ``lipsum`` *tag*:
43
+
44
+ .. code-block:: jinja
45
+
46
+ {% lipsum 40 %}
47
+
48
+ That works, but using a tag for ``lipsum`` is not a good idea for at least
49
+ three main reasons:
50
+
51
+ * ``lipsum`` is not a language construct;
52
+ * The tag outputs something;
53
+ * The tag is not flexible as you cannot use it in an expression:
54
+
55
+ .. code-block:: jinja
56
+
57
+ {{ 'some text' ~ {% lipsum 40 %} ~ 'some more text' }}
58
+
59
+ In fact, you rarely need to create tags; and that's good news because tags are
60
+ the most complex extension point of Twig.
61
+
62
+ Now, let's use a ``lipsum`` *filter*:
63
+
64
+ .. code-block:: jinja
65
+
66
+ {{ 40|lipsum }}
67
+
68
+ Again, it works, but it looks weird. A filter transforms the passed value to
69
+ something else but here we use the value to indicate the number of words to
70
+ generate (so, ``40`` is an argument of the filter, not the value we want to
71
+ transform).
72
+
73
+ Next, let's use a ``lipsum`` *function*:
74
+
75
+ .. code-block:: jinja
76
+
77
+ {{ lipsum(40) }}
78
+
79
+ Here we go. For this specific example, the creation of a function is the
80
+ extension point to use. And you can use it anywhere an expression is accepted:
81
+
82
+ .. code-block:: jinja
83
+
84
+ {{ 'some text' ~ ipsum(40) ~ 'some more text' }}
85
+
86
+ {% set ipsum = ipsum(40) %}
87
+
88
+ Last but not the least, you can also use a *global* object with a method able
89
+ to generate lorem ipsum text:
90
+
91
+ .. code-block:: jinja
92
+
93
+ {{ text.lipsum(40) }}
94
+
95
+ As a rule of thumb, use functions for frequently used features and global
96
+ objects for everything else.
97
+
98
+ Keep in mind the following when you want to extend Twig:
99
+
100
+ ========== ========================== ========== =========================
101
+ What? Implementation difficulty? How often? When?
102
+ ========== ========================== ========== =========================
103
+ *macro* trivial frequent Content generation
104
+ *global* trivial frequent Helper object
105
+ *function* trivial frequent Content generation
106
+ *filter* trivial frequent Value transformation
107
+ *tag* complex rare DSL language construct
108
+ *test* trivial rare Boolean decision
109
+ *operator* trivial rare Values transformation
110
+ ========== ========================== ========== =========================
111
+
112
+ Globals
113
+ -------
114
+
115
+ A global variable is like any other template variable, except that it's
116
+ available in all templates and macros::
117
+
118
+ $twig = new Twig_Environment($loader);
119
+ $twig->addGlobal('text', new Text());
120
+
121
+ You can then use the ``text`` variable anywhere in a template:
122
+
123
+ .. code-block:: jinja
124
+
125
+ {{ text.lipsum(40) }}
126
+
127
+ Filters
128
+ -------
129
+
130
+ A filter is a regular PHP function or an object method that takes the left
131
+ side of the filter (before the pipe ``|``) as first argument and the extra
132
+ arguments passed to the filter (within parentheses ``()``) as extra arguments.
133
+
134
+ Defining a filter is as easy as associating the filter name with a PHP
135
+ callable. For instance, let's say you have the following code in a template:
136
+
137
+ .. code-block:: jinja
138
+
139
+ {{ 'TWIG'|lower }}
140
+
141
+ When compiling this template to PHP, Twig looks for the PHP callable
142
+ associated with the ``lower`` filter. The ``lower`` filter is a built-in Twig
143
+ filter, and it is simply mapped to the PHP ``strtolower()`` function. After
144
+ compilation, the generated PHP code is roughly equivalent to:
145
+
146
+ .. code-block:: html+php
147
+
148
+ <?php echo strtolower('TWIG') ?>
149
+
150
+ As you can see, the ``'TWIG'`` string is passed as a first argument to the PHP
151
+ function.
152
+
153
+ A filter can also take extra arguments like in the following example:
154
+
155
+ .. code-block:: jinja
156
+
157
+ {{ now|date('d/m/Y') }}
158
+
159
+ In this case, the extra arguments are passed to the function after the main
160
+ argument, and the compiled code is equivalent to:
161
+
162
+ .. code-block:: html+php
163
+
164
+ <?php echo twig_date_format_filter($now, 'd/m/Y') ?>
165
+
166
+ Let's see how to create a new filter.
167
+
168
+ In this section, we will create a ``rot13`` filter, which should return the
169
+ `rot13`_ transformation of a string. Here is an example of its usage and the
170
+ expected output:
171
+
172
+ .. code-block:: jinja
173
+
174
+ {{ "Twig"|rot13 }}
175
+
176
+ {# should displays Gjvt #}
177
+
178
+ Adding a filter is as simple as calling the ``addFilter()`` method on the
179
+ ``Twig_Environment`` instance::
180
+
181
+ $twig = new Twig_Environment($loader);
182
+ $twig->addFilter('rot13', new Twig_Filter_Function('str_rot13'));
183
+
184
+ The second argument of ``addFilter()`` is an instance of ``Twig_Filter``.
185
+ Here, we use ``Twig_Filter_Function`` as the filter is a PHP function. The
186
+ first argument passed to the ``Twig_Filter_Function`` constructor is the name
187
+ of the PHP function to call, here ``str_rot13``, a native PHP function.
188
+
189
+ Let's say I now want to be able to add a prefix before the converted string:
190
+
191
+ .. code-block:: jinja
192
+
193
+ {{ "Twig"|rot13('prefix_') }}
194
+
195
+ {# should displays prefix_Gjvt #}
196
+
197
+ As the PHP ``str_rot13()`` function does not support this requirement, let's
198
+ create a new PHP function::
199
+
200
+ function project_compute_rot13($string, $prefix = '')
201
+ {
202
+ return $prefix.str_rot13($string);
203
+ }
204
+
205
+ As you can see, the ``prefix`` argument of the filter is passed as an extra
206
+ argument to the ``project_compute_rot13()`` function.
207
+
208
+ Adding this filter is as easy as before::
209
+
210
+ $twig->addFilter('rot13', new Twig_Filter_Function('project_compute_rot13'));
211
+
212
+ For better encapsulation, a filter can also be defined as a static method of a
213
+ class. The ``Twig_Filter_Function`` class can also be used to register such
214
+ static methods as filters::
215
+
216
+ $twig->addFilter('rot13', new Twig_Filter_Function('SomeClass::rot13Filter'));
217
+
218
+ .. tip::
219
+
220
+ In an extension, you can also define a filter as a static method of the
221
+ extension class.
222
+
223
+ Environment aware Filters
224
+ ~~~~~~~~~~~~~~~~~~~~~~~~~
225
+
226
+ The ``Twig_Filter`` classes take options as their last argument. For instance,
227
+ if you want access to the current environment instance in your filter, set the
228
+ ``needs_environment`` option to ``true``::
229
+
230
+ $filter = new Twig_Filter_Function('str_rot13', array('needs_environment' => true));
231
+
232
+ Twig will then pass the current environment as the first argument to the
233
+ filter call::
234
+
235
+ function twig_compute_rot13(Twig_Environment $env, $string)
236
+ {
237
+ // get the current charset for instance
238
+ $charset = $env->getCharset();
239
+
240
+ return str_rot13($string);
241
+ }
242
+
243
+ Automatic Escaping
244
+ ~~~~~~~~~~~~~~~~~~
245
+
246
+ If automatic escaping is enabled, the output of the filter may be escaped
247
+ before printing. If your filter acts as an escaper (or explicitly outputs HTML
248
+ or JavaScript code), you will want the raw output to be printed. In such a
249
+ case, set the ``is_safe`` option::
250
+
251
+ $filter = new Twig_Filter_Function('nl2br', array('is_safe' => array('html')));
252
+
253
+ Some filters may need to work on input that is already escaped or safe, for
254
+ example when adding (safe) HTML tags to originally unsafe output. In such a
255
+ case, set the ``pre_escape`` option to escape the input data before it is run
256
+ through your filter::
257
+
258
+ $filter = new Twig_Filter_Function('somefilter', array('pre_escape' => 'html', 'is_safe' => array('html')));
259
+
260
+ Dynamic Filters
261
+ ~~~~~~~~~~~~~~~
262
+
263
+ .. versionadded:: 1.5
264
+ Dynamic filters support was added in Twig 1.5.
265
+
266
+ A filter name containing the special ``*`` character is a dynamic filter as
267
+ the ``*`` can be any string::
268
+
269
+ $twig->addFilter('*_path_*', new Twig_Filter_Function('twig_path'));
270
+
271
+ function twig_path($name, $arguments)
272
+ {
273
+ // ...
274
+ }
275
+
276
+ The following filters will be matched by the above defined dynamic filter:
277
+
278
+ * ``product_path``
279
+ * ``category_path``
280
+
281
+ A dynamic filter can define more than one dynamic parts::
282
+
283
+ $twig->addFilter('*_path_*', new Twig_Filter_Function('twig_path'));
284
+
285
+ function twig_path($name, $suffix, $arguments)
286
+ {
287
+ // ...
288
+ }
289
+
290
+ The filter will receive all dynamic part values before the normal filters
291
+ arguments. For instance, a call to ``'foo'|a_path_b()`` will result in the
292
+ following PHP call: ``twig_path('a', 'b', 'foo')``.
293
+
294
+ Functions
295
+ ---------
296
+
297
+ A function is a regular PHP function or an object method that can be called from
298
+ templates.
299
+
300
+ .. code-block:: jinja
301
+
302
+ {{ constant("DATE_W3C") }}
303
+
304
+ When compiling this template to PHP, Twig looks for the PHP callable
305
+ associated with the ``constant`` function. The ``constant`` function is a built-in Twig
306
+ function, and it is simply mapped to the PHP ``constant()`` function. After
307
+ compilation, the generated PHP code is roughly equivalent to:
308
+
309
+ .. code-block:: html+php
310
+
311
+ <?php echo constant('DATE_W3C') ?>
312
+
313
+ Adding a function is similar to adding a filter. This can be done by calling the
314
+ ``addFunction()`` method on the ``Twig_Environment`` instance::
315
+
316
+ $twig = new Twig_Environment($loader);
317
+ $twig->addFunction('functionName', new Twig_Function_Function('someFunction'));
318
+
319
+ You can also expose extension methods as functions in your templates::
320
+
321
+ // $this is an object that implements Twig_ExtensionInterface.
322
+ $twig = new Twig_Environment($loader);
323
+ $twig->addFunction('otherFunction', new Twig_Function_Method($this, 'someMethod'));
324
+
325
+ Functions also support ``needs_environment`` and ``is_safe`` parameters.
326
+
327
+ Dynamic Functions
328
+ ~~~~~~~~~~~~~~~~~
329
+
330
+ .. versionadded:: 1.5
331
+ Dynamic functions support was added in Twig 1.5.
332
+
333
+ A function name containing the special ``*`` character is a dynamic function
334
+ as the ``*`` can be any string::
335
+
336
+ $twig->addFunction('*_path', new Twig_Function_Function('twig_path'));
337
+
338
+ function twig_path($name, $arguments)
339
+ {
340
+ // ...
341
+ }
342
+
343
+ The following functions will be matched by the above defined dynamic function:
344
+
345
+ * ``product_path``
346
+ * ``category_path``
347
+
348
+ A dynamic function can define more than one dynamic parts::
349
+
350
+ $twig->addFilter('*_path_*', new Twig_Filter_Function('twig_path'));
351
+
352
+ function twig_path($name, $suffix, $arguments)
353
+ {
354
+ // ...
355
+ }
356
+
357
+ The function will receive all dynamic part values before the normal functions
358
+ arguments. For instance, a call to ``a_path_b('foo')`` will result in the
359
+ following PHP call: ``twig_path('a', 'b', 'foo')``.
360
+
361
+ Tags
362
+ ----
363
+
364
+ One of the most exciting feature of a template engine like Twig is the
365
+ possibility to define new language constructs. This is also the most complex
366
+ feature as you need to understand how Twig's internals work.
367
+
368
+ Let's create a simple ``set`` tag that allows the definition of simple
369
+ variables from within a template. The tag can be used like follows:
370
+
371
+ .. code-block:: jinja
372
+
373
+ {% set name = "value" %}
374
+
375
+ {{ name }}
376
+
377
+ {# should output value #}
378
+
379
+ .. note::
380
+
381
+ The ``set`` tag is part of the Core extension and as such is always
382
+ available. The built-in version is slightly more powerful and supports
383
+ multiple assignments by default (cf. the template designers chapter for
384
+ more information).
385
+
386
+ Three steps are needed to define a new tag:
387
+
388
+ * Defining a Token Parser class (responsible for parsing the template code);
389
+
390
+ * Defining a Node class (responsible for converting the parsed code to PHP);
391
+
392
+ * Registering the tag.
393
+
394
+ Registering a new tag
395
+ ~~~~~~~~~~~~~~~~~~~~~
396
+
397
+ Adding a tag is as simple as calling the ``addTokenParser`` method on the
398
+ ``Twig_Environment`` instance::
399
+
400
+ $twig = new Twig_Environment($loader);
401
+ $twig->addTokenParser(new Project_Set_TokenParser());
402
+
403
+ Defining a Token Parser
404
+ ~~~~~~~~~~~~~~~~~~~~~~~
405
+
406
+ Now, let's see the actual code of this class::
407
+
408
+ class Project_Set_TokenParser extends Twig_TokenParser
409
+ {
410
+ public function parse(Twig_Token $token)
411
+ {
412
+ $lineno = $token->getLine();
413
+ $name = $this->parser->getStream()->expect(Twig_Token::NAME_TYPE)->getValue();
414
+ $this->parser->getStream()->expect(Twig_Token::OPERATOR_TYPE, '=');
415
+ $value = $this->parser->getExpressionParser()->parseExpression();
416
+
417
+ $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
418
+
419
+ return new Project_Set_Node($name, $value, $lineno, $this->getTag());
420
+ }
421
+
422
+ public function getTag()
423
+ {
424
+ return 'set';
425
+ }
426
+ }
427
+
428
+ The ``getTag()`` method must return the tag we want to parse, here ``set``.
429
+
430
+ The ``parse()`` method is invoked whenever the parser encounters a ``set``
431
+ tag. It should return a ``Twig_Node`` instance that represents the node (the
432
+ ``Project_Set_Node`` calls creating is explained in the next section).
433
+
434
+ The parsing process is simplified thanks to a bunch of methods you can call
435
+ from the token stream (``$this->parser->getStream()``):
436
+
437
+ * ``getCurrent()``: Gets the current token in the stream.
438
+
439
+ * ``next()``: Moves to the next token in the stream, *but returns the old one*.
440
+
441
+ * ``test($type)``, ``test($value)`` or ``test($type, $value)``: Determines whether
442
+ the current token is of a particular type or value (or both). The value may be an
443
+ array of several possible values.
444
+
445
+ * ``expect($type[, $value[, $message]])``: If the current token isn't of the given
446
+ type/value a syntax error is thrown. Otherwise, if the type and value are correct,
447
+ the token is returned and the stream moves to the next token.
448
+
449
+ * ``look()``: Looks a the next token without consuming it.
450
+
451
+ Parsing expressions is done by calling the ``parseExpression()`` like we did for
452
+ the ``set`` tag.
453
+
454
+ .. tip::
455
+
456
+ Reading the existing ``TokenParser`` classes is the best way to learn all
457
+ the nitty-gritty details of the parsing process.
458
+
459
+ Defining a Node
460
+ ~~~~~~~~~~~~~~~
461
+
462
+ The ``Project_Set_Node`` class itself is rather simple::
463
+
464
+ class Project_Set_Node extends Twig_Node
465
+ {
466
+ public function __construct($name, Twig_Node_Expression $value, $lineno, $tag = null)
467
+ {
468
+ parent::__construct(array('value' => $value), array('name' => $name), $lineno, $tag);
469
+ }
470
+
471
+ public function compile(Twig_Compiler $compiler)
472
+ {
473
+ $compiler
474
+ ->addDebugInfo($this)
475
+ ->write('$context[\''.$this->getAttribute('name').'\'] = ')
476
+ ->subcompile($this->getNode('value'))
477
+ ->raw(";\n")
478
+ ;
479
+ }
480
+ }
481
+
482
+ The compiler implements a fluid interface and provides methods that helps the
483
+ developer generate beautiful and readable PHP code:
484
+
485
+ * ``subcompile()``: Compiles a node.
486
+
487
+ * ``raw()``: Writes the given string as is.
488
+
489
+ * ``write()``: Writes the given string by adding indentation at the beginning
490
+ of each line.
491
+
492
+ * ``string()``: Writes a quoted string.
493
+
494
+ * ``repr()``: Writes a PHP representation of a given value (see
495
+ ``Twig_Node_For`` for a usage example).
496
+
497
+ * ``addDebugInfo()``: Adds the line of the original template file related to
498
+ the current node as a comment.
499
+
500
+ * ``indent()``: Indents the generated code (see ``Twig_Node_Block`` for a
501
+ usage example).
502
+
503
+ * ``outdent()``: Outdents the generated code (see ``Twig_Node_Block`` for a
504
+ usage example).
505
+
506
+ .. _creating_extensions:
507
+
508
+ Creating an Extension
509
+ ---------------------
510
+
511
+ The main motivation for writing an extension is to move often used code into a
512
+ reusable class like adding support for internationalization. An extension can
513
+ define tags, filters, tests, operators, global variables, functions, and node
514
+ visitors.
515
+
516
+ Creating an extension also makes for a better separation of code that is
517
+ executed at compilation time and code needed at runtime. As such, it makes
518
+ your code faster.
519
+
520
+ Most of the time, it is useful to create a single extension for your project,
521
+ to host all the specific tags and filters you want to add to Twig.
522
+
523
+ .. tip::
524
+
525
+ When packaging your code into an extension, Twig is smart enough to
526
+ recompile your templates whenever you make a change to it (when the
527
+ ``auto_reload`` is enabled).
528
+
529
+ .. note::
530
+
531
+ Before writing your own extensions, have a look at the Twig official
532
+ extension repository: http://github.com/twigphp/Twig-extensions.
533
+
534
+ An extension is a class that implements the following interface::
535
+
536
+ interface Twig_ExtensionInterface
537
+ {
538
+ /**
539
+ * Initializes the runtime environment.
540
+ *
541
+ * This is where you can load some file that contains filter functions for instance.
542
+ */
543
+ function initRuntime(Twig_Environment $environment);
544
+
545
+ /**
546
+ * Returns the token parser instances to add to the existing list.
547
+ *
548
+ * @return (Twig_TokenParserInterface|Twig_TokenParserBrokerInterface)[]
549
+ */
550
+ function getTokenParsers();
551
+
552
+ /**
553
+ * Returns the node visitor instances to add to the existing list.
554
+ *
555
+ * @return Twig_NodeVisitorInterface[]
556
+ */
557
+ function getNodeVisitors();
558
+
559
+ /**
560
+ * Returns a list of filters to add to the existing list.
561
+ *
562
+ * @return Twig_SimpleFilter[]
563
+ */
564
+ function getFilters();
565
+
566
+ /**
567
+ * Returns a list of tests to add to the existing list.
568
+ *
569
+ * @return Twig_SimpleTest[]
570
+ */
571
+ function getTests();
572
+
573
+ /**
574
+ * Returns a list of functions to add to the existing list.
575
+ *
576
+ * @return Twig_SimpleFunction[]
577
+ */
578
+ function getFunctions();
579
+
580
+ /**
581
+ * Returns a list of operators to add to the existing list.
582
+ *
583
+ * @return array<array> First array of unary operators, second array of binary operators
584
+ */
585
+ function getOperators();
586
+
587
+ /**
588
+ * Returns a list of global variables to add to the existing list.
589
+ *
590
+ * @return array An array of global variables
591
+ */
592
+ function getGlobals();
593
+
594
+ /**
595
+ * Returns the name of the extension.
596
+ *
597
+ * @return string The extension name
598
+ */
599
+ function getName();
600
+ }
601
+
602
+ To keep your extension class clean and lean, it can inherit from the built-in
603
+ ``Twig_Extension`` class instead of implementing the whole interface. That
604
+ way, you just need to implement the ``getName()`` method as the
605
+ ``Twig_Extension`` provides empty implementations for all other methods.
606
+
607
+ The ``getName()`` method must return a unique identifier for your extension.
608
+
609
+ Now, with this information in mind, let's create the most basic extension
610
+ possible::
611
+
612
+ class Project_Twig_Extension extends Twig_Extension
613
+ {
614
+ public function getName()
615
+ {
616
+ return 'project';
617
+ }
618
+ }
619
+
620
+ .. note::
621
+
622
+ Of course, this extension does nothing for now. We will customize it in
623
+ the next sections.
624
+
625
+ Twig does not care where you save your extension on the filesystem, as all
626
+ extensions must be registered explicitly to be available in your templates.
627
+
628
+ You can register an extension by using the ``addExtension()`` method on your
629
+ main ``Environment`` object::
630
+
631
+ $twig = new Twig_Environment($loader);
632
+ $twig->addExtension(new Project_Twig_Extension());
633
+
634
+ Of course, you need to first load the extension file by either using
635
+ ``require_once()`` or by using an autoloader (see `spl_autoload_register()`_).
636
+
637
+ .. tip::
638
+
639
+ The bundled extensions are great examples of how extensions work.
640
+
641
+ Globals
642
+ ~~~~~~~
643
+
644
+ Global variables can be registered in an extension via the ``getGlobals()``
645
+ method::
646
+
647
+ class Project_Twig_Extension extends Twig_Extension
648
+ {
649
+ public function getGlobals()
650
+ {
651
+ return array(
652
+ 'text' => new Text(),
653
+ );
654
+ }
655
+
656
+ // ...
657
+ }
658
+
659
+ Functions
660
+ ~~~~~~~~~
661
+
662
+ Functions can be registered in an extension via the ``getFunctions()``
663
+ method::
664
+
665
+ class Project_Twig_Extension extends Twig_Extension
666
+ {
667
+ public function getFunctions()
668
+ {
669
+ return array(
670
+ 'lipsum' => new Twig_Function_Function('generate_lipsum'),
671
+ );
672
+ }
673
+
674
+ // ...
675
+ }
676
+
677
+ Filters
678
+ ~~~~~~~
679
+
680
+ To add a filter to an extension, you need to override the ``getFilters()``
681
+ method. This method must return an array of filters to add to the Twig
682
+ environment::
683
+
684
+ class Project_Twig_Extension extends Twig_Extension
685
+ {
686
+ public function getFilters()
687
+ {
688
+ return array(
689
+ 'rot13' => new Twig_Filter_Function('str_rot13'),
690
+ );
691
+ }
692
+
693
+ // ...
694
+ }
695
+
696
+ As you can see in the above code, the ``getFilters()`` method returns an array
697
+ where keys are the name of the filters (``rot13``) and the values the
698
+ definition of the filter (``new Twig_Filter_Function('str_rot13')``).
699
+
700
+ As seen in the previous chapter, you can also define filters as static methods
701
+ on the extension class::
702
+
703
+ $twig->addFilter('rot13', new Twig_Filter_Function('Project_Twig_Extension::rot13Filter'));
704
+
705
+ You can also use ``Twig_Filter_Method`` instead of ``Twig_Filter_Function``
706
+ when defining a filter to use a method::
707
+
708
+ class Project_Twig_Extension extends Twig_Extension
709
+ {
710
+ public function getFilters()
711
+ {
712
+ return array(
713
+ 'rot13' => new Twig_Filter_Method($this, 'rot13Filter'),
714
+ );
715
+ }
716
+
717
+ public function rot13Filter($string)
718
+ {
719
+ return str_rot13($string);
720
+ }
721
+
722
+ // ...
723
+ }
724
+
725
+ The first argument of the ``Twig_Filter_Method`` constructor is always
726
+ ``$this``, the current extension object. The second one is the name of the
727
+ method to call.
728
+
729
+ Using methods for filters is a great way to package your filter without
730
+ polluting the global namespace. This also gives the developer more flexibility
731
+ at the cost of a small overhead.
732
+
733
+ Overriding default Filters
734
+ ..........................
735
+
736
+ If some default core filters do not suit your needs, you can easily override
737
+ them by creating your own extension. Just use the same names as the one you
738
+ want to override::
739
+
740
+ class MyCoreExtension extends Twig_Extension
741
+ {
742
+ public function getFilters()
743
+ {
744
+ return array(
745
+ 'date' => new Twig_Filter_Method($this, 'dateFilter'),
746
+ // ...
747
+ );
748
+ }
749
+
750
+ public function dateFilter($timestamp, $format = 'F j, Y H:i')
751
+ {
752
+ return '...'.twig_date_format_filter($timestamp, $format);
753
+ }
754
+
755
+ public function getName()
756
+ {
757
+ return 'project';
758
+ }
759
+ }
760
+
761
+ Here, we override the ``date`` filter with a custom one. Using this extension
762
+ is as simple as registering the ``MyCoreExtension`` extension by calling the
763
+ ``addExtension()`` method on the environment instance::
764
+
765
+ $twig = new Twig_Environment($loader);
766
+ $twig->addExtension(new MyCoreExtension());
767
+
768
+ Tags
769
+ ~~~~
770
+
771
+ Adding a tag in an extension can be done by overriding the
772
+ ``getTokenParsers()`` method. This method must return an array of tags to add
773
+ to the Twig environment::
774
+
775
+ class Project_Twig_Extension extends Twig_Extension
776
+ {
777
+ public function getTokenParsers()
778
+ {
779
+ return array(new Project_Set_TokenParser());
780
+ }
781
+
782
+ // ...
783
+ }
784
+
785
+ In the above code, we have added a single new tag, defined by the
786
+ ``Project_Set_TokenParser`` class. The ``Project_Set_TokenParser`` class is
787
+ responsible for parsing the tag and compiling it to PHP.
788
+
789
+ Operators
790
+ ~~~~~~~~~
791
+
792
+ The ``getOperators()`` methods allows to add new operators. Here is how to add
793
+ ``!``, ``||``, and ``&&`` operators::
794
+
795
+ class Project_Twig_Extension extends Twig_Extension
796
+ {
797
+ public function getOperators()
798
+ {
799
+ return array(
800
+ array(
801
+ '!' => array('precedence' => 50, 'class' => 'Twig_Node_Expression_Unary_Not'),
802
+ ),
803
+ array(
804
+ '||' => array('precedence' => 10, 'class' => 'Twig_Node_Expression_Binary_Or', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
805
+ '&&' => array('precedence' => 15, 'class' => 'Twig_Node_Expression_Binary_And', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
806
+ ),
807
+ );
808
+ }
809
+
810
+ // ...
811
+ }
812
+
813
+ Tests
814
+ ~~~~~
815
+
816
+ The ``getTests()`` methods allows to add new test functions::
817
+
818
+ class Project_Twig_Extension extends Twig_Extension
819
+ {
820
+ public function getTests()
821
+ {
822
+ return array(
823
+ 'even' => new Twig_Test_Function('twig_test_even'),
824
+ );
825
+ }
826
+
827
+ // ...
828
+ }
829
+
830
+ Testing an Extension
831
+ --------------------
832
+
833
+ .. versionadded:: 1.10
834
+ Support for functional tests was added in Twig 1.10.
835
+
836
+ Functional Tests
837
+ ~~~~~~~~~~~~~~~~
838
+
839
+ You can create functional tests for extensions simply by creating the
840
+ following file structure in your test directory::
841
+
842
+ Fixtures/
843
+ filters/
844
+ foo.test
845
+ bar.test
846
+ functions/
847
+ foo.test
848
+ bar.test
849
+ tags/
850
+ foo.test
851
+ bar.test
852
+ IntegrationTest.php
853
+
854
+ The ``IntegrationTest.php`` file should look like this::
855
+
856
+ class Project_Tests_IntegrationTest extends Twig_Test_IntegrationTestCase
857
+ {
858
+ public function getExtensions()
859
+ {
860
+ return array(
861
+ new Project_Twig_Extension1(),
862
+ new Project_Twig_Extension2(),
863
+ );
864
+ }
865
+
866
+ public function getFixturesDir()
867
+ {
868
+ return dirname(__FILE__).'/Fixtures/';
869
+ }
870
+ }
871
+
872
+ Fixtures examples can be found within the Twig repository
873
+ `tests/Twig/Fixtures`_ directory.
874
+
875
+ Node Tests
876
+ ~~~~~~~~~~
877
+
878
+ Testing the node visitors can be complex, so extend your test cases from
879
+ ``Twig_Test_NodeTestCase``. Examples can be found in the Twig repository
880
+ `tests/Twig/Node`_ directory.
881
+
882
+ .. _`spl_autoload_register()`: http://www.php.net/spl_autoload_register
883
+ .. _`rot13`: http://www.php.net/manual/en/function.str-rot13.php
884
+ .. _`tests/Twig/Fixtures`: https://github.com/twigphp/Twig/tree/master/test/Twig/Tests/Fixtures
885
+ .. _`tests/Twig/Node`: https://github.com/twigphp/Twig/tree/master/test/Twig/Tests/Node
library/twig/twig/doc/api.rst ADDED
@@ -0,0 +1,590 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Twig for Developers
2
+ ===================
3
+
4
+ This chapter describes the API to Twig and not the template language. It will
5
+ be most useful as reference to those implementing the template interface to
6
+ the application and not those who are creating Twig templates.
7
+
8
+ Basics
9
+ ------
10
+
11
+ Twig uses a central object called the **environment** (of class
12
+ ``Twig_Environment``). Instances of this class are used to store the
13
+ configuration and extensions, and are used to load templates from the file
14
+ system or other locations.
15
+
16
+ Most applications will create one ``Twig_Environment`` object on application
17
+ initialization and use that to load templates. In some cases it's however
18
+ useful to have multiple environments side by side, if different configurations
19
+ are in use.
20
+
21
+ The simplest way to configure Twig to load templates for your application
22
+ looks roughly like this::
23
+
24
+ require_once '/path/to/lib/Twig/Autoloader.php';
25
+ Twig_Autoloader::register();
26
+
27
+ $loader = new Twig_Loader_Filesystem('/path/to/templates');
28
+ $twig = new Twig_Environment($loader, array(
29
+ 'cache' => '/path/to/compilation_cache',
30
+ ));
31
+
32
+ This will create a template environment with the default settings and a loader
33
+ that looks up the templates in the ``/path/to/templates/`` folder. Different
34
+ loaders are available and you can also write your own if you want to load
35
+ templates from a database or other resources.
36
+
37
+ .. note::
38
+
39
+ Notice that the second argument of the environment is an array of options.
40
+ The ``cache`` option is a compilation cache directory, where Twig caches
41
+ the compiled templates to avoid the parsing phase for sub-sequent
42
+ requests. It is very different from the cache you might want to add for
43
+ the evaluated templates. For such a need, you can use any available PHP
44
+ cache library.
45
+
46
+ Rendering Templates
47
+ -------------------
48
+
49
+ To load a template from a Twig environment, call the ``load()`` method which
50
+ returns a ``Twig_TemplateWrapper`` instance::
51
+
52
+ $template = $twig->load('index.html');
53
+
54
+ .. note::
55
+
56
+ Before Twig 1.28, you should use ``loadTemplate()`` instead which returns a
57
+ ``Twig_Template`` instance.
58
+
59
+ To render the template with some variables, call the ``render()`` method::
60
+
61
+ echo $template->render(array('the' => 'variables', 'go' => 'here'));
62
+
63
+ .. note::
64
+
65
+ The ``display()`` method is a shortcut to output the template directly.
66
+
67
+ You can also load and render the template in one fell swoop::
68
+
69
+ echo $twig->render('index.html', array('the' => 'variables', 'go' => 'here'));
70
+
71
+ .. versionadded:: 1.28
72
+ The possibility to render blocks from the API was added in Twig 1.28.
73
+
74
+ If a template defines blocks, they can be rendered individually via the
75
+ ``renderBlock()`` call::
76
+
77
+ echo $template->renderBlock('block_name', array('the' => 'variables', 'go' => 'here'));
78
+
79
+ .. _environment_options:
80
+
81
+ Environment Options
82
+ -------------------
83
+
84
+ When creating a new ``Twig_Environment`` instance, you can pass an array of
85
+ options as the constructor second argument::
86
+
87
+ $twig = new Twig_Environment($loader, array('debug' => true));
88
+
89
+ The following options are available:
90
+
91
+ * ``debug`` *boolean*
92
+
93
+ When set to ``true``, the generated templates have a
94
+ ``__toString()`` method that you can use to display the generated nodes
95
+ (default to ``false``).
96
+
97
+ * ``charset`` *string* (defaults to ``utf-8``)
98
+
99
+ The charset used by the templates.
100
+
101
+ * ``base_template_class`` *string* (defaults to ``Twig_Template``)
102
+
103
+ The base template class to use for generated
104
+ templates.
105
+
106
+ * ``cache`` *string* or ``false``
107
+
108
+ An absolute path where to store the compiled templates, or
109
+ ``false`` to disable caching (which is the default).
110
+
111
+ * ``auto_reload`` *boolean*
112
+
113
+ When developing with Twig, it's useful to recompile the
114
+ template whenever the source code changes. If you don't provide a value for
115
+ the ``auto_reload`` option, it will be determined automatically based on the
116
+ ``debug`` value.
117
+
118
+ * ``strict_variables`` *boolean*
119
+
120
+ If set to ``false``, Twig will silently ignore invalid
121
+ variables (variables and or attributes/methods that do not exist) and
122
+ replace them with a ``null`` value. When set to ``true``, Twig throws an
123
+ exception instead (default to ``false``).
124
+
125
+ * ``autoescape`` *string* or *boolean*
126
+
127
+ If set to ``true``, HTML auto-escaping will be enabled by
128
+ default for all templates (default to ``true``).
129
+
130
+ As of Twig 1.8, you can set the escaping strategy to use (``html``, ``js``,
131
+ ``false`` to disable).
132
+
133
+ As of Twig 1.9, you can set the escaping strategy to use (``css``, ``url``,
134
+ ``html_attr``, or a PHP callback that takes the template name and must
135
+ return the escaping strategy to use -- the callback cannot be a function name
136
+ to avoid collision with built-in escaping strategies).
137
+
138
+ As of Twig 1.17, the ``filename`` escaping strategy (renamed to ``name`` as
139
+ of Twig 1.27) determines the escaping strategy to use for a template based on
140
+ the template filename extension (this strategy does not incur any overhead at
141
+ runtime as auto-escaping is done at compilation time.)
142
+
143
+ * ``optimizations`` *integer*
144
+
145
+ A flag that indicates which optimizations to apply
146
+ (default to ``-1`` -- all optimizations are enabled; set it to ``0`` to
147
+ disable).
148
+
149
+ Loaders
150
+ -------
151
+
152
+ Loaders are responsible for loading templates from a resource such as the file
153
+ system.
154
+
155
+ Compilation Cache
156
+ ~~~~~~~~~~~~~~~~~
157
+
158
+ All template loaders can cache the compiled templates on the filesystem for
159
+ future reuse. It speeds up Twig a lot as templates are only compiled once; and
160
+ the performance boost is even larger if you use a PHP accelerator such as APC.
161
+ See the ``cache`` and ``auto_reload`` options of ``Twig_Environment`` above
162
+ for more information.
163
+
164
+ Built-in Loaders
165
+ ~~~~~~~~~~~~~~~~
166
+
167
+ Here is a list of the built-in loaders Twig provides:
168
+
169
+ ``Twig_Loader_Filesystem``
170
+ ..........................
171
+
172
+ .. versionadded:: 1.10
173
+ The ``prependPath()`` and support for namespaces were added in Twig 1.10.
174
+
175
+ .. versionadded:: 1.27
176
+ Relative paths support was added in Twig 1.27.
177
+
178
+ ``Twig_Loader_Filesystem`` loads templates from the file system. This loader
179
+ can find templates in folders on the file system and is the preferred way to
180
+ load them::
181
+
182
+ $loader = new Twig_Loader_Filesystem($templateDir);
183
+
184
+ It can also look for templates in an array of directories::
185
+
186
+ $loader = new Twig_Loader_Filesystem(array($templateDir1, $templateDir2));
187
+
188
+ With such a configuration, Twig will first look for templates in
189
+ ``$templateDir1`` and if they do not exist, it will fallback to look for them
190
+ in the ``$templateDir2``.
191
+
192
+ You can add or prepend paths via the ``addPath()`` and ``prependPath()``
193
+ methods::
194
+
195
+ $loader->addPath($templateDir3);
196
+ $loader->prependPath($templateDir4);
197
+
198
+ The filesystem loader also supports namespaced templates. This allows to group
199
+ your templates under different namespaces which have their own template paths.
200
+
201
+ When using the ``setPaths()``, ``addPath()``, and ``prependPath()`` methods,
202
+ specify the namespace as the second argument (when not specified, these
203
+ methods act on the "main" namespace)::
204
+
205
+ $loader->addPath($templateDir, 'admin');
206
+
207
+ Namespaced templates can be accessed via the special
208
+ ``@namespace_name/template_path`` notation::
209
+
210
+ $twig->render('@admin/index.html', array());
211
+
212
+ ``Twig_Loader_Filesystem`` support absolute and relative paths. Using relative
213
+ paths is preferred as it makes the cache keys independent of the project root
214
+ directory (for instance, it allows warming the cache from a build server where
215
+ the directory might be different from the one used on production servers)::
216
+
217
+ $loader = new Twig_Loader_Filesystem('templates', getcwd().'/..');
218
+
219
+ .. note::
220
+
221
+ When not passing the root path as a second argument, Twig uses ``getcwd()``
222
+ for relative paths.
223
+
224
+ ``Twig_Loader_Array``
225
+ .....................
226
+
227
+ ``Twig_Loader_Array`` loads a template from a PHP array. It's passed an array
228
+ of strings bound to template names::
229
+
230
+ $loader = new Twig_Loader_Array(array(
231
+ 'index.html' => 'Hello {{ name }}!',
232
+ ));
233
+ $twig = new Twig_Environment($loader);
234
+
235
+ echo $twig->render('index.html', array('name' => 'Fabien'));
236
+
237
+ This loader is very useful for unit testing. It can also be used for small
238
+ projects where storing all templates in a single PHP file might make sense.
239
+
240
+ .. tip::
241
+
242
+ When using the ``Array`` or ``String`` loaders with a cache mechanism, you
243
+ should know that a new cache key is generated each time a template content
244
+ "changes" (the cache key being the source code of the template). If you
245
+ don't want to see your cache grows out of control, you need to take care
246
+ of clearing the old cache file by yourself.
247
+
248
+ ``Twig_Loader_Chain``
249
+ .....................
250
+
251
+ ``Twig_Loader_Chain`` delegates the loading of templates to other loaders::
252
+
253
+ $loader1 = new Twig_Loader_Array(array(
254
+ 'base.html' => '{% block content %}{% endblock %}',
255
+ ));
256
+ $loader2 = new Twig_Loader_Array(array(
257
+ 'index.html' => '{% extends "base.html" %}{% block content %}Hello {{ name }}{% endblock %}',
258
+ 'base.html' => 'Will never be loaded',
259
+ ));
260
+
261
+ $loader = new Twig_Loader_Chain(array($loader1, $loader2));
262
+
263
+ $twig = new Twig_Environment($loader);
264
+
265
+ When looking for a template, Twig will try each loader in turn and it will
266
+ return as soon as the template is found. When rendering the ``index.html``
267
+ template from the above example, Twig will load it with ``$loader2`` but the
268
+ ``base.html`` template will be loaded from ``$loader1``.
269
+
270
+ ``Twig_Loader_Chain`` accepts any loader that implements
271
+ ``Twig_LoaderInterface``.
272
+
273
+ .. note::
274
+
275
+ You can also add loaders via the ``addLoader()`` method.
276
+
277
+ Create your own Loader
278
+ ~~~~~~~~~~~~~~~~~~~~~~
279
+
280
+ All loaders implement the ``Twig_LoaderInterface``::
281
+
282
+ interface Twig_LoaderInterface
283
+ {
284
+ /**
285
+ * Gets the source code of a template, given its name.
286
+ *
287
+ * @param string $name string The name of the template to load
288
+ *
289
+ * @return string The template source code
290
+ *
291
+ * @deprecated since 1.27 (to be removed in 2.0), implement Twig_SourceContextLoaderInterface
292
+ */
293
+ function getSource($name);
294
+
295
+ /**
296
+ * Gets the cache key to use for the cache for a given template name.
297
+ *
298
+ * @param string $name string The name of the template to load
299
+ *
300
+ * @return string The cache key
301
+ */
302
+ function getCacheKey($name);
303
+
304
+ /**
305
+ * Returns true if the template is still fresh.
306
+ *
307
+ * @param string $name The template name
308
+ * @param timestamp $time The last modification time of the cached template
309
+ */
310
+ function isFresh($name, $time);
311
+ }
312
+
313
+ The ``isFresh()`` method must return ``true`` if the current cached template
314
+ is still fresh, given the last modification time, or ``false`` otherwise.
315
+
316
+ .. note::
317
+
318
+ As of Twig 1.27, you should also implement
319
+ ``Twig_SourceContextLoaderInterface`` to avoid deprecation notices.
320
+
321
+ .. tip::
322
+
323
+ As of Twig 1.11.0, you can also implement ``Twig_ExistsLoaderInterface``
324
+ to make your loader faster when used with the chain loader.
325
+
326
+ Using Extensions
327
+ ----------------
328
+
329
+ Twig extensions are packages that add new features to Twig. Using an
330
+ extension is as simple as using the ``addExtension()`` method::
331
+
332
+ $twig->addExtension(new Twig_Extension_Sandbox());
333
+
334
+ Twig comes bundled with the following extensions:
335
+
336
+ * *Twig_Extension_Core*: Defines all the core features of Twig.
337
+
338
+ * *Twig_Extension_Escaper*: Adds automatic output-escaping and the possibility
339
+ to escape/unescape blocks of code.
340
+
341
+ * *Twig_Extension_Sandbox*: Adds a sandbox mode to the default Twig
342
+ environment, making it safe to evaluate untrusted code.
343
+
344
+ * *Twig_Extension_Profiler*: Enabled the built-in Twig profiler (as of Twig
345
+ 1.18).
346
+
347
+ * *Twig_Extension_Optimizer*: Optimizes the node tree before compilation.
348
+
349
+ The core, escaper, and optimizer extensions do not need to be added to the
350
+ Twig environment, as they are registered by default.
351
+
352
+ Built-in Extensions
353
+ -------------------
354
+
355
+ This section describes the features added by the built-in extensions.
356
+
357
+ .. tip::
358
+
359
+ Read the chapter about extending Twig to learn how to create your own
360
+ extensions.
361
+
362
+ Core Extension
363
+ ~~~~~~~~~~~~~~
364
+
365
+ The ``core`` extension defines all the core features of Twig:
366
+
367
+ * :doc:`Tags <tags/index>`;
368
+ * :doc:`Filters <filters/index>`;
369
+ * :doc:`Functions <functions/index>`;
370
+ * :doc:`Tests <tests/index>`.
371
+
372
+ Escaper Extension
373
+ ~~~~~~~~~~~~~~~~~
374
+
375
+ The ``escaper`` extension adds automatic output escaping to Twig. It defines a
376
+ tag, ``autoescape``, and a filter, ``raw``.
377
+
378
+ When creating the escaper extension, you can switch on or off the global
379
+ output escaping strategy::
380
+
381
+ $escaper = new Twig_Extension_Escaper('html');
382
+ $twig->addExtension($escaper);
383
+
384
+ If set to ``html``, all variables in templates are escaped (using the ``html``
385
+ escaping strategy), except those using the ``raw`` filter:
386
+
387
+ .. code-block:: jinja
388
+
389
+ {{ article.to_html|raw }}
390
+
391
+ You can also change the escaping mode locally by using the ``autoescape`` tag
392
+ (see the :doc:`autoescape<tags/autoescape>` doc for the syntax used before
393
+ Twig 1.8):
394
+
395
+ .. code-block:: jinja
396
+
397
+ {% autoescape 'html' %}
398
+ {{ var }}
399
+ {{ var|raw }} {# var won't be escaped #}
400
+ {{ var|escape }} {# var won't be double-escaped #}
401
+ {% endautoescape %}
402
+
403
+ .. warning::
404
+
405
+ The ``autoescape`` tag has no effect on included files.
406
+
407
+ The escaping rules are implemented as follows:
408
+
409
+ * Literals (integers, booleans, arrays, ...) used in the template directly as
410
+ variables or filter arguments are never automatically escaped:
411
+
412
+ .. code-block:: jinja
413
+
414
+ {{ "Twig<br />" }} {# won't be escaped #}
415
+
416
+ {% set text = "Twig<br />" %}
417
+ {{ text }} {# will be escaped #}
418
+
419
+ * Expressions which the result is always a literal or a variable marked safe
420
+ are never automatically escaped:
421
+
422
+ .. code-block:: jinja
423
+
424
+ {{ foo ? "Twig<br />" : "<br />Twig" }} {# won't be escaped #}
425
+
426
+ {% set text = "Twig<br />" %}
427
+ {{ foo ? text : "<br />Twig" }} {# will be escaped #}
428
+
429
+ {% set text = "Twig<br />" %}
430
+ {{ foo ? text|raw : "<br />Twig" }} {# won't be escaped #}
431
+
432
+ {% set text = "Twig<br />" %}
433
+ {{ foo ? text|escape : "<br />Twig" }} {# the result of the expression won't be escaped #}
434
+
435
+ * Escaping is applied before printing, after any other filter is applied:
436
+
437
+ .. code-block:: jinja
438
+
439
+ {{ var|upper }} {# is equivalent to {{ var|upper|escape }} #}
440
+
441
+ * The `raw` filter should only be used at the end of the filter chain:
442
+
443
+ .. code-block:: jinja
444
+
445
+ {{ var|raw|upper }} {# will be escaped #}
446
+
447
+ {{ var|upper|raw }} {# won't be escaped #}
448
+
449
+ * Automatic escaping is not applied if the last filter in the chain is marked
450
+ safe for the current context (e.g. ``html`` or ``js``). ``escape`` and
451
+ ``escape('html')`` are marked safe for HTML, ``escape('js')`` is marked
452
+ safe for JavaScript, ``raw`` is marked safe for everything.
453
+
454
+ .. code-block:: jinja
455
+
456
+ {% autoescape 'js' %}
457
+ {{ var|escape('html') }} {# will be escaped for HTML and JavaScript #}
458
+ {{ var }} {# will be escaped for JavaScript #}
459
+ {{ var|escape('js') }} {# won't be double-escaped #}
460
+ {% endautoescape %}
461
+
462
+ .. note::
463
+
464
+ Note that autoescaping has some limitations as escaping is applied on
465
+ expressions after evaluation. For instance, when working with
466
+ concatenation, ``{{ foo|raw ~ bar }}`` won't give the expected result as
467
+ escaping is applied on the result of the concatenation, not on the
468
+ individual variables (so, the ``raw`` filter won't have any effect here).
469
+
470
+ Sandbox Extension
471
+ ~~~~~~~~~~~~~~~~~
472
+
473
+ The ``sandbox`` extension can be used to evaluate untrusted code. Access to
474
+ unsafe attributes and methods is prohibited. The sandbox security is managed
475
+ by a policy instance. By default, Twig comes with one policy class:
476
+ ``Twig_Sandbox_SecurityPolicy``. This class allows you to white-list some
477
+ tags, filters, properties, and methods::
478
+
479
+ $tags = array('if');
480
+ $filters = array('upper');
481
+ $methods = array(
482
+ 'Article' => array('getTitle', 'getBody'),
483
+ );
484
+ $properties = array(
485
+ 'Article' => array('title', 'body'),
486
+ );
487
+ $functions = array('range');
488
+ $policy = new Twig_Sandbox_SecurityPolicy($tags, $filters, $methods, $properties, $functions);
489
+
490
+ With the previous configuration, the security policy will only allow usage of
491
+ the ``if`` tag, and the ``upper`` filter. Moreover, the templates will only be
492
+ able to call the ``getTitle()`` and ``getBody()`` methods on ``Article``
493
+ objects, and the ``title`` and ``body`` public properties. Everything else
494
+ won't be allowed and will generate a ``Twig_Sandbox_SecurityError`` exception.
495
+
496
+ The policy object is the first argument of the sandbox constructor::
497
+
498
+ $sandbox = new Twig_Extension_Sandbox($policy);
499
+ $twig->addExtension($sandbox);
500
+
501
+ By default, the sandbox mode is disabled and should be enabled when including
502
+ untrusted template code by using the ``sandbox`` tag:
503
+
504
+ .. code-block:: jinja
505
+
506
+ {% sandbox %}
507
+ {% include 'user.html' %}
508
+ {% endsandbox %}
509
+
510
+ You can sandbox all templates by passing ``true`` as the second argument of
511
+ the extension constructor::
512
+
513
+ $sandbox = new Twig_Extension_Sandbox($policy, true);
514
+
515
+ Profiler Extension
516
+ ~~~~~~~~~~~~~~~~~~
517
+
518
+ .. versionadded:: 1.18
519
+ The Profile extension was added in Twig 1.18.
520
+
521
+ The ``profiler`` extension enables a profiler for Twig templates; it should
522
+ only be used on your development machines as it adds some overhead::
523
+
524
+ $profile = new Twig_Profiler_Profile();
525
+ $twig->addExtension(new Twig_Extension_Profiler($profile));
526
+
527
+ $dumper = new Twig_Profiler_Dumper_Text();
528
+ echo $dumper->dump($profile);
529
+
530
+ A profile contains information about time and memory consumption for template,
531
+ block, and macro executions.
532
+
533
+ You can also dump the data in a `Blackfire.io <https://blackfire.io/>`_
534
+ compatible format::
535
+
536
+ $dumper = new Twig_Profiler_Dumper_Blackfire();
537
+ file_put_contents('/path/to/profile.prof', $dumper->dump($profile));
538
+
539
+ Upload the profile to visualize it (create a `free account
540
+ <https://blackfire.io/signup>`_ first):
541
+
542
+ .. code-block:: sh
543
+
544
+ blackfire --slot=7 upload /path/to/profile.prof
545
+
546
+ Optimizer Extension
547
+ ~~~~~~~~~~~~~~~~~~~
548
+
549
+ The ``optimizer`` extension optimizes the node tree before compilation::
550
+
551
+ $twig->addExtension(new Twig_Extension_Optimizer());
552
+
553
+ By default, all optimizations are turned on. You can select the ones you want
554
+ to enable by passing them to the constructor::
555
+
556
+ $optimizer = new Twig_Extension_Optimizer(Twig_NodeVisitor_Optimizer::OPTIMIZE_FOR);
557
+
558
+ $twig->addExtension($optimizer);
559
+
560
+ Twig supports the following optimizations:
561
+
562
+ * ``Twig_NodeVisitor_Optimizer::OPTIMIZE_ALL``, enables all optimizations
563
+ (this is the default value).
564
+ * ``Twig_NodeVisitor_Optimizer::OPTIMIZE_NONE``, disables all optimizations.
565
+ This reduces the compilation time, but it can increase the execution time
566
+ and the consumed memory.
567
+ * ``Twig_NodeVisitor_Optimizer::OPTIMIZE_FOR``, optimizes the ``for`` tag by
568
+ removing the ``loop`` variable creation whenever possible.
569
+ * ``Twig_NodeVisitor_Optimizer::OPTIMIZE_RAW_FILTER``, removes the ``raw``
570
+ filter whenever possible.
571
+ * ``Twig_NodeVisitor_Optimizer::OPTIMIZE_VAR_ACCESS``, simplifies the creation
572
+ and access of variables in the compiled templates whenever possible.
573
+
574
+ Exceptions
575
+ ----------
576
+
577
+ Twig can throw exceptions:
578
+
579
+ * ``Twig_Error``: The base exception for all errors.
580
+
581
+ * ``Twig_Error_Syntax``: Thrown to tell the user that there is a problem with
582
+ the template syntax.
583
+
584
+ * ``Twig_Error_Runtime``: Thrown when an error occurs at runtime (when a filter
585
+ does not exist for instance).
586
+
587
+ * ``Twig_Error_Loader``: Thrown when an error occurs during template loading.
588
+
589
+ * ``Twig_Sandbox_SecurityError``: Thrown when an unallowed tag, filter, or
590
+ method is called in a sandboxed template.
library/twig/twig/doc/coding_standards.rst ADDED
@@ -0,0 +1,101 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Coding Standards
2
+ ================
3
+
4
+ When writing Twig templates, we recommend you to follow these official coding
5
+ standards:
6
+
7
+ * Put one (and only one) space after the start of a delimiter (``{{``, ``{%``,
8
+ and ``{#``) and before the end of a delimiter (``}}``, ``%}``, and ``#}``):
9
+
10
+ .. code-block:: jinja
11
+
12
+ {{ foo }}
13
+ {# comment #}
14
+ {% if foo %}{% endif %}
15
+
16
+ When using the whitespace control character, do not put any spaces between
17
+ it and the delimiter:
18
+
19
+ .. code-block:: jinja
20
+
21
+ {{- foo -}}
22
+ {#- comment -#}
23
+ {%- if foo -%}{%- endif -%}
24
+
25
+ * Put one (and only one) space before and after the following operators:
26
+ comparison operators (``==``, ``!=``, ``<``, ``>``, ``>=``, ``<=``), math
27
+ operators (``+``, ``-``, ``/``, ``*``, ``%``, ``//``, ``**``), logic
28
+ operators (``not``, ``and``, ``or``), ``~``, ``is``, ``in``, and the ternary
29
+ operator (``?:``):
30
+
31
+ .. code-block:: jinja
32
+
33
+ {{ 1 + 2 }}
34
+ {{ foo ~ bar }}
35
+ {{ true ? true : false }}
36
+
37
+ * Put one (and only one) space after the ``:`` sign in hashes and ``,`` in
38
+ arrays and hashes:
39
+
40
+ .. code-block:: jinja
41
+
42
+ {{ [1, 2, 3] }}
43
+ {{ {'foo': 'bar'} }}
44
+
45
+ * Do not put any spaces after an opening parenthesis and before a closing
46
+ parenthesis in expressions:
47
+
48
+ .. code-block:: jinja
49
+
50
+ {{ 1 + (2 * 3) }}
51
+
52
+ * Do not put any spaces before and after string delimiters:
53
+
54
+ .. code-block:: jinja
55
+
56
+ {{ 'foo' }}
57
+ {{ "foo" }}
58
+
59
+ * Do not put any spaces before and after the following operators: ``|``,
60
+ ``.``, ``..``, ``[]``:
61
+
62
+ .. code-block:: jinja
63
+
64
+ {{ foo|upper|lower }}
65
+ {{ user.name }}
66
+ {{ user[name] }}
67
+ {% for i in 1..12 %}{% endfor %}
68
+
69
+ * Do not put any spaces before and after the parenthesis used for filter and
70
+ function calls:
71
+
72
+ .. code-block:: jinja
73
+
74
+ {{ foo|default('foo') }}
75
+ {{ range(1..10) }}
76
+
77
+ * Do not put any spaces before and after the opening and the closing of arrays
78
+ and hashes:
79
+
80
+ .. code-block:: jinja
81
+
82
+ {{ [1, 2, 3] }}
83
+ {{ {'foo': 'bar'} }}
84
+
85
+ * Use lower cased and underscored variable names:
86
+
87
+ .. code-block:: jinja
88
+
89
+ {% set foo = 'foo' %}
90
+ {% set foo_bar = 'foo' %}
91
+
92
+ * Indent your code inside tags (use the same indentation as the one used for
93
+ the target language of the rendered template):
94
+
95
+ .. code-block:: jinja
96
+
97
+ {% block foo %}
98
+ {% if true %}
99
+ true
100
+ {% endif %}
101
+ {% endblock %}
library/twig/twig/doc/deprecated.rst ADDED
@@ -0,0 +1,221 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Deprecated Features
2
+ ===================
3
+
4
+ This document lists all deprecated features in Twig. Deprecated features are
5
+ kept for backward compatibility and removed in the next major release (a
6
+ feature that was deprecated in Twig 1.x is removed in Twig 2.0).
7
+
8
+ Deprecation Notices
9
+ -------------------
10
+
11
+ As of Twig 1.21, Twig generates deprecation notices when a template uses
12
+ deprecated features. See :ref:`deprecation-notices` for more information.
13
+
14
+ Macros
15
+ ------
16
+
17
+ As of Twig 2.0, macros imported in a file are not available in child templates
18
+ anymore (via an ``include`` call for instance). You need to import macros
19
+ explicitly in each file where you are using them.
20
+
21
+ Token Parsers
22
+ -------------
23
+
24
+ * As of Twig 1.x, the token parser broker sub-system is deprecated. The
25
+ following class and interface will be removed in 2.0:
26
+
27
+ * ``Twig_TokenParserBrokerInterface``
28
+ * ``Twig_TokenParserBroker``
29
+
30
+ * As of Twig 1.27, ``Twig_Parser::getFilename()`` is deprecated. From a token
31
+ parser, use ``$this->parser->getStream()->getSourceContext()->getPath()`` instead.
32
+
33
+ * As of Twig 1.27, ``Twig_Parser::getEnvironment()`` is deprecated.
34
+
35
+ Extensions
36
+ ----------
37
+
38
+ * As of Twig 1.x, the ability to remove an extension is deprecated and the
39
+ ``Twig_Environment::removeExtension()`` method will be removed in 2.0.
40
+
41
+ * As of Twig 1.23, the ``Twig_ExtensionInterface::initRuntime()`` method is
42
+ deprecated. You have two options to avoid the deprecation notice: if you
43
+ implement this method to store the environment for your custom filters,
44
+ functions, or tests, use the ``needs_environment`` option instead; if you
45
+ have more complex needs, explicitly implement
46
+ ``Twig_Extension_InitRuntimeInterface`` (not recommended).
47
+
48
+ * As of Twig 1.23, the ``Twig_ExtensionInterface::getGlobals()`` method is
49
+ deprecated. Implement ``Twig_Extension_GlobalsInterface`` to avoid
50
+ deprecation notices.
51
+
52
+ * As of Twig 1.26, the ``Twig_ExtensionInterface::getName()`` method is
53
+ deprecated and it is not used internally anymore.
54
+
55
+ PEAR
56
+ ----
57
+
58
+ PEAR support has been discontinued in Twig 1.15.1, and no PEAR packages are
59
+ provided anymore. Use Composer instead.
60
+
61
+ Filters
62
+ -------
63
+
64
+ * As of Twig 1.x, use ``Twig_SimpleFilter`` to add a filter. The following
65
+ classes and interfaces will be removed in 2.0:
66
+
67
+ * ``Twig_FilterInterface``
68
+ * ``Twig_FilterCallableInterface``
69
+ * ``Twig_Filter``
70
+ * ``Twig_Filter_Function``
71
+ * ``Twig_Filter_Method``
72
+ * ``Twig_Filter_Node``
73
+
74
+ * As of Twig 2.x, the ``Twig_SimpleFilter`` class is deprecated and will be
75
+ removed in Twig 3.x (use ``Twig_Filter`` instead). In Twig 2.x,
76
+ ``Twig_SimpleFilter`` is just an alias for ``Twig_Filter``.
77
+
78
+ Functions
79
+ ---------
80
+
81
+ * As of Twig 1.x, use ``Twig_SimpleFunction`` to add a function. The following
82
+ classes and interfaces will be removed in 2.0:
83
+
84
+ * ``Twig_FunctionInterface``
85
+ * ``Twig_FunctionCallableInterface``
86
+ * ``Twig_Function``
87
+ * ``Twig_Function_Function``
88
+ * ``Twig_Function_Method``
89
+ * ``Twig_Function_Node``
90
+
91
+ * As of Twig 2.x, the ``Twig_SimpleFunction`` class is deprecated and will be
92
+ removed in Twig 3.x (use ``Twig_Function`` instead). In Twig 2.x,
93
+ ``Twig_SimpleFunction`` is just an alias for ``Twig_Function``.
94
+
95
+ Tests
96
+ -----
97
+
98
+ * As of Twig 1.x, use ``Twig_SimpleTest`` to add a test. The following classes
99
+ and interfaces will be removed in 2.0:
100
+
101
+ * ``Twig_TestInterface``
102
+ * ``Twig_TestCallableInterface``
103
+ * ``Twig_Test``
104
+ * ``Twig_Test_Function``
105
+ * ``Twig_Test_Method``
106
+ * ``Twig_Test_Node``
107
+
108
+ * As of Twig 2.x, the ``Twig_SimpleTest`` class is deprecated and will be
109
+ removed in Twig 3.x (use ``Twig_Test`` instead). In Twig 2.x,
110
+ ``Twig_SimpleTest`` is just an alias for ``Twig_Test``.
111
+
112
+ * The ``sameas`` and ``divisibleby`` tests are deprecated in favor of ``same
113
+ as`` and ``divisible by`` respectively.
114
+
115
+ Tags
116
+ ----
117
+
118
+ * As of Twig 1.x, the ``raw`` tag is deprecated. You should use ``verbatim``
119
+ instead.
120
+
121
+ Nodes
122
+ -----
123
+
124
+ * As of Twig 1.x, ``Node::toXml()`` is deprecated and will be removed in Twig
125
+ 2.0.
126
+
127
+ * As of Twig 1.26, ``Node::$nodes`` should only contains ``Twig_Node``
128
+ instances, storing a ``null`` value is deprecated and won't be possible in
129
+ Twig 2.x.
130
+
131
+ * As of Twig 1.27, the ``filename`` attribute on ``Twig_Node_Module`` is
132
+ deprecated. Use ``getName()`` instead.
133
+
134
+ * As of Twig 1.27, the ``Twig_Node::getFilename()/Twig_Node::getLine()``
135
+ methods are deprecated, use
136
+ ``Twig_Node::getTemplateName()/Twig_Node::getTemplateLine()`` instead.
137
+
138
+ Interfaces
139
+ ----------
140
+
141
+ * As of Twig 2.x, the following interfaces are deprecated and empty (they will
142
+ be removed in Twig 3.0):
143
+
144
+ * ``Twig_CompilerInterface`` (use ``Twig_Compiler`` instead)
145
+ * ``Twig_LexerInterface`` (use ``Twig_Lexer`` instead)
146
+ * ``Twig_NodeInterface`` (use ``Twig_Node`` instead)
147
+ * ``Twig_ParserInterface`` (use ``Twig_Parser`` instead)
148
+ * ``Twig_ExistsLoaderInterface`` (merged with ``Twig_LoaderInterface``)
149
+ * ``Twig_SourceContextLoaderInterface`` (merged with ``Twig_LoaderInterface``)
150
+ * ``Twig_TemplateInterface`` (use ``Twig_Template`` instead, and use
151
+ those constants Twig_Template::ANY_CALL, Twig_Template::ARRAY_CALL,
152
+ Twig_Template::METHOD_CALL)
153
+
154
+ Compiler
155
+ --------
156
+
157
+ * As of Twig 1.26, the ``Twig_Compiler::getFilename()`` has been deprecated.
158
+ You should not use it anyway as its values is not reliable.
159
+
160
+ * As of Twig 1.27, the ``Twig_Compiler::addIndentation()`` has been deprecated.
161
+ Use ``Twig_Compiler::write('')`` instead.
162
+
163
+ Loaders
164
+ -------
165
+
166
+ * As of Twig 1.x, ``Twig_Loader_String`` is deprecated and will be removed in
167
+ 2.0. You can render a string via ``Twig_Environment::createTemplate()``.
168
+
169
+ * As of Twig 1.27, ``Twig_LoaderInterface::getSource()`` is deprecated.
170
+ Implement ``Twig_SourceContextLoaderInterface`` instead and use
171
+ ``getSourceContext()``.
172
+
173
+ Node Visitors
174
+ -------------
175
+
176
+ * Because of the removal of ``Twig_NodeInterface`` in 2.0, you need to extend
177
+ ``Twig_BaseNodeVisitor`` instead of implementing ``Twig_NodeVisitorInterface``
178
+ directly to make your node visitors compatible with both Twig 1.x and 2.x.
179
+
180
+ Globals
181
+ -------
182
+
183
+ * As of Twig 2.x, the ability to register a global variable after the runtime
184
+ or the extensions have been initialized is not possible anymore (but
185
+ changing the value of an already registered global is possible).
186
+
187
+ * As of Twig 1.x, using the ``_self`` global variable to get access to the
188
+ current ``Twig_Template`` instance is deprecated; most usages only need the
189
+ current template name, which will continue to work in Twig 2.0. In Twig 2.0,
190
+ ``_self`` returns the current template name instead of the current
191
+ ``Twig_Template`` instance. If you are using ``{{ _self.templateName }}``,
192
+ just replace it with ``{{ _self }}``.
193
+
194
+ Miscellaneous
195
+ -------------
196
+
197
+ * As of Twig 1.x, ``Twig_Environment::clearTemplateCache()``,
198
+ ``Twig_Environment::writeCacheFile()``,
199
+ ``Twig_Environment::clearCacheFiles()``,
200
+ ``Twig_Environment::getCacheFilename()``,
201
+ ``Twig_Environment::getTemplateClassPrefix()``,
202
+ ``Twig_Environment::getLexer()``, ``Twig_Environment::getParser()``, and
203
+ ``Twig_Environment::getCompiler()`` are deprecated and will be removed in 2.0.
204
+
205
+ * As of Twig 1.x, ``Twig_Template::getEnvironment()`` and
206
+ ``Twig_TemplateInterface::getEnvironment()`` are deprecated and will be
207
+ removed in 2.0.
208
+
209
+ * As of Twig 1.27, ``Twig_Error::getTemplateFile()`` and
210
+ ``Twig_Error::setTemplateFile()`` are deprecated. Use
211
+ ``Twig_Error::getTemplateName()`` and ``Twig_Error::setTemplateName()``
212
+ instead.
213
+
214
+ * As of Twig 1.27, ``Twig_Template::getSource()`` is deprecated. Use
215
+ ``Twig_Template::getSourceContext()`` instead.
216
+
217
+ * As of Twig 1.27, ``Twig_Parser::addHandler()`` and
218
+ ``Twig_Parser::addNodeVisitor()`` are deprecated and will be removed in 2.0.
219
+
220
+ * As of Twig 1.29, some classes are marked as being final via the `@final`
221
+ annotation. Those classes will be marked as final in 2.0.
library/twig/twig/doc/filters/abs.rst ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ``abs``
2
+ =======
3
+
4
+ The ``abs`` filter returns the absolute value.
5
+
6
+ .. code-block:: jinja
7
+
8
+ {# number = -5 #}
9
+
10
+ {{ number|abs }}
11
+
12
+ {# outputs 5 #}
13
+
14
+ .. note::
15
+
16
+ Internally, Twig uses the PHP `abs`_ function.
17
+
18
+ .. _`abs`: http://php.net/abs
library/twig/twig/doc/filters/batch.rst ADDED
@@ -0,0 +1,51 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ``batch``
2
+ =========
3
+
4
+ .. versionadded:: 1.12.3
5
+ The ``batch`` filter was added in Twig 1.12.3.
6
+
7
+ The ``batch`` filter "batches" items by returning a list of lists with the
8
+ given number of items. A second parameter can be provided and used to fill in
9
+ missing items:
10
+
11
+ .. code-block:: jinja
12
+
13
+ {% set items = ['a', 'b', 'c', 'd', 'e', 'f', 'g'] %}
14
+
15
+ <table>
16
+ {% for row in items|batch(3, 'No item') %}
17
+ <tr>
18
+ {% for column in row %}
19
+ <td>{{ column }}</td>
20
+ {% endfor %}
21
+ </tr>
22
+ {% endfor %}
23
+ </table>
24
+
25
+ The above example will be rendered as:
26
+
27
+ .. code-block:: jinja
28
+
29
+ <table>
30
+ <tr>
31
+ <td>a</td>
32
+ <td>b</td>
33
+ <td>c</td>
34
+ </tr>
35
+ <tr>
36
+ <td>d</td>
37
+ <td>e</td>
38
+ <td>f</td>
39
+ </tr>
40
+ <tr>
41
+ <td>g</td>
42
+ <td>No item</td>
43
+ <td>No item</td>
44
+ </tr>
45
+ </table>
46
+
47
+ Arguments
48
+ ---------
49
+
50
+ * ``size``: The size of the batch; fractional numbers will be rounded up
51
+ * ``fill``: Used to fill in missing items
library/twig/twig/doc/filters/capitalize.rst ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ ``capitalize``
2
+ ==============
3
+
4
+ The ``capitalize`` filter capitalizes a value. The first character will be
5
+ uppercase, all others lowercase:
6
+
7
+ .. code-block:: jinja
8
+
9
+ {{ 'my first car'|capitalize }}
10
+
11
+ {# outputs 'My first car' #}
library/twig/twig/doc/filters/convert_encoding.rst ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ``convert_encoding``
2
+ ====================
3
+
4
+ .. versionadded:: 1.4
5
+ The ``convert_encoding`` filter was added in Twig 1.4.
6
+
7
+ The ``convert_encoding`` filter converts a string from one encoding to
8
+ another. The first argument is the expected output charset and the second one
9
+ is the input charset:
10
+
11
+ .. code-block:: jinja
12
+
13
+ {{ data|convert_encoding('UTF-8', 'iso-2022-jp') }}
14
+
15
+ .. note::
16
+
17
+ This filter relies on the `iconv`_ or `mbstring`_ extension, so one of
18
+ them must be installed. In case both are installed, `mbstring`_ is used by
19
+ default (Twig before 1.8.1 uses `iconv`_ by default).
20
+
21
+ Arguments
22
+ ---------
23
+
24
+ * ``to``: The output charset
25
+ * ``from``: The input charset
26
+
27
+ .. _`iconv`: http://php.net/iconv
28
+ .. _`mbstring`: http://php.net/mbstring
library/twig/twig/doc/filters/date.rst ADDED
@@ -0,0 +1,100 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ``date``
2
+ ========
3
+
4
+ .. versionadded:: 1.1
5
+ The timezone support has been added in Twig 1.1.
6
+
7
+ .. versionadded:: 1.5
8
+ The default date format support has been added in Twig 1.5.
9
+
10
+ .. versionadded:: 1.6.1
11
+ The default timezone support has been added in Twig 1.6.1.
12
+
13
+ .. versionadded:: 1.11.0
14
+ The introduction of the false value for the timezone was introduced in Twig 1.11.0
15
+
16
+ The ``date`` filter formats a date to a given format:
17
+
18
+ .. code-block:: jinja
19
+
20
+ {{ post.published_at|date("m/d/Y") }}
21
+
22
+ The format specifier is the same as supported by `date`_,
23
+ except when the filtered data is of type `DateInterval`_, when the format must conform to
24
+ `DateInterval::format`_ instead.
25
+
26
+ The ``date`` filter accepts strings (it must be in a format supported by the
27
+ `strtotime`_ function), `DateTime`_ instances, or `DateInterval`_ instances. For
28
+ instance, to display the current date, filter the word "now":
29
+
30
+ .. code-block:: jinja
31
+
32
+ {{ "now"|date("m/d/Y") }}
33
+
34
+ To escape words and characters in the date format use ``\\`` in front of each
35
+ character:
36
+
37
+ .. code-block:: jinja
38
+
39
+ {{ post.published_at|date("F jS \\a\\t g:ia") }}
40
+
41
+ If the value passed to the ``date`` filter is ``null``, it will return the
42
+ current date by default. If an empty string is desired instead of the current
43
+ date, use a ternary operator:
44
+
45
+ .. code-block:: jinja
46
+
47
+ {{ post.published_at is empty ? "" : post.published_at|date("m/d/Y") }}
48
+
49
+ If no format is provided, Twig will use the default one: ``F j, Y H:i``. This
50
+ default can be easily changed by calling the ``setDateFormat()`` method on the
51
+ ``core`` extension instance. The first argument is the default format for
52
+ dates and the second one is the default format for date intervals:
53
+
54
+ .. code-block:: php
55
+
56
+ $twig = new Twig_Environment($loader);
57
+ $twig->getExtension('Twig_Extension_Core')->setDateFormat('d/m/Y', '%d days');
58
+
59
+ // before Twig 1.26
60
+ $twig->getExtension('core')->setDateFormat('d/m/Y', '%d days');
61
+
62
+ Timezone
63
+ --------
64
+
65
+ By default, the date is displayed by applying the default timezone (the one
66
+ specified in php.ini or declared in Twig -- see below), but you can override
67
+ it by explicitly specifying a timezone:
68
+
69
+ .. code-block:: jinja
70
+
71
+ {{ post.published_at|date("m/d/Y", "Europe/Paris") }}
72
+
73
+ If the date is already a DateTime object, and if you want to keep its current
74
+ timezone, pass ``false`` as the timezone value:
75
+
76
+ .. code-block:: jinja
77
+
78
+ {{ post.published_at|date("m/d/Y", false) }}
79
+
80
+ The default timezone can also be set globally by calling ``setTimezone()``:
81
+
82
+ .. code-block:: php
83
+
84
+ $twig = new Twig_Environment($loader);
85
+ $twig->getExtension('Twig_Extension_Core')->setTimezone('Europe/Paris');
86
+
87
+ // before Twig 1.26
88
+ $twig->getExtension('core')->setTimezone('Europe/Paris');
89
+
90
+ Arguments
91
+ ---------
92
+
93
+ * ``format``: The date format
94
+ * ``timezone``: The date timezone
95
+
96
+ .. _`strtotime`: http://www.php.net/strtotime
97
+ .. _`DateTime`: http://www.php.net/DateTime
98
+ .. _`DateInterval`: http://www.php.net/DateInterval
99
+ .. _`date`: http://www.php.net/date
100
+ .. _`DateInterval::format`: http://www.php.net/DateInterval.format
library/twig/twig/doc/filters/date_modify.rst ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ``date_modify``
2
+ ===============
3
+
4
+ .. versionadded:: 1.9.0
5
+ The date_modify filter has been added in Twig 1.9.0.
6
+
7
+ The ``date_modify`` filter modifies a date with a given modifier string:
8
+
9
+ .. code-block:: jinja
10
+
11
+ {{ post.published_at|date_modify("+1 day")|date("m/d/Y") }}
12
+
13
+ The ``date_modify`` filter accepts strings (it must be in a format supported
14
+ by the `strtotime`_ function) or `DateTime`_ instances. You can easily combine
15
+ it with the :doc:`date<date>` filter for formatting.
16
+
17
+ Arguments
18
+ ---------
19
+
20
+ * ``modifier``: The modifier
21
+
22
+ .. _`strtotime`: http://www.php.net/strtotime
23
+ .. _`DateTime`: http://www.php.net/DateTime
library/twig/twig/doc/filters/default.rst ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ``default``
2
+ ===========
3
+
4
+ The ``default`` filter returns the passed default value if the value is
5
+ undefined or empty, otherwise the value of the variable:
6
+
7
+ .. code-block:: jinja
8
+
9
+ {{ var|default('var is not defined') }}
10
+
11
+ {{ var.foo|default('foo item on var is not defined') }}
12
+
13
+ {{ var['foo']|default('foo item on var is not defined') }}
14
+
15
+ {{ ''|default('passed var is empty') }}
16
+
17
+ When using the ``default`` filter on an expression that uses variables in some
18
+ method calls, be sure to use the ``default`` filter whenever a variable can be
19
+ undefined:
20
+
21
+ .. code-block:: jinja
22
+
23
+ {{ var.method(foo|default('foo'))|default('foo') }}
24
+
25
+ .. note::
26
+
27
+ Read the documentation for the :doc:`defined<../tests/defined>` and
28
+ :doc:`empty<../tests/empty>` tests to learn more about their semantics.
29
+
30
+ Arguments
31
+ ---------
32
+
33
+ * ``default``: The default value
library/twig/twig/doc/filters/escape.rst ADDED
@@ -0,0 +1,119 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ``escape``
2
+ ==========
3
+
4
+ .. versionadded:: 1.9.0
5
+ The ``css``, ``url``, and ``html_attr`` strategies were added in Twig
6
+ 1.9.0.
7
+
8
+ .. versionadded:: 1.14.0
9
+ The ability to define custom escapers was added in Twig 1.14.0.
10
+
11
+ The ``escape`` filter escapes a string for safe insertion into the final
12
+ output. It supports different escaping strategies depending on the template
13
+ context.
14
+
15
+ By default, it uses the HTML escaping strategy:
16
+
17
+ .. code-block:: jinja
18
+
19
+ {{ user.username|escape }}
20
+
21
+ For convenience, the ``e`` filter is defined as an alias:
22
+
23
+ .. code-block:: jinja
24
+
25
+ {{ user.username|e }}
26
+
27
+ The ``escape`` filter can also be used in other contexts than HTML thanks to
28
+ an optional argument which defines the escaping strategy to use:
29
+
30
+ .. code-block:: jinja
31
+
32
+ {{ user.username|e }}
33
+ {# is equivalent to #}
34
+ {{ user.username|e('html') }}
35
+
36
+ And here is how to escape variables included in JavaScript code:
37
+
38
+ .. code-block:: jinja
39
+
40
+ {{ user.username|escape('js') }}
41
+ {{ user.username|e('js') }}
42
+
43
+ The ``escape`` filter supports the following escaping strategies:
44
+
45
+ * ``html``: escapes a string for the **HTML body** context.
46
+
47
+ * ``js``: escapes a string for the **JavaScript context**.
48
+
49
+ * ``css``: escapes a string for the **CSS context**. CSS escaping can be
50
+ applied to any string being inserted into CSS and escapes everything except
51
+ alphanumerics.
52
+
53
+ * ``url``: escapes a string for the **URI or parameter contexts**. This should
54
+ not be used to escape an entire URI; only a subcomponent being inserted.
55
+
56
+ * ``html_attr``: escapes a string for the **HTML attribute** context.
57
+
58
+ .. note::
59
+
60
+ Internally, ``escape`` uses the PHP native `htmlspecialchars`_ function
61
+ for the HTML escaping strategy.
62
+
63
+ .. caution::
64
+
65
+ When using automatic escaping, Twig tries to not double-escape a variable
66
+ when the automatic escaping strategy is the same as the one applied by the
67
+ escape filter; but that does not work when using a variable as the
68
+ escaping strategy:
69
+
70
+ .. code-block:: jinja
71
+
72
+ {% set strategy = 'html' %}
73
+
74
+ {% autoescape 'html' %}
75
+ {{ var|escape('html') }} {# won't be double-escaped #}
76
+ {{ var|escape(strategy) }} {# will be double-escaped #}
77
+ {% endautoescape %}
78
+
79
+ When using a variable as the escaping strategy, you should disable
80
+ automatic escaping:
81
+
82
+ .. code-block:: jinja
83
+
84
+ {% set strategy = 'html' %}
85
+
86
+ {% autoescape 'html' %}
87
+ {{ var|escape(strategy)|raw }} {# won't be double-escaped #}
88
+ {% endautoescape %}
89
+
90
+ Custom Escapers
91
+ ---------------
92
+
93
+ You can define custom escapers by calling the ``setEscaper()`` method on the
94
+ ``core`` extension instance. The first argument is the escaper name (to be
95
+ used in the ``escape`` call) and the second one must be a valid PHP callable:
96
+
97
+ .. code-block:: php
98
+
99
+ $twig = new Twig_Environment($loader);
100
+ $twig->getExtension('Twig_Extension_Core')->setEscaper('csv', 'csv_escaper');
101
+
102
+ // before Twig 1.26
103
+ $twig->getExtension('core')->setEscaper('csv', 'csv_escaper');
104
+
105
+ When called by Twig, the callable receives the Twig environment instance, the
106
+ string to escape, and the charset.
107
+
108
+ .. note::
109
+
110
+ Built-in escapers cannot be overridden mainly they should be considered as
111
+ the final implementation and also for better performance.
112
+
113
+ Arguments
114
+ ---------
115
+
116
+ * ``strategy``: The escaping strategy
117
+ * ``charset``: The string charset
118
+
119
+ .. _`htmlspecialchars`: http://php.net/htmlspecialchars
library/twig/twig/doc/filters/first.rst ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ``first``
2
+ =========
3
+
4
+ .. versionadded:: 1.12.2
5
+ The ``first`` filter was added in Twig 1.12.2.
6
+
7
+ The ``first`` filter returns the first "element" of a sequence, a mapping, or
8
+ a string:
9
+
10
+ .. code-block:: jinja
11
+
12
+ {{ [1, 2, 3, 4]|first }}
13
+ {# outputs 1 #}
14
+
15
+ {{ { a: 1, b: 2, c: 3, d: 4 }|first }}
16
+ {# outputs 1 #}
17
+
18
+ {{ '1234'|first }}
19
+ {# outputs 1 #}
20
+
21
+ .. note::
22
+
23
+ It also works with objects implementing the `Traversable`_ interface.
24
+
25
+ .. _`Traversable`: http://php.net/manual/en/class.traversable.php
library/twig/twig/doc/filters/format.rst ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ``format``
2
+ ==========
3
+
4
+ The ``format`` filter formats a given string by replacing the placeholders
5
+ (placeholders follows the `sprintf`_ notation):
6
+
7
+ .. code-block:: jinja
8
+
9
+ {{ "I like %s and %s."|format(foo, "bar") }}
10
+
11
+ {# outputs I like foo and bar
12
+ if the foo parameter equals to the foo string. #}
13
+
14
+ .. _`sprintf`: http://www.php.net/sprintf
15
+
16
+ .. seealso:: :doc:`replace<replace>`
library/twig/twig/doc/filters/index.rst ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Filters
2
+ =======
3
+
4
+ .. toctree::
5
+ :maxdepth: 1
6
+
7
+ abs
8
+ batch
9
+ capitalize
10
+ convert_encoding
11
+ date
12
+ date_modify
13
+ default
14
+ escape
15
+ first
16
+ format
17
+ join
18
+ json_encode
19
+ keys
20
+ last
21
+ length
22
+ lower
23
+ merge
24
+ nl2br
25
+ number_format
26
+ raw
27
+ replace
28
+ reverse
29
+ round
30
+ slice
31
+ sort
32
+ split
33
+ striptags
34
+ title
35
+ trim
36
+ upper
37
+ url_encode
library/twig/twig/doc/filters/join.rst ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ``join``
2
+ ========
3
+
4
+ The ``join`` filter returns a string which is the concatenation of the items
5
+ of a sequence:
6
+
7
+ .. code-block:: jinja
8
+
9
+ {{ [1, 2, 3]|join }}
10
+ {# returns 123 #}
11
+
12
+ The separator between elements is an empty string per default, but you can
13
+ define it with the optional first parameter:
14
+
15
+ .. code-block:: jinja
16
+
17
+ {{ [1, 2, 3]|join('|') }}
18
+ {# outputs 1|2|3 #}
19
+
20
+ Arguments
21
+ ---------
22
+
23
+ * ``glue``: The separator
library/twig/twig/doc/filters/json_encode.rst ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ``json_encode``
2
+ ===============
3
+
4
+ The ``json_encode`` filter returns the JSON representation of a value:
5
+
6
+ .. code-block:: jinja
7
+
8
+ {{ data|json_encode() }}
9
+
10
+ .. note::
11
+
12
+ Internally, Twig uses the PHP `json_encode`_ function.
13
+
14
+ Arguments
15
+ ---------
16
+
17
+ * ``options``: A bitmask of `json_encode options`_ (``{{
18
+ data|json_encode(constant('JSON_PRETTY_PRINT')) }}``)
19
+
20
+ .. _`json_encode`: http://php.net/json_encode
21
+ .. _`json_encode options`: http://www.php.net/manual/en/json.constants.php
library/twig/twig/doc/filters/keys.rst ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ ``keys``
2
+ ========
3
+
4
+ The ``keys`` filter returns the keys of an array. It is useful when you want to
5
+ iterate over the keys of an array:
6
+
7
+ .. code-block:: jinja
8
+
9
+ {% for key in array|keys %}
10
+ ...
11
+ {% endfor %}
library/twig/twig/doc/filters/last.rst ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ``last``
2
+ ========
3
+
4
+ .. versionadded:: 1.12.2
5
+ The ``last`` filter was added in Twig 1.12.2.
6
+
7
+ The ``last`` filter returns the last "element" of a sequence, a mapping, or
8
+ a string:
9
+
10
+ .. code-block:: jinja
11
+
12
+ {{ [1, 2, 3, 4]|last }}
13
+ {# outputs 4 #}
14
+
15
+ {{ { a: 1, b: 2, c: 3, d: 4 }|last }}
16
+ {# outputs 4 #}
17
+
18
+ {{ '1234'|last }}
19
+ {# outputs 4 #}
20
+
21
+ .. note::
22
+
23
+ It also works with objects implementing the `Traversable`_ interface.
24
+
25
+ .. _`Traversable`: http://php.net/manual/en/class.traversable.php
library/twig/twig/doc/filters/length.rst ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ ``length``
2
+ ==========
3
+
4
+ The ``length`` filter returns the number of items of a sequence or mapping, or
5
+ the length of a string:
6
+
7
+ .. code-block:: jinja
8
+
9
+ {% if users|length > 10 %}
10
+ ...
11
+ {% endif %}
library/twig/twig/doc/filters/lower.rst ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ ``lower``
2
+ =========
3
+
4
+ The ``lower`` filter converts a value to lowercase:
5
+
6
+ .. code-block:: jinja
7
+
8
+ {{ 'WELCOME'|lower }}
9
+
10
+ {# outputs 'welcome' #}
library/twig/twig/doc/filters/merge.rst ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ``merge``
2
+ =========
3
+
4
+ The ``merge`` filter merges an array with another array:
5
+
6
+ .. code-block:: jinja
7
+
8
+ {% set values = [1, 2] %}
9
+
10
+ {% set values = values|merge(['apple', 'orange']) %}
11
+
12
+ {# values now contains [1, 2, 'apple', 'orange'] #}
13
+
14
+ New values are added at the end of the existing ones.
15
+
16
+ The ``merge`` filter also works on hashes:
17
+
18
+ .. code-block:: jinja
19
+
20
+ {% set items = { 'apple': 'fruit', 'orange': 'fruit', 'peugeot': 'unknown' } %}
21
+
22
+ {% set items = items|merge({ 'peugeot': 'car', 'renault': 'car' }) %}
23
+
24
+ {# items now contains { 'apple': 'fruit', 'orange': 'fruit', 'peugeot': 'car', 'renault': 'car' } #}
25
+
26
+ For hashes, the merging process occurs on the keys: if the key does not
27
+ already exist, it is added but if the key already exists, its value is
28
+ overridden.
29
+
30
+ .. tip::
31
+
32
+ If you want to ensure that some values are defined in an array (by given
33
+ default values), reverse the two elements in the call:
34
+
35
+ .. code-block:: jinja
36
+
37
+ {% set items = { 'apple': 'fruit', 'orange': 'fruit' } %}
38
+
39
+ {% set items = { 'apple': 'unknown' }|merge(items) %}
40
+
41
+ {# items now contains { 'apple': 'fruit', 'orange': 'fruit' } #}
42
+
43
+ .. note::
44
+
45
+ Internally, Twig uses the PHP `array_merge`_ function. It supports
46
+ Traversable objects by transforming those to arrays.
47
+
48
+ .. _`array_merge`: http://php.net/array_merge
library/twig/twig/doc/filters/nl2br.rst ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ``nl2br``
2
+ =========
3
+
4
+ .. versionadded:: 1.5
5
+ The ``nl2br`` filter was added in Twig 1.5.
6
+
7
+ The ``nl2br`` filter inserts HTML line breaks before all newlines in a string:
8
+
9
+ .. code-block:: jinja
10
+
11
+ {{ "I like Twig.\nYou will like it too."|nl2br }}
12
+ {# outputs
13
+
14
+ I like Twig.<br />
15
+ You will like it too.
16
+
17
+ #}
18
+
19
+ .. note::
20
+
21
+ The ``nl2br`` filter pre-escapes the input before applying the
22
+ transformation.
library/twig/twig/doc/filters/number_format.rst ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ``number_format``
2
+ =================
3
+
4
+ .. versionadded:: 1.5
5
+ The ``number_format`` filter was added in Twig 1.5
6
+
7
+ The ``number_format`` filter formats numbers. It is a wrapper around PHP's
8
+ `number_format`_ function:
9
+
10
+ .. code-block:: jinja
11
+
12
+ {{ 200.35|number_format }}
13
+
14
+ You can control the number of decimal places, decimal point, and thousands
15
+ separator using the additional arguments:
16
+
17
+ .. code-block:: jinja
18
+
19
+ {{ 9800.333|number_format(2, '.', ',') }}
20
+
21
+ If no formatting options are provided then Twig will use the default formatting
22
+ options of:
23
+
24
+ * 0 decimal places.
25
+ * ``.`` as the decimal point.
26
+ * ``,`` as the thousands separator.
27
+
28
+ These defaults can be easily changed through the core extension:
29
+
30
+ .. code-block:: php
31
+
32
+ $twig = new Twig_Environment($loader);
33
+ $twig->getExtension('Twig_Extension_Core')->setNumberFormat(3, '.', ',');
34
+
35
+ // before Twig 1.26
36
+ $twig->getExtension('core')->setNumberFormat(3, '.', ',');
37
+
38
+ The defaults set for ``number_format`` can be over-ridden upon each call using the
39
+ additional parameters.
40
+
41
+ Arguments
42
+ ---------
43
+
44
+ * ``decimal``: The number of decimal points to display
45
+ * ``decimal_point``: The character(s) to use for the decimal point
46
+ * ``thousand_sep``: The character(s) to use for the thousands separator
47
+
48
+ .. _`number_format`: http://php.net/number_format
library/twig/twig/doc/filters/raw.rst ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ``raw``
2
+ =======
3
+
4
+ The ``raw`` filter marks the value as being "safe", which means that in an
5
+ environment with automatic escaping enabled this variable will not be escaped
6
+ if ``raw`` is the last filter applied to it:
7
+
8
+ .. code-block:: jinja
9
+
10
+ {% autoescape %}
11
+ {{ var|raw }} {# var won't be escaped #}
12
+ {% endautoescape %}
13
+
14
+ .. note::
15
+
16
+ Be careful when using the ``raw`` filter inside expressions:
17
+
18
+ .. code-block:: jinja
19
+
20
+ {% autoescape %}
21
+ {% set hello = '<strong>Hello</strong>' %}
22
+ {% set hola = '<strong>Hola</strong>' %}
23
+
24
+ {{ false ? '<strong>Hola</strong>' : hello|raw }}
25
+ does not render the same as
26
+ {{ false ? hola : hello|raw }}
27
+ but renders the same as
28
+ {{ (false ? hola : hello)|raw }}
29
+ {% endautoescape %}
30
+
31
+ The first ternary statement is not escaped: ``hello`` is marked as being
32
+ safe and Twig does not escape static values (see
33
+ :doc:`escape<../tags/autoescape>`). In the second ternary statement, even
34
+ if ``hello`` is marked as safe, ``hola`` remains unsafe and so is the whole
35
+ expression. The third ternary statement is marked as safe and the result is
36
+ not escaped.
library/twig/twig/doc/filters/replace.rst ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ``replace``
2
+ ===========
3
+
4
+ The ``replace`` filter formats a given string by replacing the placeholders
5
+ (placeholders are free-form):
6
+
7
+ .. code-block:: jinja
8
+
9
+ {{ "I like %this% and %that%."|replace({'%this%': foo, '%that%': "bar"}) }}
10
+
11
+ {# outputs I like foo and bar
12
+ if the foo parameter equals to the foo string. #}
13
+
14
+ Arguments
15
+ ---------
16
+
17
+ * ``from``: The placeholder values
18
+
19
+ .. seealso:: :doc:`format<format>`
library/twig/twig/doc/filters/reverse.rst ADDED
@@ -0,0 +1,47 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ``reverse``
2
+ ===========
3
+
4
+ .. versionadded:: 1.6
5
+ Support for strings has been added in Twig 1.6.
6
+
7
+ The ``reverse`` filter reverses a sequence, a mapping, or a string:
8
+
9
+ .. code-block:: jinja
10
+
11
+ {% for user in users|reverse %}
12
+ ...
13
+ {% endfor %}
14
+
15
+ {{ '1234'|reverse }}
16
+
17
+ {# outputs 4321 #}
18
+
19
+ .. tip::
20
+
21
+ For sequences and mappings, numeric keys are not preserved. To reverse
22
+ them as well, pass ``true`` as an argument to the ``reverse`` filter:
23
+
24
+ .. code-block:: jinja
25
+
26
+ {% for key, value in {1: "a", 2: "b", 3: "c"}|reverse %}
27
+ {{ key }}: {{ value }}
28
+ {%- endfor %}
29
+
30
+ {# output: 0: c 1: b 2: a #}
31
+
32
+ {% for key, value in {1: "a", 2: "b", 3: "c"}|reverse(true) %}
33
+ {{ key }}: {{ value }}
34
+ {%- endfor %}
35
+
36
+ {# output: 3: c 2: b 1: a #}
37
+
38
+ .. note::
39
+
40
+ It also works with objects implementing the `Traversable`_ interface.
41
+
42
+ Arguments
43
+ ---------
44
+
45
+ * ``preserve_keys``: Preserve keys when reversing a mapping or a sequence.
46
+
47
+ .. _`Traversable`: http://php.net/Traversable
library/twig/twig/doc/filters/round.rst ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ``round``
2
+ =========
3
+
4
+ .. versionadded:: 1.15.0
5
+ The ``round`` filter was added in Twig 1.15.0.
6
+
7
+ The ``round`` filter rounds a number to a given precision:
8
+
9
+ .. code-block:: jinja
10
+
11
+ {{ 42.55|round }}
12
+ {# outputs 43 #}
13
+
14
+ {{ 42.55|round(1, 'floor') }}
15
+ {# outputs 42.5 #}
16
+
17
+ The ``round`` filter takes two optional arguments; the first one specifies the
18
+ precision (default is ``0``) and the second the rounding method (default is
19
+ ``common``):
20
+
21
+ * ``common`` rounds either up or down (rounds the value up to precision decimal
22
+ places away from zero, when it is half way there -- making 1.5 into 2 and
23
+ -1.5 into -2);
24
+
25
+ * ``ceil`` always rounds up;
26
+
27
+ * ``floor`` always rounds down.
28
+
29
+ .. note::
30
+
31
+ The ``//`` operator is equivalent to ``|round(0, 'floor')``.
32
+
33
+ Arguments
34
+ ---------
35
+
36
+ * ``precision``: The rounding precision
37
+ * ``method``: The rounding method
library/twig/twig/doc/filters/slice.rst ADDED
@@ -0,0 +1,71 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ``slice``
2
+ ===========
3
+
4
+ .. versionadded:: 1.6
5
+ The ``slice`` filter was added in Twig 1.6.
6
+
7
+ The ``slice`` filter extracts a slice of a sequence, a mapping, or a string:
8
+
9
+ .. code-block:: jinja
10
+
11
+ {% for i in [1, 2, 3, 4, 5]|slice(1, 2) %}
12
+ {# will iterate over 2 and 3 #}
13
+ {% endfor %}
14
+
15
+ {{ '12345'|slice(1, 2) }}
16
+
17
+ {# outputs 23 #}
18
+
19
+ You can use any valid expression for both the start and the length:
20
+
21
+ .. code-block:: jinja
22
+
23
+ {% for i in [1, 2, 3, 4, 5]|slice(start, length) %}
24
+ {# ... #}
25
+ {% endfor %}
26
+
27
+ As syntactic sugar, you can also use the ``[]`` notation:
28
+
29
+ .. code-block:: jinja
30
+
31
+ {% for i in [1, 2, 3, 4, 5][start:length] %}
32
+ {# ... #}
33
+ {% endfor %}
34
+
35
+ {{ '12345'[1:2] }} {# will display "23" #}
36
+
37
+ {# you can omit the first argument -- which is the same as 0 #}
38
+ {{ '12345'[:2] }} {# will display "12" #}
39
+
40
+ {# you can omit the last argument -- which will select everything till the end #}
41
+ {{ '12345'[2:] }} {# will display "345" #}
42
+
43
+ The ``slice`` filter works as the `array_slice`_ PHP function for arrays and
44
+ `mb_substr`_ for strings with a fallback to `substr`_.
45
+
46
+ If the start is non-negative, the sequence will start at that start in the
47
+ variable. If start is negative, the sequence will start that far from the end
48
+ of the variable.
49
+
50
+ If length is given and is positive, then the sequence will have up to that
51
+ many elements in it. If the variable is shorter than the length, then only the
52
+ available variable elements will be present. If length is given and is
53
+ negative then the sequence will stop that many elements from the end of the
54
+ variable. If it is omitted, then the sequence will have everything from offset
55
+ up until the end of the variable.
56
+
57
+ .. note::
58
+
59
+ It also works with objects implementing the `Traversable`_ interface.
60
+
61
+ Arguments
62
+ ---------
63
+
64
+ * ``start``: The start of the slice
65
+ * ``length``: The size of the slice
66
+ * ``preserve_keys``: Whether to preserve key or not (when the input is an array)
67
+
68
+ .. _`Traversable`: http://php.net/manual/en/class.traversable.php
69
+ .. _`array_slice`: http://php.net/array_slice
70
+ .. _`mb_substr` : http://php.net/mb-substr
71
+ .. _`substr`: http://php.net/substr
library/twig/twig/doc/filters/sort.rst ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ``sort``
2
+ ========
3
+
4
+ The ``sort`` filter sorts an array:
5
+
6
+ .. code-block:: jinja
7
+
8
+ {% for user in users|sort %}
9
+ ...
10
+ {% endfor %}
11
+
12
+ .. note::
13
+
14
+ Internally, Twig uses the PHP `asort`_ function to maintain index
15
+ association. It supports Traversable objects by transforming
16
+ those to arrays.
17
+
18
+ .. _`asort`: http://php.net/asort
library/twig/twig/doc/filters/split.rst ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ``split``
2
+ =========
3
+
4
+ .. versionadded:: 1.10.3
5
+ The ``split`` filter was added in Twig 1.10.3.
6
+
7
+ The ``split`` filter splits a string by the given delimiter and returns a list
8
+ of strings:
9
+
10
+ .. code-block:: jinja
11
+
12
+ {% set foo = "one,two,three"|split(',') %}
13
+ {# foo contains ['one', 'two', 'three'] #}
14
+
15
+ You can also pass a ``limit`` argument:
16
+
17
+ * If ``limit`` is positive, the returned array will contain a maximum of
18
+ limit elements with the last element containing the rest of string;
19
+
20
+ * If ``limit`` is negative, all components except the last -limit are
21
+ returned;
22
+
23
+ * If ``limit`` is zero, then this is treated as 1.
24
+
25
+ .. code-block:: jinja
26
+
27
+ {% set foo = "one,two,three,four,five"|split(',', 3) %}
28
+ {# foo contains ['one', 'two', 'three,four,five'] #}
29
+
30
+ If the ``delimiter`` is an empty string, then value will be split by equal
31
+ chunks. Length is set by the ``limit`` argument (one character by default).
32
+
33
+ .. code-block:: jinja
34
+
35
+ {% set foo = "123"|split('') %}
36
+ {# foo contains ['1', '2', '3'] #}
37
+
38
+ {% set bar = "aabbcc"|split('', 2) %}
39
+ {# bar contains ['aa', 'bb', 'cc'] #}
40
+
41
+ .. note::
42
+
43
+ Internally, Twig uses the PHP `explode`_ or `str_split`_ (if delimiter is
44
+ empty) functions for string splitting.
45
+
46
+ Arguments
47
+ ---------
48
+
49
+ * ``delimiter``: The delimiter
50
+ * ``limit``: The limit argument
51
+
52
+ .. _`explode`: http://php.net/explode
53
+ .. _`str_split`: http://php.net/str_split
library/twig/twig/doc/filters/striptags.rst ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ``striptags``
2
+ =============
3
+
4
+ The ``striptags`` filter strips SGML/XML tags and replace adjacent whitespace
5
+ by one space:
6
+
7
+ .. code-block:: jinja
8
+
9
+ {{ some_html|striptags }}
10
+
11
+ .. note::
12
+
13
+ Internally, Twig uses the PHP `strip_tags`_ function.
14
+
15
+ .. _`strip_tags`: http://php.net/strip_tags
library/twig/twig/doc/filters/title.rst ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ ``title``
2
+ =========
3
+
4
+ The ``title`` filter returns a titlecased version of the value. Words will
5
+ start with uppercase letters, all remaining characters are lowercase:
6
+
7
+ .. code-block:: jinja
8
+
9
+ {{ 'my first car'|title }}
10
+
11
+ {# outputs 'My First Car' #}
library/twig/twig/doc/filters/trim.rst ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ``trim``
2
+ ========
3
+
4
+ .. versionadded:: 1.6.2
5
+ The ``trim`` filter was added in Twig 1.6.2.
6
+
7
+ The ``trim`` filter strips whitespace (or other characters) from the beginning
8
+ and end of a string:
9
+
10
+ .. code-block:: jinja
11
+
12
+ {{ ' I like Twig. '|trim }}
13
+
14
+ {# outputs 'I like Twig.' #}
15
+
16
+ {{ ' I like Twig.'|trim('.') }}
17
+
18
+ {# outputs ' I like Twig' #}
19
+
20
+ .. note::
21
+
22
+ Internally, Twig uses the PHP `trim`_ function.
23
+
24
+ Arguments
25
+ ---------
26
+
27
+ * ``character_mask``: The characters to strip
28
+
29
+ .. _`trim`: http://php.net/trim
library/twig/twig/doc/filters/upper.rst ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ ``upper``
2
+ =========
3
+
4
+ The ``upper`` filter converts a value to uppercase:
5
+
6
+ .. code-block:: jinja
7
+
8
+ {{ 'welcome'|upper }}
9
+
10
+ {# outputs 'WELCOME' #}
library/twig/twig/doc/filters/url_encode.rst ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ``url_encode``
2
+ ==============
3
+
4
+ .. versionadded:: 1.12.3
5
+ Support for encoding an array as query string was added in Twig 1.12.3.
6
+
7
+ .. versionadded:: 1.16.0
8
+ The ``raw`` argument was removed in Twig 1.16.0. Twig now always encodes
9
+ according to RFC 3986.
10
+
11
+ The ``url_encode`` filter percent encodes a given string as URL segment
12
+ or an array as query string:
13
+
14
+ .. code-block:: jinja
15
+
16
+ {{ "path-seg*ment"|url_encode }}
17
+ {# outputs "path-seg%2Ament" #}
18
+
19
+ {{ "string with spaces"|url_encode }}
20
+ {# outputs "string%20with%20spaces" #}
21
+
22
+ {{ {'param': 'value', 'foo': 'bar'}|url_encode }}
23
+ {# outputs "param=value&foo=bar" #}
24
+
25
+ .. note::
26
+
27
+ Internally, Twig uses the PHP `urlencode`_ (or `rawurlencode`_ if you pass
28
+ ``true`` as the first parameter) or the `http_build_query`_ function. Note
29
+ that as of Twig 1.16.0, ``urlencode`` **always** uses ``rawurlencode`` (the
30
+ ``raw`` argument was removed.)
31
+
32
+ .. _`urlencode`: http://php.net/urlencode
33
+ .. _`rawurlencode`: http://php.net/rawurlencode
34
+ .. _`http_build_query`: http://php.net/http_build_query
library/twig/twig/doc/functions/attribute.rst ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ``attribute``
2
+ =============
3
+
4
+ .. versionadded:: 1.2
5
+ The ``attribute`` function was added in Twig 1.2.
6
+
7
+ The ``attribute`` function can be used to access a "dynamic" attribute of a
8
+ variable:
9
+
10
+ .. code-block:: jinja
11
+
12
+ {{ attribute(object, method) }}
13
+ {{ attribute(object, method, arguments) }}
14
+ {{ attribute(array, item) }}
15
+
16
+ In addition, the ``defined`` test can check for the existence of a dynamic
17
+ attribute:
18
+
19
+ .. code-block:: jinja
20
+
21
+ {{ attribute(object, method) is defined ? 'Method exists' : 'Method does not exist' }}
22
+
23
+ .. note::
24
+
25
+ The resolution algorithm is the same as the one used for the ``.``
26
+ notation, except that the item can be any valid expression.
library/twig/twig/doc/functions/block.rst ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ``block``
2
+ =========
3
+
4
+ .. versionadded: 1.28
5
+ Using ``block`` with the ``defined`` test was added in Twig 1.28.
6
+
7
+ .. versionadded: 1.28
8
+ Support for the template argument was added in Twig 1.28.
9
+
10
+ When a template uses inheritance and if you want to print a block multiple
11
+ times, use the ``block`` function:
12
+
13
+ .. code-block:: jinja
14
+
15
+ <title>{% block title %}{% endblock %}</title>
16
+
17
+ <h1>{{ block('title') }}</h1>
18
+
19
+ {% block body %}{% endblock %}
20
+
21
+ The ``block`` function can also be used to display one block of another
22
+ template:
23
+
24
+ .. code-block:: jinja
25
+
26
+ {{ block("title", "common_blocks.twig") }}
27
+
28
+ Use the ``defined`` test to check if a block exists in the context of the
29
+ current template:
30
+
31
+ .. code-block:: jinja
32
+
33
+ {% if block("footer") is defined %}
34
+ ...
35
+ {% endif %}
36
+
37
+ {% if block("footer", "common_blocks.twig") is defined %}
38
+ ...
39
+ {% endif %}
40
+
41
+ .. seealso:: :doc:`extends<../tags/extends>`, :doc:`parent<../functions/parent>`
library/twig/twig/doc/functions/constant.rst ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ``constant``
2
+ ============
3
+
4
+ .. versionadded: 1.12.1
5
+ constant now accepts object instances as the second argument.
6
+
7
+ .. versionadded: 1.28
8
+ Using ``constant`` with the ``defined`` test was added in Twig 1.28.
9
+
10
+ ``constant`` returns the constant value for a given string:
11
+
12
+ .. code-block:: jinja
13
+
14
+ {{ some_date|date(constant('DATE_W3C')) }}
15
+ {{ constant('Namespace\\Classname::CONSTANT_NAME') }}
16
+
17
+ As of 1.12.1 you can read constants from object instances as well:
18
+
19
+ .. code-block:: jinja
20
+
21
+ {{ constant('RSS', date) }}
22
+
23
+ Use the ``defined`` test to check if a constant is defined:
24
+
25
+ .. code-block:: jinja
26
+
27
+ {% if constant('SOME_CONST') is defined %}
28
+ ...
29
+ {% endif %}
library/twig/twig/doc/functions/cycle.rst ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ``cycle``
2
+ =========
3
+
4
+ The ``cycle`` function cycles on an array of values:
5
+
6
+ .. code-block:: jinja
7
+
8
+ {% set start_year = date() | date('Y') %}
9
+ {% set end_year = start_year + 5 %}
10
+
11
+ {% for year in start_year..end_year %}
12
+ {{ cycle(['odd', 'even'], loop.index0) }}
13
+ {% endfor %}
14
+
15
+ The array can contain any number of values:
16
+
17
+ .. code-block:: jinja
18
+
19
+ {% set fruits = ['apple', 'orange', 'citrus'] %}
20
+
21
+ {% for i in 0..10 %}
22
+ {{ cycle(fruits, i) }}
23
+ {% endfor %}
24
+
25
+ Arguments
26
+ ---------
27
+
28
+ * ``position``: The cycle position
library/twig/twig/doc/functions/date.rst ADDED
@@ -0,0 +1,55 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ``date``
2
+ ========
3
+
4
+ .. versionadded:: 1.6
5
+ The date function has been added in Twig 1.6.
6
+
7
+ .. versionadded:: 1.6.1
8
+ The default timezone support has been added in Twig 1.6.1.
9
+
10
+ Converts an argument to a date to allow date comparison:
11
+
12
+ .. code-block:: jinja
13
+
14
+ {% if date(user.created_at) < date('-2days') %}
15
+ {# do something #}
16
+ {% endif %}
17
+
18
+ The argument must be in one of PHP’s supported `date and time formats`_.
19
+
20
+ You can pass a timezone as the second argument:
21
+
22
+ .. code-block:: jinja
23
+
24
+ {% if date(user.created_at) < date('-2days', 'Europe/Paris') %}
25
+ {# do something #}
26
+ {% endif %}
27
+
28
+ If no argument is passed, the function returns the current date:
29
+
30
+ .. code-block:: jinja
31
+
32
+ {% if date(user.created_at) < date() %}
33
+ {# always! #}
34
+ {% endif %}
35
+
36
+ .. note::
37
+
38
+ You can set the default timezone globally by calling ``setTimezone()`` on
39
+ the ``core`` extension instance:
40
+
41
+ .. code-block:: php
42
+
43
+ $twig = new Twig_Environment($loader);
44
+ $twig->getExtension('Twig_Extension_Core')->setTimezone('Europe/Paris');
45
+
46
+ // before Twig 1.26
47
+ $twig->getExtension('core')->setTimezone('Europe/Paris');
48
+
49
+ Arguments
50
+ ---------
51
+
52
+ * ``date``: The date
53
+ * ``timezone``: The timezone
54
+
55
+ .. _`date and time formats`: http://php.net/manual/en/datetime.formats.php
library/twig/twig/doc/functions/dump.rst ADDED
@@ -0,0 +1,69 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ``dump``
2
+ ========
3
+
4
+ .. versionadded:: 1.5
5
+ The ``dump`` function was added in Twig 1.5.
6
+
7
+ The ``dump`` function dumps information about a template variable. This is
8
+ mostly useful to debug a template that does not behave as expected by
9
+ introspecting its variables:
10
+
11
+ .. code-block:: jinja
12
+
13
+ {{ dump(user) }}
14
+
15
+ .. note::
16
+
17
+ The ``dump`` function is not available by default. You must add the
18
+ ``Twig_Extension_Debug`` extension explicitly when creating your Twig
19
+ environment::
20
+
21
+ $twig = new Twig_Environment($loader, array(
22
+ 'debug' => true,
23
+ // ...
24
+ ));
25
+ $twig->addExtension(new Twig_Extension_Debug());
26
+
27
+ Even when enabled, the ``dump`` function won't display anything if the
28
+ ``debug`` option on the environment is not enabled (to avoid leaking debug
29
+ information on a production server).
30
+
31
+ In an HTML context, wrap the output with a ``pre`` tag to make it easier to
32
+ read:
33
+
34
+ .. code-block:: jinja
35
+
36
+ <pre>
37
+ {{ dump(user) }}
38
+ </pre>
39
+
40
+ .. tip::
41
+
42
+ Using a ``pre`` tag is not needed when `XDebug`_ is enabled and
43
+ ``html_errors`` is ``on``; as a bonus, the output is also nicer with
44
+ XDebug enabled.
45
+
46
+ You can debug several variables by passing them as additional arguments:
47
+
48
+ .. code-block:: jinja
49
+
50
+ {{ dump(user, categories) }}
51
+
52
+ If you don't pass any value, all variables from the current context are
53
+ dumped:
54
+
55
+ .. code-block:: jinja
56
+
57
+ {{ dump() }}
58
+
59
+ .. note::
60
+
61
+ Internally, Twig uses the PHP `var_dump`_ function.
62
+
63
+ Arguments
64
+ ---------
65
+
66
+ * ``context``: The context to dump
67
+
68
+ .. _`XDebug`: http://xdebug.org/docs/display
69
+ .. _`var_dump`: http://php.net/var_dump
library/twig/twig/doc/functions/include.rst ADDED
@@ -0,0 +1,84 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ``include``
2
+ ===========
3
+
4
+ .. versionadded:: 1.12
5
+ The ``include`` function was added in Twig 1.12.
6
+
7
+ The ``include`` function returns the rendered content of a template:
8
+
9
+ .. code-block:: jinja
10
+
11
+ {{ include('template.html') }}
12
+ {{ include(some_var) }}
13
+
14
+ Included templates have access to the variables of the active context.
15
+
16
+ If you are using the filesystem loader, the templates are looked for in the
17
+ paths defined by it.
18
+
19
+ The context is passed by default to the template but you can also pass
20
+ additional variables:
21
+
22
+ .. code-block:: jinja
23
+
24
+ {# template.html will have access to the variables from the current context and the additional ones provided #}
25
+ {{ include('template.html', {foo: 'bar'}) }}
26
+
27
+ You can disable access to the context by setting ``with_context`` to
28
+ ``false``:
29
+
30
+ .. code-block:: jinja
31
+
32
+ {# only the foo variable will be accessible #}
33
+ {{ include('template.html', {foo: 'bar'}, with_context = false) }}
34
+
35
+ .. code-block:: jinja
36
+
37
+ {# no variables will be accessible #}
38
+ {{ include('template.html', with_context = false) }}
39
+
40
+ And if the expression evaluates to a ``Twig_Template`` or a
41
+ ``Twig_TemplateWrapper`` instance, Twig will use it directly::
42
+
43
+ // {{ include(template) }}
44
+
45
+ // deprecated as of Twig 1.28
46
+ $template = $twig->loadTemplate('some_template.twig');
47
+
48
+ // as of Twig 1.28
49
+ $template = $twig->load('some_template.twig');
50
+
51
+ $twig->display('template.twig', array('template' => $template));
52
+
53
+ When you set the ``ignore_missing`` flag, Twig will return an empty string if
54
+ the template does not exist:
55
+
56
+ .. code-block:: jinja
57
+
58
+ {{ include('sidebar.html', ignore_missing = true) }}
59
+
60
+ You can also provide a list of templates that are checked for existence before
61
+ inclusion. The first template that exists will be rendered:
62
+
63
+ .. code-block:: jinja
64
+
65
+ {{ include(['page_detailed.html', 'page.html']) }}
66
+
67
+ If ``ignore_missing`` is set, it will fall back to rendering nothing if none
68
+ of the templates exist, otherwise it will throw an exception.
69
+
70
+ When including a template created by an end user, you should consider
71
+ sandboxing it:
72
+
73
+ .. code-block:: jinja
74
+
75
+ {{ include('page.html', sandboxed = true) }}
76
+
77
+ Arguments
78
+ ---------
79
+
80
+ * ``template``: The template to render
81
+ * ``variables``: The variables to pass to the template
82
+ * ``with_context``: Whether to pass the current context variables or not
83
+ * ``ignore_missing``: Whether to ignore missing templates or not
84
+ * ``sandboxed``: Whether to sandbox the template or not
library/twig/twig/doc/functions/index.rst ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Functions
2
+ =========
3
+
4
+ .. toctree::
5
+ :maxdepth: 1
6
+
7
+ attribute
8
+ block
9
+ constant
10
+ cycle
11
+ date
12
+ dump
13
+ include
14
+ max
15
+ min
16
+ parent
17
+ random
18
+ range
19
+ source
20
+ template_from_string
library/twig/twig/doc/functions/max.rst ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ``max``
2
+ =======
3
+
4
+ .. versionadded:: 1.15
5
+ The ``max`` function was added in Twig 1.15.
6
+
7
+ ``max`` returns the biggest value of a sequence or a set of values:
8
+
9
+ .. code-block:: jinja
10
+
11
+ {{ max(1, 3, 2) }}
12
+ {{ max([1, 3, 2]) }}
13
+
14
+ When called with a mapping, max ignores keys and only compares values:
15
+
16
+ .. code-block:: jinja
17
+
18
+ {{ max({2: "e", 1: "a", 3: "b", 5: "d", 4: "c"}) }}
19
+ {# returns "e" #}
20
+
library/twig/twig/doc/functions/min.rst ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ``min``
2
+ =======
3
+
4
+ .. versionadded:: 1.15
5
+ The ``min`` function was added in Twig 1.15.
6
+
7
+ ``min`` returns the lowest value of a sequence or a set of values:
8
+
9
+ .. code-block:: jinja
10
+
11
+ {{ min(1, 3, 2) }}
12
+ {{ min([1, 3, 2]) }}
13
+
14
+ When called with a mapping, min ignores keys and only compares values:
15
+
16
+ .. code-block:: jinja
17
+
18
+ {{ min({2: "e", 3: "a", 1: "b", 5: "d", 4: "c"}) }}
19
+ {# returns "a" #}
20
+
library/twig/twig/doc/functions/parent.rst ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ``parent``
2
+ ==========
3
+
4
+ When a template uses inheritance, it's possible to render the contents of the
5
+ parent block when overriding a block by using the ``parent`` function:
6
+
7
+ .. code-block:: jinja
8
+
9
+ {% extends "base.html" %}
10
+
11
+ {% block sidebar %}
12
+ <h3>Table Of Contents</h3>
13
+ ...
14
+ {{ parent() }}
15
+ {% endblock %}
16
+
17
+ The ``parent()`` call will return the content of the ``sidebar`` block as
18
+ defined in the ``base.html`` template.
19
+
20
+ .. seealso:: :doc:`extends<../tags/extends>`, :doc:`block<../functions/block>`, :doc:`block<../tags/block>`
library/twig/twig/doc/functions/random.rst ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ``random``
2
+ ==========
3
+
4
+ .. versionadded:: 1.5
5
+ The ``random`` function was added in Twig 1.5.
6
+
7
+ .. versionadded:: 1.6
8
+ String and integer handling was added in Twig 1.6.
9
+
10
+ The ``random`` function returns a random value depending on the supplied
11
+ parameter type:
12
+
13
+ * a random item from a sequence;
14
+ * a random character from a string;
15
+ * a random integer between 0 and the integer parameter (inclusive).
16
+
17
+ .. code-block:: jinja
18
+
19
+ {{ random(['apple', 'orange', 'citrus']) }} {# example output: orange #}
20
+ {{ random('ABC') }} {# example output: C #}
21
+ {{ random() }} {# example output: 15386094 (works as the native PHP mt_rand function) #}
22
+ {{ random(5) }} {# example output: 3 #}
23
+
24
+ Arguments
25
+ ---------
26
+
27
+ * ``values``: The values
28
+
29
+ .. _`mt_rand`: http://php.net/mt_rand
library/twig/twig/doc/functions/range.rst ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ``range``
2
+ =========
3
+
4
+ Returns a list containing an arithmetic progression of integers:
5
+
6
+ .. code-block:: jinja
7
+
8
+ {% for i in range(0, 3) %}
9
+ {{ i }},
10
+ {% endfor %}
11
+
12
+ {# outputs 0, 1, 2, 3, #}
13
+
14
+ When step is given (as the third parameter), it specifies the increment (or
15
+ decrement for negative values):
16
+
17
+ .. code-block:: jinja
18
+
19
+ {% for i in range(0, 6, 2) %}
20
+ {{ i }},
21
+ {% endfor %}
22
+
23
+ {# outputs 0, 2, 4, 6, #}
24
+
25
+ .. note::
26
+
27
+ Note that if the start is greater than the end, ``range`` assumes a step of
28
+ ``-1``:
29
+
30
+ .. code-block:: jinja
31
+
32
+ {% for i in range(3, 0) %}
33
+ {{ i }},
34
+ {% endfor %}
35
+
36
+ {# outputs 3, 2, 1, 0, #}
37
+
38
+ The Twig built-in ``..`` operator is just syntactic sugar for the ``range``
39
+ function (with a step of ``1``, or ``-1`` if the start is greater than the end):
40
+
41
+ .. code-block:: jinja
42
+
43
+ {% for i in 0..3 %}
44
+ {{ i }},
45
+ {% endfor %}
46
+
47
+ .. tip::
48
+
49
+ The ``range`` function works as the native PHP `range`_ function.
50
+
51
+ Arguments
52
+ ---------
53
+
54
+ * ``low``: The first value of the sequence.
55
+ * ``high``: The highest possible value of the sequence.
56
+ * ``step``: The increment between elements of the sequence.
57
+
58
+ .. _`range`: http://php.net/range
library/twig/twig/doc/functions/source.rst ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ``source``
2
+ ==========
3
+
4
+ .. versionadded:: 1.15
5
+ The ``source`` function was added in Twig 1.15.
6
+
7
+ .. versionadded:: 1.18.3
8
+ The ``ignore_missing`` flag was added in Twig 1.18.3.
9
+
10
+ The ``source`` function returns the content of a template without rendering it:
11
+
12
+ .. code-block:: jinja
13
+
14
+ {{ source('template.html') }}
15
+ {{ source(some_var) }}
16
+
17
+ When you set the ``ignore_missing`` flag, Twig will return an empty string if
18
+ the template does not exist:
19
+
20
+ .. code-block:: jinja
21
+
22
+ {{ source('template.html', ignore_missing = true) }}
23
+
24
+ The function uses the same template loaders as the ones used to include
25
+ templates. So, if you are using the filesystem loader, the templates are looked
26
+ for in the paths defined by it.
27
+
28
+ Arguments
29
+ ---------
30
+
31
+ * ``name``: The name of the template to read
32
+ * ``ignore_missing``: Whether to ignore missing templates or not
library/twig/twig/doc/functions/template_from_string.rst ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ``template_from_string``
2
+ ========================
3
+
4
+ .. versionadded:: 1.11
5
+ The ``template_from_string`` function was added in Twig 1.11.
6
+
7
+ The ``template_from_string`` function loads a template from a string:
8
+
9
+ .. code-block:: jinja
10
+
11
+ {{ include(template_from_string("Hello {{ name }}")) }}
12
+ {{ include(template_from_string(page.template)) }}
13
+
14
+ .. note::
15
+
16
+ The ``template_from_string`` function is not available by default. You
17
+ must add the ``Twig_Extension_StringLoader`` extension explicitly when
18
+ creating your Twig environment::
19
+
20
+ $twig = new Twig_Environment(...);
21
+ $twig->addExtension(new Twig_Extension_StringLoader());
22
+
23
+ .. note::
24
+
25
+ Even if you will probably always use the ``template_from_string`` function
26
+ with the ``include`` function, you can use it with any tag or function that
27
+ takes a template as an argument (like the ``embed`` or ``extends`` tags).
28
+
29
+ Arguments
30
+ ---------
31
+
32
+ * ``template``: The template
library/twig/twig/doc/index.rst ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Twig
2
+ ====
3
+
4
+ .. toctree::
5
+ :maxdepth: 2
6
+
7
+ intro
8
+ installation
9
+ templates
10
+ api
11
+ advanced
12
+ internals
13
+ deprecated
14
+ recipes
15
+ coding_standards
16
+ tags/index
17
+ filters/index
18
+ functions/index
19
+ tests/index
library/twig/twig/doc/installation.rst ADDED
@@ -0,0 +1,116 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Installation
2
+ ============
3
+
4
+ You have multiple ways to install Twig.
5
+
6
+ Installing the Twig PHP package
7
+ -------------------------------
8
+
9
+ Installing via Composer (recommended)
10
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
11
+
12
+ Install `Composer`_ and run the following command to get the latest version:
13
+
14
+ .. code-block:: bash
15
+
16
+ composer require twig/twig:~1.0
17
+
18
+ Installing from the tarball release
19
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
20
+
21
+ 1. Download the most recent tarball from the `download page`_
22
+ 2. Verify the integrity of the tarball http://fabien.potencier.org/article/73/signing-project-releases
23
+ 3. Unpack the tarball
24
+ 4. Move the files somewhere in your project
25
+
26
+ Installing the development version
27
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
28
+
29
+ .. code-block:: bash
30
+
31
+ git clone git://github.com/twigphp/Twig.git
32
+
33
+ Installing the PEAR package
34
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~
35
+
36
+ .. note::
37
+
38
+ Using PEAR for installing Twig is deprecated and Twig 1.15.1 was the last
39
+ version published on the PEAR channel; use Composer instead.
40
+
41
+ .. code-block:: bash
42
+
43
+ pear channel-discover pear.twig-project.org
44
+ pear install twig/Twig
45
+
46
+ Installing the C extension
47
+ --------------------------
48
+
49
+ .. versionadded:: 1.4
50
+ The C extension was added in Twig 1.4.
51
+
52
+ .. note::
53
+
54
+ The C extension is **optional** but it brings some nice performance
55
+ improvements. Note that the extension is not a replacement for the PHP
56
+ code; it only implements a small part of the PHP code to improve the
57
+ performance at runtime; you must still install the regular PHP code.
58
+
59
+ Twig comes with a C extension that enhances the performance of the Twig
60
+ runtime engine; install it like any other PHP extensions:
61
+
62
+ .. code-block:: bash
63
+
64
+ cd ext/twig
65
+ phpize
66
+ ./configure
67
+ make
68
+ make install
69
+
70
+ .. note::
71
+
72
+ You can also install the C extension via PEAR (note that this method is
73
+ deprecated and newer versions of Twig are not available on the PEAR
74
+ channel):
75
+
76
+ .. code-block:: bash
77
+
78
+ pear channel-discover pear.twig-project.org
79
+ pear install twig/CTwig
80
+
81
+ For Windows:
82
+
83
+ 1. Setup the build environment following the `PHP documentation`_
84
+ 2. Put Twig's C extension source code into ``C:\php-sdk\phpdev\vcXX\x86\php-source-directory\ext\twig``
85
+ 3. Use the ``configure --disable-all --enable-cli --enable-twig=shared`` command instead of step 14
86
+ 4. ``nmake``
87
+ 5. Copy the ``C:\php-sdk\phpdev\vcXX\x86\php-source-directory\Release_TS\php_twig.dll`` file to your PHP setup.
88
+
89
+ .. tip::
90
+
91
+ For Windows ZendServer, ZTS is not enabled as mentioned in `Zend Server
92
+ FAQ`_.
93
+
94
+ You have to use ``configure --disable-all --disable-zts --enable-cli
95
+ --enable-twig=shared`` to be able to build the twig C extension for
96
+ ZendServer.
97
+
98
+ The built DLL will be available in
99
+ ``C:\\php-sdk\\phpdev\\vcXX\\x86\\php-source-directory\\Release``
100
+
101
+ Finally, enable the extension in your ``php.ini`` configuration file:
102
+
103
+ .. code-block:: ini
104
+
105
+ extension=twig.so #For Unix systems
106
+ extension=php_twig.dll #For Windows systems
107
+
108
+ And from now on, Twig will automatically compile your templates to take
109
+ advantage of the C extension. Note that this extension does not replace the
110
+ PHP code but only provides an optimized version of the
111
+ ``Twig_Template::getAttribute()`` method.
112
+
113
+ .. _`download page`: https://github.com/twigphp/Twig/tags
114
+ .. _`Composer`: https://getcomposer.org/download/
115
+ .. _`PHP documentation`: https://wiki.php.net/internals/windows/stepbystepbuild
116
+ .. _`Zend Server FAQ`: http://www.zend.com/en/products/server/faq#faqD6
library/twig/twig/doc/internals.rst ADDED
@@ -0,0 +1,142 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Twig Internals
2
+ ==============
3
+
4
+ Twig is very extensible and you can easily hack it. Keep in mind that you
5
+ should probably try to create an extension before hacking the core, as most
6
+ features and enhancements can be handled with extensions. This chapter is also
7
+ useful for people who want to understand how Twig works under the hood.
8
+
9
+ How does Twig work?
10
+ -------------------
11
+
12
+ The rendering of a Twig template can be summarized into four key steps:
13
+
14
+ * **Load** the template: If the template is already compiled, load it and go
15
+ to the *evaluation* step, otherwise:
16
+
17
+ * First, the **lexer** tokenizes the template source code into small pieces
18
+ for easier processing;
19
+ * Then, the **parser** converts the token stream into a meaningful tree
20
+ of nodes (the Abstract Syntax Tree);
21
+ * Eventually, the *compiler* transforms the AST into PHP code.
22
+
23
+ * **Evaluate** the template: It basically means calling the ``display()``
24
+ method of the compiled template and passing it the context.
25
+
26
+ The Lexer
27
+ ---------
28
+
29
+ The lexer tokenizes a template source code into a token stream (each token is
30
+ an instance of ``Twig_Token``, and the stream is an instance of
31
+ ``Twig_TokenStream``). The default lexer recognizes 13 different token types:
32
+
33
+ * ``Twig_Token::BLOCK_START_TYPE``, ``Twig_Token::BLOCK_END_TYPE``: Delimiters for blocks (``{% %}``)
34
+ * ``Twig_Token::VAR_START_TYPE``, ``Twig_Token::VAR_END_TYPE``: Delimiters for variables (``{{ }}``)
35
+ * ``Twig_Token::TEXT_TYPE``: A text outside an expression;
36
+ * ``Twig_Token::NAME_TYPE``: A name in an expression;
37
+ * ``Twig_Token::NUMBER_TYPE``: A number in an expression;
38
+ * ``Twig_Token::STRING_TYPE``: A string in an expression;
39
+ * ``Twig_Token::OPERATOR_TYPE``: An operator;
40
+ * ``Twig_Token::PUNCTUATION_TYPE``: A punctuation sign;
41
+ * ``Twig_Token::INTERPOLATION_START_TYPE``, ``Twig_Token::INTERPOLATION_END_TYPE`` (as of Twig 1.5): Delimiters for string interpolation;
42
+ * ``Twig_Token::EOF_TYPE``: Ends of template.
43
+
44
+ You can manually convert a source code into a token stream by calling the
45
+ ``tokenize()`` method of an environment::
46
+
47
+ $stream = $twig->tokenize(new Twig_Source($source, $identifier));
48
+
49
+ .. versionadded:: 1.27
50
+ ``Twig_Source`` was introduced in version 1.27, pass the source and the
51
+ identifier directly on previous versions.
52
+
53
+ As the stream has a ``__toString()`` method, you can have a textual
54
+ representation of it by echoing the object::
55
+
56
+ echo $stream."\n";
57
+
58
+ Here is the output for the ``Hello {{ name }}`` template:
59
+
60
+ .. code-block:: text
61
+
62
+ TEXT_TYPE(Hello )
63
+ VAR_START_TYPE()
64
+ NAME_TYPE(name)
65
+ VAR_END_TYPE()
66
+ EOF_TYPE()
67
+
68
+ .. note::
69
+
70
+ The default lexer (``Twig_Lexer``) can be changed by calling
71
+ the ``setLexer()`` method::
72
+
73
+ $twig->setLexer($lexer);
74
+
75
+ The Parser
76
+ ----------
77
+
78
+ The parser converts the token stream into an AST (Abstract Syntax Tree), or a
79
+ node tree (an instance of ``Twig_Node_Module``). The core extension defines
80
+ the basic nodes like: ``for``, ``if``, ... and the expression nodes.
81
+
82
+ You can manually convert a token stream into a node tree by calling the
83
+ ``parse()`` method of an environment::
84
+
85
+ $nodes = $twig->parse($stream);
86
+
87
+ Echoing the node object gives you a nice representation of the tree::
88
+
89
+ echo $nodes."\n";
90
+
91
+ Here is the output for the ``Hello {{ name }}`` template:
92
+
93
+ .. code-block:: text
94
+
95
+ Twig_Node_Module(
96
+ Twig_Node_Text(Hello )
97
+ Twig_Node_Print(
98
+ Twig_Node_Expression_Name(name)
99
+ )
100
+ )
101
+
102
+ .. note::
103
+
104
+ The default parser (``Twig_TokenParser``) can be changed by calling the
105
+ ``setParser()`` method::
106
+
107
+ $twig->setParser($parser);
108
+
109
+ The Compiler
110
+ ------------
111
+
112
+ The last step is done by the compiler. It takes a node tree as an input and
113
+ generates PHP code usable for runtime execution of the template.
114
+
115
+ You can manually compile a node tree to PHP code with the ``compile()`` method
116
+ of an environment::
117
+
118
+ $php = $twig->compile($nodes);
119
+
120
+ The generated template for a ``Hello {{ name }}`` template reads as follows
121
+ (the actual output can differ depending on the version of Twig you are
122
+ using)::
123
+
124
+ /* Hello {{ name }} */
125
+ class __TwigTemplate_1121b6f109fe93ebe8c6e22e3712bceb extends Twig_Template
126
+ {
127
+ protected function doDisplay(array $context, array $blocks = array())
128
+ {
129
+ // line 1
130
+ echo "Hello ";
131
+ echo twig_escape_filter($this->env, isset($context["name"]) ? $context["name"] : null), "html", null, true);
132
+ }
133
+
134
+ // some more code
135
+ }
136
+
137
+ .. note::
138
+
139
+ The default compiler (``Twig_Compiler``) can be changed by calling the
140
+ ``setCompiler()`` method::
141
+
142
+ $twig->setCompiler($compiler);
library/twig/twig/doc/intro.rst ADDED
@@ -0,0 +1,85 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Introduction
2
+ ============
3
+
4
+ This is the documentation for Twig, the flexible, fast, and secure template
5
+ engine for PHP.
6
+
7
+ If you have any exposure to other text-based template languages, such as
8
+ Smarty, Django, or Jinja, you should feel right at home with Twig. It's both
9
+ designer and developer friendly by sticking to PHP's principles and adding
10
+ functionality useful for templating environments.
11
+
12
+ The key-features are...
13
+
14
+ * *Fast*: Twig compiles templates down to plain optimized PHP code. The
15
+ overhead compared to regular PHP code was reduced to the very minimum.
16
+
17
+ * *Secure*: Twig has a sandbox mode to evaluate untrusted template code. This
18
+ allows Twig to be used as a template language for applications where users
19
+ may modify the template design.
20
+
21
+ * *Flexible*: Twig is powered by a flexible lexer and parser. This allows the
22
+ developer to define their own custom tags and filters, and to create their own DSL.
23
+
24
+ Twig is used by many Open-Source projects like Symfony, Drupal8, eZPublish,
25
+ phpBB, Piwik, OroCRM; and many frameworks have support for it as well like
26
+ Slim, Yii, Laravel, Codeigniter and Kohana — just to name a few.
27
+
28
+ Prerequisites
29
+ -------------
30
+
31
+ Twig needs at least **PHP 5.2.7** to run.
32
+
33
+ Installation
34
+ ------------
35
+
36
+ The recommended way to install Twig is via Composer:
37
+
38
+ .. code-block:: bash
39
+
40
+ composer require "twig/twig:~1.0"
41
+
42
+ .. note::
43
+
44
+ To learn more about the other installation methods, read the
45
+ :doc:`installation<installation>` chapter; it also explains how to install
46
+ the Twig C extension.
47
+
48
+ Basic API Usage
49
+ ---------------
50
+
51
+ This section gives you a brief introduction to the PHP API for Twig.
52
+
53
+ .. code-block:: php
54
+
55
+ require_once '/path/to/vendor/autoload.php';
56
+
57
+ $loader = new Twig_Loader_Array(array(
58
+ 'index' => 'Hello {{ name }}!',
59
+ ));
60
+ $twig = new Twig_Environment($loader);
61
+
62
+ echo $twig->render('index', array('name' => 'Fabien'));
63
+
64
+ Twig uses a loader (``Twig_Loader_Array``) to locate templates, and an
65
+ environment (``Twig_Environment``) to store the configuration.
66
+
67
+ The ``render()`` method loads the template passed as a first argument and
68
+ renders it with the variables passed as a second argument.
69
+
70
+ As templates are generally stored on the filesystem, Twig also comes with a
71
+ filesystem loader::
72
+
73
+ $loader = new Twig_Loader_Filesystem('/path/to/templates');
74
+ $twig = new Twig_Environment($loader, array(
75
+ 'cache' => '/path/to/compilation_cache',
76
+ ));
77
+
78
+ echo $twig->render('index.html', array('name' => 'Fabien'));
79
+
80
+ .. tip::
81
+
82
+ If you are not using Composer, use the Twig built-in autoloader::
83
+
84
+ require_once '/path/to/lib/Twig/Autoloader.php';
85
+ Twig_Autoloader::register();
library/twig/twig/doc/recipes.rst ADDED
@@ -0,0 +1,568 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Recipes
2
+ =======
3
+
4
+ .. _deprecation-notices:
5
+
6
+ Displaying Deprecation Notices
7
+ ------------------------------
8
+
9
+ .. versionadded:: 1.21
10
+ This works as of Twig 1.21.
11
+
12
+ Deprecated features generate deprecation notices (via a call to the
13
+ ``trigger_error()`` PHP function). By default, they are silenced and never
14
+ displayed nor logged.
15
+
16
+ To easily remove all deprecated feature usages from your templates, write and
17
+ run a script along the lines of the following::
18
+
19
+ require_once __DIR__.'/vendor/autoload.php';
20
+
21
+ $twig = create_your_twig_env();
22
+
23
+ $deprecations = new Twig_Util_DeprecationCollector($twig);
24
+
25
+ print_r($deprecations->collectDir(__DIR__.'/templates'));
26
+
27
+ The ``collectDir()`` method compiles all templates found in a directory,
28
+ catches deprecation notices, and return them.
29
+
30
+ .. tip::
31
+
32
+ If your templates are not stored on the filesystem, use the ``collect()``
33
+ method instead which takes an ``Iterator``; the iterator must return
34
+ template names as keys and template contents as values (as done by
35
+ ``Twig_Util_TemplateDirIterator``).
36
+
37
+ However, this code won't find all deprecations (like using deprecated some Twig
38
+ classes). To catch all notices, register a custom error handler like the one
39
+ below::
40
+
41
+ $deprecations = array();
42
+ set_error_handler(function ($type, $msg) use (&$deprecations) {
43
+ if (E_USER_DEPRECATED === $type) {
44
+ $deprecations[] = $msg;
45
+ }
46
+ });
47
+
48
+ // run your application
49
+
50
+ print_r($deprecations);
51
+
52
+ Note that most deprecation notices are triggered during **compilation**, so
53
+ they won't be generated when templates are already cached.
54
+
55
+ .. tip::
56
+
57
+ If you want to manage the deprecation notices from your PHPUnit tests, have
58
+ a look at the `symfony/phpunit-bridge
59
+ <https://github.com/symfony/phpunit-bridge>`_ package, which eases the
60
+ process a lot.
61
+
62
+ Making a Layout conditional
63
+ ---------------------------
64
+
65
+ Working with Ajax means that the same content is sometimes displayed as is,
66
+ and sometimes decorated with a layout. As Twig layout template names can be
67
+ any valid expression, you can pass a variable that evaluates to ``true`` when
68
+ the request is made via Ajax and choose the layout accordingly:
69
+
70
+ .. code-block:: jinja
71
+
72
+ {% extends request.ajax ? "base_ajax.html" : "base.html" %}
73
+
74
+ {% block content %}
75
+ This is the content to be displayed.
76
+ {% endblock %}
77
+
78
+ Making an Include dynamic
79
+ -------------------------
80
+
81
+ When including a template, its name does not need to be a string. For
82
+ instance, the name can depend on the value of a variable:
83
+
84
+ .. code-block:: jinja
85
+
86
+ {% include var ~ '_foo.html' %}
87
+
88
+ If ``var`` evaluates to ``index``, the ``index_foo.html`` template will be
89
+ rendered.
90
+
91
+ As a matter of fact, the template name can be any valid expression, such as
92
+ the following:
93
+
94
+ .. code-block:: jinja
95
+
96
+ {% include var|default('index') ~ '_foo.html' %}
97
+
98
+ Overriding a Template that also extends itself
99
+ ----------------------------------------------
100
+
101
+ A template can be customized in two different ways:
102
+
103
+ * *Inheritance*: A template *extends* a parent template and overrides some
104
+ blocks;
105
+
106
+ * *Replacement*: If you use the filesystem loader, Twig loads the first
107
+ template it finds in a list of configured directories; a template found in a
108
+ directory *replaces* another one from a directory further in the list.
109
+
110
+ But how do you combine both: *replace* a template that also extends itself
111
+ (aka a template in a directory further in the list)?
112
+
113
+ Let's say that your templates are loaded from both ``.../templates/mysite``
114
+ and ``.../templates/default`` in this order. The ``page.twig`` template,
115
+ stored in ``.../templates/default`` reads as follows:
116
+
117
+ .. code-block:: jinja
118
+
119
+ {# page.twig #}
120
+ {% extends "layout.twig" %}
121
+
122
+ {% block content %}
123
+ {% endblock %}
124
+
125
+ You can replace this template by putting a file with the same name in
126
+ ``.../templates/mysite``. And if you want to extend the original template, you
127
+ might be tempted to write the following:
128
+
129
+ .. code-block:: jinja
130
+
131
+ {# page.twig in .../templates/mysite #}
132
+ {% extends "page.twig" %} {# from .../templates/default #}
133
+
134
+ Of course, this will not work as Twig will always load the template from
135
+ ``.../templates/mysite``.
136
+
137
+ It turns out it is possible to get this to work, by adding a directory right
138
+ at the end of your template directories, which is the parent of all of the
139
+ other directories: ``.../templates`` in our case. This has the effect of
140
+ making every template file within our system uniquely addressable. Most of the
141
+ time you will use the "normal" paths, but in the special case of wanting to
142
+ extend a template with an overriding version of itself we can reference its
143
+ parent's full, unambiguous template path in the extends tag:
144
+
145
+ .. code-block:: jinja
146
+
147
+ {# page.twig in .../templates/mysite #}
148
+ {% extends "default/page.twig" %} {# from .../templates #}
149
+
150
+ .. note::
151
+
152
+ This recipe was inspired by the following Django wiki page:
153
+ http://code.djangoproject.com/wiki/ExtendingTemplates
154
+
155
+ Customizing the Syntax
156
+ ----------------------
157
+
158
+ Twig allows some syntax customization for the block delimiters. It's not
159
+ recommended to use this feature as templates will be tied with your custom
160
+ syntax. But for specific projects, it can make sense to change the defaults.
161
+
162
+ To change the block delimiters, you need to create your own lexer object::
163
+
164
+ $twig = new Twig_Environment();
165
+
166
+ $lexer = new Twig_Lexer($twig, array(
167
+ 'tag_comment' => array('{#', '#}'),
168
+ 'tag_block' => array('{%', '%}'),
169
+ 'tag_variable' => array('{{', '}}'),
170
+ 'interpolation' => array('#{', '}'),
171
+ ));
172
+ $twig->setLexer($lexer);
173
+
174
+ Here are some configuration example that simulates some other template engines
175
+ syntax::
176
+
177
+ // Ruby erb syntax
178
+ $lexer = new Twig_Lexer($twig, array(
179
+ 'tag_comment' => array('<%#', '%>'),
180
+ 'tag_block' => array('<%', '%>'),
181
+ 'tag_variable' => array('<%=', '%>'),
182
+ ));
183
+
184
+ // SGML Comment Syntax
185
+ $lexer = new Twig_Lexer($twig, array(
186
+ 'tag_comment' => array('<!--#', '-->'),
187
+ 'tag_block' => array('<!--', '-->'),
188
+ 'tag_variable' => array('${', '}'),
189
+ ));
190
+
191
+ // Smarty like
192
+ $lexer = new Twig_Lexer($twig, array(
193
+ 'tag_comment' => array('{*', '*}'),
194
+ 'tag_block' => array('{', '}'),
195
+ 'tag_variable' => array('{$', '}'),
196
+ ));
197
+
198
+ Using dynamic Object Properties
199
+ -------------------------------
200
+
201
+ When Twig encounters a variable like ``article.title``, it tries to find a
202
+ ``title`` public property in the ``article`` object.
203
+
204
+ It also works if the property does not exist but is rather defined dynamically
205
+ thanks to the magic ``__get()`` method; you just need to also implement the
206
+ ``__isset()`` magic method like shown in the following snippet of code::
207
+
208
+ class Article
209
+ {
210
+ public function __get($name)
211
+ {
212
+ if ('title' == $name) {
213
+ return 'The title';
214
+ }
215
+
216
+ // throw some kind of error
217
+ }
218
+
219
+ public function __isset($name)
220
+ {
221
+ if ('title' == $name) {
222
+ return true;
223
+ }
224
+
225
+ return false;
226
+ }
227
+ }
228
+
229
+ Accessing the parent Context in Nested Loops
230
+ --------------------------------------------
231
+
232
+ Sometimes, when using nested loops, you need to access the parent context. The
233
+ parent context is always accessible via the ``loop.parent`` variable. For
234
+ instance, if you have the following template data::
235
+
236
+ $data = array(
237
+ 'topics' => array(
238
+ 'topic1' => array('Message 1 of topic 1', 'Message 2 of topic 1'),
239
+ 'topic2' => array('Message 1 of topic 2', 'Message 2 of topic 2'),
240
+ ),
241
+ );
242
+
243
+ And the following template to display all messages in all topics:
244
+
245
+ .. code-block:: jinja
246
+
247
+ {% for topic, messages in topics %}
248
+ * {{ loop.index }}: {{ topic }}
249
+ {% for message in messages %}
250
+ - {{ loop.parent.loop.index }}.{{ loop.index }}: {{ message }}
251
+ {% endfor %}
252
+ {% endfor %}
253
+
254
+ The output will be similar to:
255
+
256
+ .. code-block:: text
257
+
258
+ * 1: topic1
259
+ - 1.1: The message 1 of topic 1
260
+ - 1.2: The message 2 of topic 1
261
+ * 2: topic2
262
+ - 2.1: The message 1 of topic 2
263
+ - 2.2: The message 2 of topic 2
264
+
265
+ In the inner loop, the ``loop.parent`` variable is used to access the outer
266
+ context. So, the index of the current ``topic`` defined in the outer for loop
267
+ is accessible via the ``loop.parent.loop.index`` variable.
268
+
269
+ Defining undefined Functions and Filters on the Fly
270
+ ---------------------------------------------------
271
+
272
+ When a function (or a filter) is not defined, Twig defaults to throw a
273
+ ``Twig_Error_Syntax`` exception. However, it can also call a `callback`_ (any
274
+ valid PHP callable) which should return a function (or a filter).
275
+
276
+ For filters, register callbacks with ``registerUndefinedFilterCallback()``.
277
+ For functions, use ``registerUndefinedFunctionCallback()``::
278
+
279
+ // auto-register all native PHP functions as Twig functions
280
+ // don't try this at home as it's not secure at all!
281
+ $twig->registerUndefinedFunctionCallback(function ($name) {
282
+ if (function_exists($name)) {
283
+ return new Twig_SimpleFunction($name, $name);
284
+ }
285
+
286
+ return false;
287
+ });
288
+
289
+ If the callable is not able to return a valid function (or filter), it must
290
+ return ``false``.
291
+
292
+ If you register more than one callback, Twig will call them in turn until one
293
+ does not return ``false``.
294
+
295
+ .. tip::
296
+
297
+ As the resolution of functions and filters is done during compilation,
298
+ there is no overhead when registering these callbacks.
299
+
300
+ Validating the Template Syntax
301
+ ------------------------------
302
+
303
+ When template code is provided by a third-party (through a web interface for
304
+ instance), it might be interesting to validate the template syntax before
305
+ saving it. If the template code is stored in a `$template` variable, here is
306
+ how you can do it::
307
+
308
+ try {
309
+ $twig->parse($twig->tokenize(new Twig_Source($template)));
310
+
311
+ // the $template is valid
312
+ } catch (Twig_Error_Syntax $e) {
313
+ // $template contains one or more syntax errors
314
+ }
315
+
316
+ If you iterate over a set of files, you can pass the filename to the
317
+ ``tokenize()`` method to get the filename in the exception message::
318
+
319
+ foreach ($files as $file) {
320
+ try {
321
+ $twig->parse($twig->tokenize(new Twig_Source($template, $file->getFilename(), $file)));
322
+
323
+ // the $template is valid
324
+ } catch (Twig_Error_Syntax $e) {
325
+ // $template contains one or more syntax errors
326
+ }
327
+ }
328
+
329
+ .. versionadded:: 1.27
330
+ ``Twig_Source`` was introduced in version 1.27, pass the source and the
331
+ identifier directly on previous versions.
332
+
333
+ .. note::
334
+
335
+ This method won't catch any sandbox policy violations because the policy
336
+ is enforced during template rendering (as Twig needs the context for some
337
+ checks like allowed methods on objects).
338
+
339
+ Refreshing modified Templates when OPcache or APC is enabled
340
+ ------------------------------------------------------------
341
+
342
+ When using OPcache with ``opcache.validate_timestamps`` set to ``0`` or APC
343
+ with ``apc.stat`` set to ``0`` and Twig cache enabled, clearing the template
344
+ cache won't update the cache.
345
+
346
+ To get around this, force Twig to invalidate the bytecode cache::
347
+
348
+ $twig = new Twig_Environment($loader, array(
349
+ 'cache' => new Twig_Cache_Filesystem('/some/cache/path', Twig_Cache_Filesystem::FORCE_BYTECODE_INVALIDATION),
350
+ // ...
351
+ ));
352
+
353
+ .. note::
354
+
355
+ Before Twig 1.22, you should extend ``Twig_Environment`` instead::
356
+
357
+ class OpCacheAwareTwigEnvironment extends Twig_Environment
358
+ {
359
+ protected function writeCacheFile($file, $content)
360
+ {
361
+ parent::writeCacheFile($file, $content);
362
+
363
+ // Compile cached file into bytecode cache
364
+ if (function_exists('opcache_invalidate')) {
365
+ opcache_invalidate($file, true);
366
+ } elseif (function_exists('apc_compile_file')) {
367
+ apc_compile_file($file);
368
+ }
369
+ }
370
+ }
371
+
372
+ Reusing a stateful Node Visitor
373
+ -------------------------------
374
+
375
+ When attaching a visitor to a ``Twig_Environment`` instance, Twig uses it to
376
+ visit *all* templates it compiles. If you need to keep some state information
377
+ around, you probably want to reset it when visiting a new template.
378
+
379
+ This can be easily achieved with the following code::
380
+
381
+ protected $someTemplateState = array();
382
+
383
+ public function enterNode(Twig_NodeInterface $node, Twig_Environment $env)
384
+ {
385
+ if ($node instanceof Twig_Node_Module) {
386
+ // reset the state as we are entering a new template
387
+ $this->someTemplateState = array();
388
+ }
389
+
390
+ // ...
391
+
392
+ return $node;
393
+ }
394
+
395
+ Using a Database to store Templates
396
+ -----------------------------------
397
+
398
+ If you are developing a CMS, templates are usually stored in a database. This
399
+ recipe gives you a simple PDO template loader you can use as a starting point
400
+ for your own.
401
+
402
+ First, let's create a temporary in-memory SQLite3 database to work with::
403
+
404
+ $dbh = new PDO('sqlite::memory:');
405
+ $dbh->exec('CREATE TABLE templates (name STRING, source STRING, last_modified INTEGER)');
406
+ $base = '{% block content %}{% endblock %}';
407
+ $index = '
408
+ {% extends "base.twig" %}
409
+ {% block content %}Hello {{ name }}{% endblock %}
410
+ ';
411
+ $now = time();
412
+ $dbh->exec("INSERT INTO templates (name, source, last_modified) VALUES ('base.twig', '$base', $now)");
413
+ $dbh->exec("INSERT INTO templates (name, source, last_modified) VALUES ('index.twig', '$index', $now)");
414
+
415
+ We have created a simple ``templates`` table that hosts two templates:
416
+ ``base.twig`` and ``index.twig``.
417
+
418
+ Now, let's define a loader able to use this database::
419
+
420
+ class DatabaseTwigLoader implements Twig_LoaderInterface, Twig_ExistsLoaderInterface, Twig_SourceContextLoaderInterface
421
+ {
422
+ protected $dbh;
423
+
424
+ public function __construct(PDO $dbh)
425
+ {
426
+ $this->dbh = $dbh;
427
+ }
428
+
429
+ public function getSource($name)
430
+ {
431
+ if (false === $source = $this->getValue('source', $name)) {
432
+ throw new Twig_Error_Loader(sprintf('Template "%s" does not exist.', $name));
433
+ }
434
+
435
+ return $source;
436
+ }
437
+
438
+ // Twig_SourceContextLoaderInterface as of Twig 1.27
439
+ public function getSourceContext($name)
440
+ {
441
+ if (false === $source = $this->getValue('source', $name)) {
442
+ throw new Twig_Error_Loader(sprintf('Template "%s" does not exist.', $name));
443
+ }
444
+
445
+ return new Twig_Source($source, $name);
446
+ }
447
+
448
+ // Twig_ExistsLoaderInterface as of Twig 1.11
449
+ public function exists($name)
450
+ {
451
+ return $name === $this->getValue('name', $name);
452
+ }
453
+
454
+ public function getCacheKey($name)
455
+ {
456
+ return $name;
457
+ }
458
+
459
+ public function isFresh($name, $time)
460
+ {
461
+ if (false === $lastModified = $this->getValue('last_modified', $name)) {
462
+ return false;
463
+ }
464
+
465
+ return $lastModified <= $time;
466
+ }
467
+
468
+ protected function getValue($column, $name)
469
+ {
470
+ $sth = $this->dbh->prepare('SELECT '.$column.' FROM templates WHERE name = :name');
471
+ $sth->execute(array(':name' => (string) $name));
472
+
473
+ return $sth->fetchColumn();
474
+ }
475
+ }
476
+
477
+ Finally, here is an example on how you can use it::
478
+
479
+ $loader = new DatabaseTwigLoader($dbh);
480
+ $twig = new Twig_Environment($loader);
481
+
482
+ echo $twig->render('index.twig', array('name' => 'Fabien'));
483
+
484
+ Using different Template Sources
485
+ --------------------------------
486
+
487
+ This recipe is the continuation of the previous one. Even if you store the
488
+ contributed templates in a database, you might want to keep the original/base
489
+ templates on the filesystem. When templates can be loaded from different
490
+ sources, you need to use the ``Twig_Loader_Chain`` loader.
491
+
492
+ As you can see in the previous recipe, we reference the template in the exact
493
+ same way as we would have done it with a regular filesystem loader. This is
494
+ the key to be able to mix and match templates coming from the database, the
495
+ filesystem, or any other loader for that matter: the template name should be a
496
+ logical name, and not the path from the filesystem::
497
+
498
+ $loader1 = new DatabaseTwigLoader($dbh);
499
+ $loader2 = new Twig_Loader_Array(array(
500
+ 'base.twig' => '{% block content %}{% endblock %}',
501
+ ));
502
+ $loader = new Twig_Loader_Chain(array($loader1, $loader2));
503
+
504
+ $twig = new Twig_Environment($loader);
505
+
506
+ echo $twig->render('index.twig', array('name' => 'Fabien'));
507
+
508
+ Now that the ``base.twig`` templates is defined in an array loader, you can
509
+ remove it from the database, and everything else will still work as before.
510
+
511
+ Loading a Template from a String
512
+ --------------------------------
513
+
514
+ From a template, you can easily load a template stored in a string via the
515
+ ``template_from_string`` function (available as of Twig 1.11 via the
516
+ ``Twig_Extension_StringLoader`` extension):
517
+
518
+ .. code-block:: jinja
519
+
520
+ {{ include(template_from_string("Hello {{ name }}")) }}
521
+
522
+ From PHP, it's also possible to load a template stored in a string via
523
+ ``Twig_Environment::createTemplate()`` (available as of Twig 1.18)::
524
+
525
+ $template = $twig->createTemplate('hello {{ name }}');
526
+ echo $template->render(array('name' => 'Fabien'));
527
+
528
+ .. note::
529
+
530
+ Never use the ``Twig_Loader_String`` loader, which has severe limitations.
531
+
532
+ Using Twig and AngularJS in the same Templates
533
+ ----------------------------------------------
534
+
535
+ Mixing different template syntaxes in the same file is not a recommended
536
+ practice as both AngularJS and Twig use the same delimiters in their syntax:
537
+ ``{{`` and ``}}``.
538
+
539
+ Still, if you want to use AngularJS and Twig in the same template, there are
540
+ two ways to make it work depending on the amount of AngularJS you need to
541
+ include in your templates:
542
+
543
+ * Escaping the AngularJS delimiters by wrapping AngularJS sections with the
544
+ ``{% verbatim %}`` tag or by escaping each delimiter via ``{{ '{{' }}`` and
545
+ ``{{ '}}' }}``;
546
+
547
+ * Changing the delimiters of one of the template engines (depending on which
548
+ engine you introduced last):
549
+
550
+ * For AngularJS, change the interpolation tags using the
551
+ ``interpolateProvider`` service, for instance at the module initialization
552
+ time:
553
+
554
+ ..code-block:: javascript
555
+
556
+ angular.module('myApp', []).config(function($interpolateProvider) {
557
+ $interpolateProvider.startSymbol('{[').endSymbol(']}');
558
+ });
559
+
560
+ * For Twig, change the delimiters via the ``tag_variable`` Lexer option:
561
+
562
+ ..code-block:: php
563
+
564
+ $env->setLexer(new Twig_Lexer($env, array(
565
+ 'tag_variable' => array('{[', ']}'),
566
+ )));
567
+
568
+ .. _callback: http://www.php.net/manual/en/function.is-callable.php
library/twig/twig/doc/tags/autoescape.rst ADDED
@@ -0,0 +1,81 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ``autoescape``
2
+ ==============
3
+
4
+ Whether automatic escaping is enabled or not, you can mark a section of a
5
+ template to be escaped or not by using the ``autoescape`` tag:
6
+
7
+ .. code-block:: jinja
8
+
9
+ {% autoescape %}
10
+ Everything will be automatically escaped in this block
11
+ using the HTML strategy
12
+ {% endautoescape %}
13
+
14
+ {% autoescape 'html' %}
15
+ Everything will be automatically escaped in this block
16
+ using the HTML strategy
17
+ {% endautoescape %}
18
+
19
+ {% autoescape 'js' %}
20
+ Everything will be automatically escaped in this block
21
+ using the js escaping strategy
22
+ {% endautoescape %}
23
+
24
+ {% autoescape false %}
25
+ Everything will be outputted as is in this block
26
+ {% endautoescape %}
27
+
28
+ .. note::
29
+
30
+ Before Twig 1.8, the syntax was different:
31
+
32
+ .. code-block:: jinja
33
+
34
+ {% autoescape true %}
35
+ Everything will be automatically escaped in this block
36
+ using the HTML strategy
37
+ {% endautoescape %}
38
+
39
+ {% autoescape false %}
40
+ Everything will be outputted as is in this block
41
+ {% endautoescape %}
42
+
43
+ {% autoescape true js %}
44
+ Everything will be automatically escaped in this block
45
+ using the js escaping strategy
46
+ {% endautoescape %}
47
+
48
+ When automatic escaping is enabled everything is escaped by default except for
49
+ values explicitly marked as safe. Those can be marked in the template by using
50
+ the :doc:`raw<../filters/raw>` filter:
51
+
52
+ .. code-block:: jinja
53
+
54
+ {% autoescape %}
55
+ {{ safe_value|raw }}
56
+ {% endautoescape %}
57
+
58
+ Functions returning template data (like :doc:`macros<macro>` and
59
+ :doc:`parent<../functions/parent>`) always return safe markup.
60
+
61
+ .. note::
62
+
63
+ Twig is smart enough to not escape an already escaped value by the
64
+ :doc:`escape<../filters/escape>` filter.
65
+
66
+ .. note::
67
+
68
+ Twig does not escape static expressions:
69
+
70
+ .. code-block:: jinja
71
+
72
+ {% set hello = "<strong>Hello</strong>" %}
73
+ {{ hello }}
74
+ {{ "<strong>world</strong>" }}
75
+
76
+ Will be rendered "<strong>Hello</strong> **world**".
77
+
78
+ .. note::
79
+
80
+ The chapter :doc:`Twig for Developers<../api>` gives more information
81
+ about when and how automatic escaping is applied.
library/twig/twig/doc/tags/block.rst ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ ``block``
2
+ =========
3
+
4
+ Blocks are used for inheritance and act as placeholders and replacements at
5
+ the same time. They are documented in detail in the documentation for the
6
+ :doc:`extends<../tags/extends>` tag.
7
+
8
+ Block names should consist of alphanumeric characters, and underscores. Dashes
9
+ are not permitted.
10
+
11
+ .. seealso:: :doc:`block<../functions/block>`, :doc:`parent<../functions/parent>`, :doc:`use<../tags/use>`, :doc:`extends<../tags/extends>`
library/twig/twig/doc/tags/do.rst ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ``do``
2
+ ======
3
+
4
+ .. versionadded:: 1.5
5
+ The ``do`` tag was added in Twig 1.5.
6
+
7
+ The ``do`` tag works exactly like the regular variable expression (``{{ ...
8
+ }}``) just that it doesn't print anything:
9
+
10
+ .. code-block:: jinja
11
+
12
+ {% do 1 + 2 %}
library/twig/twig/doc/tags/embed.rst ADDED
@@ -0,0 +1,178 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ``embed``
2
+ =========
3
+
4
+ .. versionadded:: 1.8
5
+ The ``embed`` tag was added in Twig 1.8.
6
+
7
+ The ``embed`` tag combines the behaviour of :doc:`include<include>` and
8
+ :doc:`extends<extends>`.
9
+ It allows you to include another template's contents, just like ``include``
10
+ does. But it also allows you to override any block defined inside the
11
+ included template, like when extending a template.
12
+
13
+ Think of an embedded template as a "micro layout skeleton".
14
+
15
+ .. code-block:: jinja
16
+
17
+ {% embed "teasers_skeleton.twig" %}
18
+ {# These blocks are defined in "teasers_skeleton.twig" #}
19
+ {# and we override them right here: #}
20
+ {% block left_teaser %}
21
+ Some content for the left teaser box
22
+ {% endblock %}
23
+ {% block right_teaser %}
24
+ Some content for the right teaser box
25
+ {% endblock %}
26
+ {% endembed %}
27
+
28
+ The ``embed`` tag takes the idea of template inheritance to the level of
29
+ content fragments. While template inheritance allows for "document skeletons",
30
+ which are filled with life by child templates, the ``embed`` tag allows you to
31
+ create "skeletons" for smaller units of content and re-use and fill them
32
+ anywhere you like.
33
+
34
+ Since the use case may not be obvious, let's look at a simplified example.
35
+ Imagine a base template shared by multiple HTML pages, defining a single block
36
+ named "content":
37
+
38
+ .. code-block:: text
39
+
40
+ ┌─── page layout ─────────────────────┐
41
+ │ │
42
+ │ ┌── block "content" ──┐ │
43
+ │ │ │ │
44
+ │ │ │ │
45
+ │ │ (child template to │ │
46
+ │ │ put content here) │ │
47
+ │ │ │ │
48
+ │ │ │ │
49
+ │ └─────────────────────┘ │
50
+ │ │
51
+ └─────────────────────────────────────┘
52
+
53
+ Some pages ("foo" and "bar") share the same content structure -
54
+ two vertically stacked boxes:
55
+
56
+ .. code-block:: text
57
+
58
+ ┌─── page layout ─────────────────────┐
59
+ │ │
60
+ │ ┌── block "content" ──┐ │
61
+ │ │ ┌─ block "top" ───┐ │ │
62
+ │ │ │ │ │ │
63
+ │ │ └─────────────────┘ │ │
64
+ │ │ ┌─ block "bottom" ┐ │ │
65
+ │ │ │ │ │ │
66
+ │ │ └─────────────────┘ │ │
67
+ │ └─────────────────────┘ │
68
+ │ │
69
+ └─────────────────────────────────────┘
70
+
71
+ While other pages ("boom" and "baz") share a different content structure -
72
+ two boxes side by side:
73
+
74
+ .. code-block:: text
75
+
76
+ ┌─── page layout ─────────────────────┐
77
+ │ │
78
+ │ ┌── block "content" ──┐ │
79
+ │ │ │ │
80
+ │ │ ┌ block ┐ ┌ block ┐ │ │
81
+ │ │ │"left" │ │"right"│ │ │
82
+ │ │ │ │ │ │ │ │
83
+ │ │ │ │ │ │ │ │
84
+ │ │ └───────┘ └───────┘ │ │
85
+ │ └─────────────────────┘ │
86
+ │ │
87
+ └─────────────────────────────────────┘
88
+
89
+ Without the ``embed`` tag, you have two ways to design your templates:
90
+
91
+ * Create two "intermediate" base templates that extend the master layout
92
+ template: one with vertically stacked boxes to be used by the "foo" and
93
+ "bar" pages and another one with side-by-side boxes for the "boom" and
94
+ "baz" pages.
95
+
96
+ * Embed the markup for the top/bottom and left/right boxes into each page
97
+ template directly.
98
+
99
+ These two solutions do not scale well because they each have a major drawback:
100
+
101
+ * The first solution may indeed work for this simplified example. But imagine
102
+ we add a sidebar, which may again contain different, recurring structures
103
+ of content. Now we would need to create intermediate base templates for
104
+ all occurring combinations of content structure and sidebar structure...
105
+ and so on.
106
+
107
+ * The second solution involves duplication of common code with all its negative
108
+ consequences: any change involves finding and editing all affected copies
109
+ of the structure, correctness has to be verified for each copy, copies may
110
+ go out of sync by careless modifications etc.
111
+
112
+ In such a situation, the ``embed`` tag comes in handy. The common layout
113
+ code can live in a single base template, and the two different content structures,
114
+ let's call them "micro layouts" go into separate templates which are embedded
115
+ as necessary:
116
+
117
+ Page template ``foo.twig``:
118
+
119
+ .. code-block:: jinja
120
+
121
+ {% extends "layout_skeleton.twig" %}
122
+
123
+ {% block content %}
124
+ {% embed "vertical_boxes_skeleton.twig" %}
125
+ {% block top %}
126
+ Some content for the top box
127
+ {% endblock %}
128
+
129
+ {% block bottom %}
130
+ Some content for the bottom box
131
+ {% endblock %}
132
+ {% endembed %}
133
+ {% endblock %}
134
+
135
+ And here is the code for ``vertical_boxes_skeleton.twig``:
136
+
137
+ .. code-block:: html+jinja
138
+
139
+ <div class="top_box">
140
+ {% block top %}
141
+ Top box default content
142
+ {% endblock %}
143
+ </div>
144
+
145
+ <div class="bottom_box">
146
+ {% block bottom %}
147
+ Bottom box default content
148
+ {% endblock %}
149
+ </div>
150
+
151
+ The goal of the ``vertical_boxes_skeleton.twig`` template being to factor
152
+ out the HTML markup for the boxes.
153
+
154
+ The ``embed`` tag takes the exact same arguments as the ``include`` tag:
155
+
156
+ .. code-block:: jinja
157
+
158
+ {% embed "base" with {'foo': 'bar'} %}
159
+ ...
160
+ {% endembed %}
161
+
162
+ {% embed "base" with {'foo': 'bar'} only %}
163
+ ...
164
+ {% endembed %}
165
+
166
+ {% embed "base" ignore missing %}
167
+ ...
168
+ {% endembed %}
169
+
170
+ .. warning::
171
+
172
+ As embedded templates do not have "names", auto-escaping strategies based
173
+ on the template name won't work as expected if you change the context (for
174
+ instance, if you embed a CSS/JavaScript template into an HTML one). In that
175
+ case, explicitly set the default auto-escaping strategy with the
176
+ ``autoescape`` tag.
177
+
178
+ .. seealso:: :doc:`include<../tags/include>`
library/twig/twig/doc/tags/extends.rst ADDED
@@ -0,0 +1,272 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ``extends``
2
+ ===========
3
+
4
+ The ``extends`` tag can be used to extend a template from another one.
5
+
6
+ .. note::
7
+
8
+ Like PHP, Twig does not support multiple inheritance. So you can only have
9
+ one extends tag called per rendering. However, Twig supports horizontal
10
+ :doc:`reuse<use>`.
11
+
12
+ Let's define a base template, ``base.html``, which defines a simple HTML
13
+ skeleton document:
14
+
15
+ .. code-block:: html+jinja
16
+
17
+ <!DOCTYPE html>
18
+ <html>
19
+ <head>
20
+ {% block head %}
21
+ <link rel="stylesheet" href="style.css" />
22
+ <title>{% block title %}{% endblock %} - My Webpage</title>
23
+ {% endblock %}
24
+ </head>
25
+ <body>
26
+ <div id="content">{% block content %}{% endblock %}</div>
27
+ <div id="footer">
28
+ {% block footer %}
29
+ &copy; Copyright 2011 by <a href="http://domain.invalid/">you</a>.
30
+ {% endblock %}
31
+ </div>
32
+ </body>
33
+ </html>
34
+
35
+ In this example, the :doc:`block<block>` tags define four blocks that child
36
+ templates can fill in.
37
+
38
+ All the ``block`` tag does is to tell the template engine that a child
39
+ template may override those portions of the template.
40
+
41
+ Child Template
42
+ --------------
43
+
44
+ A child template might look like this:
45
+
46
+ .. code-block:: jinja
47
+
48
+ {% extends "base.html" %}
49
+
50
+ {% block title %}Index{% endblock %}
51
+ {% block head %}
52
+ {{ parent() }}
53
+ <style type="text/css">
54
+ .important { color: #336699; }
55
+ </style>
56
+ {% endblock %}
57
+ {% block content %}
58
+ <h1>Index</h1>
59
+ <p class="important">
60
+ Welcome on my awesome homepage.
61
+ </p>
62
+ {% endblock %}
63
+
64
+ The ``extends`` tag is the key here. It tells the template engine that this
65
+ template "extends" another template. When the template system evaluates this
66
+ template, first it locates the parent. The extends tag should be the first tag
67
+ in the template.
68
+
69
+ Note that since the child template doesn't define the ``footer`` block, the
70
+ value from the parent template is used instead.
71
+
72
+ You can't define multiple ``block`` tags with the same name in the same
73
+ template. This limitation exists because a block tag works in "both"
74
+ directions. That is, a block tag doesn't just provide a hole to fill - it also
75
+ defines the content that fills the hole in the *parent*. If there were two
76
+ similarly-named ``block`` tags in a template, that template's parent wouldn't
77
+ know which one of the blocks' content to use.
78
+
79
+ If you want to print a block multiple times you can however use the
80
+ ``block`` function:
81
+
82
+ .. code-block:: jinja
83
+
84
+ <title>{% block title %}{% endblock %}</title>
85
+ <h1>{{ block('title') }}</h1>
86
+ {% block body %}{% endblock %}
87
+
88
+ Parent Blocks
89
+ -------------
90
+
91
+ It's possible to render the contents of the parent block by using the
92
+ :doc:`parent<../functions/parent>` function. This gives back the results of
93
+ the parent block:
94
+
95
+ .. code-block:: jinja
96
+
97
+ {% block sidebar %}
98
+ <h3>Table Of Contents</h3>
99
+ ...
100
+ {{ parent() }}
101
+ {% endblock %}
102
+
103
+ Named Block End-Tags
104
+ --------------------
105
+
106
+ Twig allows you to put the name of the block after the end tag for better
107
+ readability:
108
+
109
+ .. code-block:: jinja
110
+
111
+ {% block sidebar %}
112
+ {% block inner_sidebar %}
113
+ ...
114
+ {% endblock inner_sidebar %}
115
+ {% endblock sidebar %}
116
+
117
+ Of course, the name after the ``endblock`` word must match the block name.
118
+
119
+ Block Nesting and Scope
120
+ -----------------------
121
+
122
+ Blocks can be nested for more complex layouts. Per default, blocks have access
123
+ to variables from outer scopes:
124
+
125
+ .. code-block:: jinja
126
+
127
+ {% for item in seq %}
128
+ <li>{% block loop_item %}{{ item }}{% endblock %}</li>
129
+ {% endfor %}
130
+
131
+ Block Shortcuts
132
+ ---------------
133
+
134
+ For blocks with little content, it's possible to use a shortcut syntax. The
135
+ following constructs do the same thing:
136
+
137
+ .. code-block:: jinja
138
+
139
+ {% block title %}
140
+ {{ page_title|title }}
141
+ {% endblock %}
142
+
143
+ .. code-block:: jinja
144
+
145
+ {% block title page_title|title %}
146
+
147
+ Dynamic Inheritance
148
+ -------------------
149
+
150
+ Twig supports dynamic inheritance by using a variable as the base template:
151
+
152
+ .. code-block:: jinja
153
+
154
+ {% extends some_var %}
155
+
156
+ If the variable evaluates to a ``Twig_Template`` or a ``Twig_TemplateWrapper``
157
+ instance, Twig will use it as the parent template::
158
+
159
+ // {% extends layout %}
160
+
161
+ // deprecated as of Twig 1.28
162
+ $layout = $twig->loadTemplate('some_layout_template.twig');
163
+
164
+ // as of Twig 1.28
165
+ $layout = $twig->load('some_layout_template.twig');
166
+
167
+ $twig->display('template.twig', array('layout' => $layout));
168
+
169
+ .. versionadded:: 1.2
170
+ The possibility to pass an array of templates has been added in Twig 1.2.
171
+
172
+ You can also provide a list of templates that are checked for existence. The
173
+ first template that exists will be used as a parent:
174
+
175
+ .. code-block:: jinja
176
+
177
+ {% extends ['layout.html', 'base_layout.html'] %}
178
+
179
+ Conditional Inheritance
180
+ -----------------------
181
+
182
+ As the template name for the parent can be any valid Twig expression, it's
183
+ possible to make the inheritance mechanism conditional:
184
+
185
+ .. code-block:: jinja
186
+
187
+ {% extends standalone ? "minimum.html" : "base.html" %}
188
+
189
+ In this example, the template will extend the "minimum.html" layout template
190
+ if the ``standalone`` variable evaluates to ``true``, and "base.html"
191
+ otherwise.
192
+
193
+ How do blocks work?
194
+ -------------------
195
+
196
+ A block provides a way to change how a certain part of a template is rendered
197
+ but it does not interfere in any way with the logic around it.
198
+
199
+ Let's take the following example to illustrate how a block works and more
200
+ importantly, how it does not work:
201
+
202
+ .. code-block:: jinja
203
+
204
+ {# base.twig #}
205
+
206
+ {% for post in posts %}
207
+ {% block post %}
208
+ <h1>{{ post.title }}</h1>
209
+ <p>{{ post.body }}</p>
210
+ {% endblock %}
211
+ {% endfor %}
212
+
213
+ If you render this template, the result would be exactly the same with or
214
+ without the ``block`` tag. The ``block`` inside the ``for`` loop is just a way
215
+ to make it overridable by a child template:
216
+
217
+ .. code-block:: jinja
218
+
219
+ {# child.twig #}
220
+
221
+ {% extends "base.twig" %}
222
+
223
+ {% block post %}
224
+ <article>
225
+ <header>{{ post.title }}</header>
226
+ <section>{{ post.text }}</section>
227
+ </article>
228
+ {% endblock %}
229
+
230
+ Now, when rendering the child template, the loop is going to use the block
231
+ defined in the child template instead of the one defined in the base one; the
232
+ executed template is then equivalent to the following one:
233
+
234
+ .. code-block:: jinja
235
+
236
+ {% for post in posts %}
237
+ <article>
238
+ <header>{{ post.title }}</header>
239
+ <section>{{ post.text }}</section>
240
+ </article>
241
+ {% endfor %}
242
+
243
+ Let's take another example: a block included within an ``if`` statement:
244
+
245
+ .. code-block:: jinja
246
+
247
+ {% if posts is empty %}
248
+ {% block head %}
249
+ {{ parent() }}
250
+
251
+ <meta name="robots" content="noindex, follow">
252
+ {% endblock head %}
253
+ {% endif %}
254
+
255
+ Contrary to what you might think, this template does not define a block
256
+ conditionally; it just makes overridable by a child template the output of
257
+ what will be rendered when the condition is ``true``.
258
+
259
+ If you want the output to be displayed conditionally, use the following
260
+ instead:
261
+
262
+ .. code-block:: jinja
263
+
264
+ {% block head %}
265
+ {{ parent() }}
266
+
267
+ {% if posts is empty %}
268
+ <meta name="robots" content="noindex, follow">
269
+ {% endif %}
270
+ {% endblock head %}
271
+
272
+ .. seealso:: :doc:`block<../functions/block>`, :doc:`block<../tags/block>`, :doc:`parent<../functions/parent>`, :doc:`use<../tags/use>`
library/twig/twig/doc/tags/filter.rst ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ``filter``
2
+ ==========
3
+
4
+ Filter sections allow you to apply regular Twig filters on a block of template
5
+ data. Just wrap the code in the special ``filter`` section:
6
+
7
+ .. code-block:: jinja
8
+
9
+ {% filter upper %}
10
+ This text becomes uppercase
11
+ {% endfilter %}
12
+
13
+ You can also chain filters:
14
+
15
+ .. code-block:: jinja
16
+
17
+ {% filter lower|escape %}
18
+ <strong>SOME TEXT</strong>
19
+ {% endfilter %}
20
+
21
+ {# outputs "&lt;strong&gt;some text&lt;/strong&gt;" #}
library/twig/twig/doc/tags/flush.rst ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ``flush``
2
+ =========
3
+
4
+ .. versionadded:: 1.5
5
+ The flush tag was added in Twig 1.5.
6
+
7
+ The ``flush`` tag tells Twig to flush the output buffer:
8
+
9
+ .. code-block:: jinja
10
+
11
+ {% flush %}
12
+
13
+ .. note::
14
+
15
+ Internally, Twig uses the PHP `flush`_ function.
16
+
17
+ .. _`flush`: http://php.net/flush
library/twig/twig/doc/tags/for.rst ADDED
@@ -0,0 +1,172 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ``for``
2
+ =======
3
+
4
+ Loop over each item in a sequence. For example, to display a list of users
5
+ provided in a variable called ``users``:
6
+
7
+ .. code-block:: jinja
8
+
9
+ <h1>Members</h1>
10
+ <ul>
11
+ {% for user in users %}
12
+ <li>{{ user.username|e }}</li>
13
+ {% endfor %}
14
+ </ul>
15
+
16
+ .. note::
17
+
18
+ A sequence can be either an array or an object implementing the
19
+ ``Traversable`` interface.
20
+
21
+ If you do need to iterate over a sequence of numbers, you can use the ``..``
22
+ operator:
23
+
24
+ .. code-block:: jinja
25
+
26
+ {% for i in 0..10 %}
27
+ * {{ i }}
28
+ {% endfor %}
29
+
30
+ The above snippet of code would print all numbers from 0 to 10.
31
+
32
+ It can be also useful with letters:
33
+
34
+ .. code-block:: jinja
35
+
36
+ {% for letter in 'a'..'z' %}
37
+ * {{ letter }}
38
+ {% endfor %}
39
+
40
+ The ``..`` operator can take any expression at both sides:
41
+
42
+ .. code-block:: jinja
43
+
44
+ {% for letter in 'a'|upper..'z'|upper %}
45
+ * {{ letter }}
46
+ {% endfor %}
47
+
48
+ .. tip:
49
+
50
+ If you need a step different from 1, you can use the ``range`` function
51
+ instead.
52
+
53
+ The `loop` variable
54
+ -------------------
55
+
56
+ Inside of a ``for`` loop block you can access some special variables:
57
+
58
+ ===================== =============================================================
59
+ Variable Description
60
+ ===================== =============================================================
61
+ ``loop.index`` The current iteration of the loop. (1 indexed)
62
+ ``loop.index0`` The current iteration of the loop. (0 indexed)
63
+ ``loop.revindex`` The number of iterations from the end of the loop (1 indexed)
64
+ ``loop.revindex0`` The number of iterations from the end of the loop (0 indexed)
65
+ ``loop.first`` True if first iteration
66
+ ``loop.last`` True if last iteration
67
+ ``loop.length`` The number of items in the sequence
68
+ ``loop.parent`` The parent context
69
+ ===================== =============================================================
70
+
71
+ .. code-block:: jinja
72
+
73
+ {% for user in users %}
74
+ {{ loop.index }} - {{ user.username }}
75
+ {% endfor %}
76
+
77
+ .. note::
78
+
79
+ The ``loop.length``, ``loop.revindex``, ``loop.revindex0``, and
80
+ ``loop.last`` variables are only available for PHP arrays, or objects that
81
+ implement the ``Countable`` interface. They are also not available when
82
+ looping with a condition.
83
+
84
+ .. versionadded:: 1.2
85
+ The ``if`` modifier support has been added in Twig 1.2.
86
+
87
+ Adding a condition
88
+ ------------------
89
+
90
+ Unlike in PHP, it's not possible to ``break`` or ``continue`` in a loop. You
91
+ can however filter the sequence during iteration which allows you to skip
92
+ items. The following example skips all the users which are not active:
93
+
94
+ .. code-block:: jinja
95
+
96
+ <ul>
97
+ {% for user in users if user.active %}
98
+ <li>{{ user.username|e }}</li>
99
+ {% endfor %}
100
+ </ul>
101
+
102
+ The advantage is that the special loop variable will count correctly thus not
103
+ counting the users not iterated over. Keep in mind that properties like
104
+ ``loop.last`` will not be defined when using loop conditions.
105
+
106
+ .. note::
107
+
108
+ Using the ``loop`` variable within the condition is not recommended as it
109
+ will probably not be doing what you expect it to. For instance, adding a
110
+ condition like ``loop.index > 4`` won't work as the index is only
111
+ incremented when the condition is true (so the condition will never
112
+ match).
113
+
114
+ The `else` Clause
115
+ -----------------
116
+
117
+ If no iteration took place because the sequence was empty, you can render a
118
+ replacement block by using ``else``:
119
+
120
+ .. code-block:: jinja
121
+
122
+ <ul>
123
+ {% for user in users %}
124
+ <li>{{ user.username|e }}</li>
125
+ {% else %}
126
+ <li><em>no user found</em></li>
127
+ {% endfor %}
128
+ </ul>
129
+
130
+ Iterating over Keys
131
+ -------------------
132
+
133
+ By default, a loop iterates over the values of the sequence. You can iterate
134
+ on keys by using the ``keys`` filter:
135
+
136
+ .. code-block:: jinja
137
+
138
+ <h1>Members</h1>
139
+ <ul>
140
+ {% for key in users|keys %}
141
+ <li>{{ key }}</li>
142
+ {% endfor %}
143
+ </ul>
144
+
145
+ Iterating over Keys and Values
146
+ ------------------------------
147
+
148
+ You can also access both keys and values:
149
+
150
+ .. code-block:: jinja
151
+
152
+ <h1>Members</h1>
153
+ <ul>
154
+ {% for key, user in users %}
155
+ <li>{{ key }}: {{ user.username|e }}</li>
156
+ {% endfor %}
157
+ </ul>
158
+
159
+ Iterating over a Subset
160
+ -----------------------
161
+
162
+ You might want to iterate over a subset of values. This can be achieved using
163
+ the :doc:`slice <../filters/slice>` filter:
164
+
165
+ .. code-block:: jinja
166
+
167
+ <h1>Top Ten Members</h1>
168
+ <ul>
169
+ {% for user in users|slice(0, 10) %}
170
+ <li>{{ user.username|e }}</li>
171
+ {% endfor %}
172
+ </ul>
library/twig/twig/doc/tags/from.rst ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
1
+ ``from``
2
+ ========
3
+
4
+ The ``from`` tag imports :doc:`macro<../tags/macro>` names into the current
5
+ namespace. The tag is documented in detail in the documentation for the
6
+ :doc:`import<../tags/import>` tag.
7
+
8
+ .. seealso:: :doc:`macro<../tags/macro>`, :doc:`import<../tags/import>`
library/twig/twig/doc/tags/if.rst ADDED
@@ -0,0 +1,76 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ``if``
2
+ ======
3
+
4
+ The ``if`` statement in Twig is comparable with the if statements of PHP.
5
+
6
+ In the simplest form you can use it to test if an expression evaluates to
7
+ ``true``:
8
+
9
+ .. code-block:: jinja
10
+
11
+ {% if online == false %}
12
+ <p>Our website is in maintenance mode. Please, come back later.</p>
13
+ {% endif %}
14
+
15
+ You can also test if an array is not empty:
16
+
17
+ .. code-block:: jinja
18
+
19
+ {% if users %}
20
+ <ul>
21
+ {% for user in users %}
22
+ <li>{{ user.username|e }}</li>
23
+ {% endfor %}
24
+ </ul>
25
+ {% endif %}
26
+
27
+ .. note::
28
+
29
+ If you want to test if the variable is defined, use ``if users is
30
+ defined`` instead.
31
+
32
+ You can also use ``not`` to check for values that evaluate to ``false``:
33
+
34
+ .. code-block:: jinja
35
+
36
+ {% if not user.subscribed %}
37
+ <p>You are not subscribed to our mailing list.</p>
38
+ {% endif %}
39
+
40
+ For multiple conditions, ``and`` and ``or`` can be used:
41
+
42
+ .. code-block:: jinja
43
+
44
+ {% if temperature > 18 and temperature < 27 %}
45
+ <p>It's a nice day for a walk in the park.</p>
46
+ {% endif %}
47
+
48
+ For multiple branches ``elseif`` and ``else`` can be used like in PHP. You can
49
+ use more complex ``expressions`` there too:
50
+
51
+ .. code-block:: jinja
52
+
53
+ {% if kenny.sick %}
54
+ Kenny is sick.
55
+ {% elseif kenny.dead %}
56
+ You killed Kenny! You bastard!!!
57
+ {% else %}
58
+ Kenny looks okay --- so far
59
+ {% endif %}
60
+
61
+ .. note::
62
+
63
+ The rules to determine if an expression is ``true`` or ``false`` are the
64
+ same as in PHP; here are the edge cases rules:
65
+
66
+ ====================== ====================
67
+ Value Boolean evaluation
68
+ ====================== ====================
69
+ empty string false
70
+ numeric zero false
71
+ whitespace-only string true
72
+ empty array false
73
+ null false
74
+ non-empty array true
75
+ object true
76
+ ====================== ====================
library/twig/twig/doc/tags/import.rst ADDED
@@ -0,0 +1,57 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ``import``
2
+ ==========
3
+
4
+ Twig supports putting often used code into :doc:`macros<../tags/macro>`. These
5
+ macros can go into different templates and get imported from there.
6
+
7
+ There are two ways to import templates. You can import the complete template
8
+ into a variable or request specific macros from it.
9
+
10
+ Imagine we have a helper module that renders forms (called ``forms.html``):
11
+
12
+ .. code-block:: jinja
13
+
14
+ {% macro input(name, value, type, size) %}
15
+ <input type="{{ type|default('text') }}" name="{{ name }}" value="{{ value|e }}" size="{{ size|default(20) }}" />
16
+ {% endmacro %}
17
+
18
+ {% macro textarea(name, value, rows, cols) %}
19
+ <textarea name="{{ name }}" rows="{{ rows|default(10) }}" cols="{{ cols|default(40) }}">{{ value|e }}</textarea>
20
+ {% endmacro %}
21
+
22
+ The easiest and most flexible is importing the whole module into a variable.
23
+ That way you can access the attributes:
24
+
25
+ .. code-block:: jinja
26
+
27
+ {% import 'forms.html' as forms %}
28
+
29
+ <dl>
30
+ <dt>Username</dt>
31
+ <dd>{{ forms.input('username') }}</dd>
32
+ <dt>Password</dt>
33
+ <dd>{{ forms.input('password', null, 'password') }}</dd>
34
+ </dl>
35
+ <p>{{ forms.textarea('comment') }}</p>
36
+
37
+ Alternatively you can import names from the template into the current
38
+ namespace:
39
+
40
+ .. code-block:: jinja
41
+
42
+ {% from 'forms.html' import input as input_field, textarea %}
43
+
44
+ <dl>
45
+ <dt>Username</dt>
46
+ <dd>{{ input_field('username') }}</dd>
47
+ <dt>Password</dt>
48
+ <dd>{{ input_field('password', '', 'password') }}</dd>
49
+ </dl>
50
+ <p>{{ textarea('comment') }}</p>
51
+
52
+ .. tip::
53
+
54
+ To import macros from the current file, use the special ``_self`` variable
55
+ for the source.
56
+
57
+ .. seealso:: :doc:`macro<../tags/macro>`, :doc:`from<../tags/from>`
library/twig/twig/doc/tags/include.rst ADDED
@@ -0,0 +1,90 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ``include``
2
+ ===========
3
+
4
+ The ``include`` statement includes a template and returns the rendered content
5
+ of that file into the current namespace:
6
+
7
+ .. code-block:: jinja
8
+
9
+ {% include 'header.html' %}
10
+ Body
11
+ {% include 'footer.html' %}
12
+
13
+ Included templates have access to the variables of the active context.
14
+
15
+ If you are using the filesystem loader, the templates are looked for in the
16
+ paths defined by it.
17
+
18
+ You can add additional variables by passing them after the ``with`` keyword:
19
+
20
+ .. code-block:: jinja
21
+
22
+ {# template.html will have access to the variables from the current context and the additional ones provided #}
23
+ {% include 'template.html' with {'foo': 'bar'} %}
24
+
25
+ {% set vars = {'foo': 'bar'} %}
26
+ {% include 'template.html' with vars %}
27
+
28
+ You can disable access to the context by appending the ``only`` keyword:
29
+
30
+ .. code-block:: jinja
31
+
32
+ {# only the foo variable will be accessible #}
33
+ {% include 'template.html' with {'foo': 'bar'} only %}
34
+
35
+ .. code-block:: jinja
36
+
37
+ {# no variables will be accessible #}
38
+ {% include 'template.html' only %}
39
+
40
+ .. tip::
41
+
42
+ When including a template created by an end user, you should consider
43
+ sandboxing it. More information in the :doc:`Twig for Developers<../api>`
44
+ chapter and in the :doc:`sandbox<../tags/sandbox>` tag documentation.
45
+
46
+ The template name can be any valid Twig expression:
47
+
48
+ .. code-block:: jinja
49
+
50
+ {% include some_var %}
51
+ {% include ajax ? 'ajax.html' : 'not_ajax.html' %}
52
+
53
+ And if the expression evaluates to a ``Twig_Template`` or a
54
+ ``Twig_TemplateWrapper`` instance, Twig will use it directly::
55
+
56
+ // {% include template %}
57
+
58
+ // deprecated as of Twig 1.28
59
+ $template = $twig->loadTemplate('some_template.twig');
60
+
61
+ // as of Twig 1.28
62
+ $template = $twig->load('some_template.twig');
63
+
64
+ $twig->display('template.twig', array('template' => $template));
65
+
66
+ .. versionadded:: 1.2
67
+ The ``ignore missing`` feature has been added in Twig 1.2.
68
+
69
+ You can mark an include with ``ignore missing`` in which case Twig will ignore
70
+ the statement if the template to be included does not exist. It has to be
71
+ placed just after the template name. Here some valid examples:
72
+
73
+ .. code-block:: jinja
74
+
75
+ {% include 'sidebar.html' ignore missing %}
76
+ {% include 'sidebar.html' ignore missing with {'foo': 'bar'} %}
77
+ {% include 'sidebar.html' ignore missing only %}
78
+
79
+ .. versionadded:: 1.2
80
+ The possibility to pass an array of templates has been added in Twig 1.2.
81
+
82
+ You can also provide a list of templates that are checked for existence before
83
+ inclusion. The first template that exists will be included:
84
+
85
+ .. code-block:: jinja
86
+
87
+ {% include ['page_detailed.html', 'page.html'] %}
88
+
89
+ If ``ignore missing`` is given, it will fall back to rendering nothing if none
90
+ of the templates exist, otherwise it will throw an exception.
library/twig/twig/doc/tags/index.rst ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Tags
2
+ ====
3
+
4
+ .. toctree::
5
+ :maxdepth: 1
6
+
7
+ autoescape
8
+ block
9
+ do
10
+ embed
11
+ extends
12
+ filter
13
+ flush
14
+ for
15
+ from
16
+ if
17
+ import
18
+ include
19
+ macro
20
+ sandbox
21
+ set
22
+ spaceless
23
+ use
24
+ verbatim
25
+ with
library/twig/twig/doc/tags/macro.rst ADDED
@@ -0,0 +1,103 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ``macro``
2
+ =========
3
+
4
+ Macros are comparable with functions in regular programming languages. They
5
+ are useful to put often used HTML idioms into reusable elements to not repeat
6
+ yourself.
7
+
8
+ Here is a small example of a macro that renders a form element:
9
+
10
+ .. code-block:: jinja
11
+
12
+ {% macro input(name, value, type, size) %}
13
+ <input type="{{ type|default('text') }}" name="{{ name }}" value="{{ value|e }}" size="{{ size|default(20) }}" />
14
+ {% endmacro %}
15
+
16
+ Macros differ from native PHP functions in a few ways:
17
+
18
+ * Default argument values are defined by using the ``default`` filter in the
19
+ macro body;
20
+
21
+ * Arguments of a macro are always optional.
22
+
23
+ * If extra positional arguments are passed to a macro, they end up in the
24
+ special ``varargs`` variable as a list of values.
25
+
26
+ But as with PHP functions, macros don't have access to the current template
27
+ variables.
28
+
29
+ .. tip::
30
+
31
+ You can pass the whole context as an argument by using the special
32
+ ``_context`` variable.
33
+
34
+ Import
35
+ ------
36
+
37
+ Macros can be defined in any template, and need to be "imported" before being
38
+ used (see the documentation for the :doc:`import<../tags/import>` tag for more
39
+ information):
40
+
41
+ .. code-block:: jinja
42
+
43
+ {% import "forms.html" as forms %}
44
+
45
+ The above ``import`` call imports the "forms.html" file (which can contain only
46
+ macros, or a template and some macros), and import the functions as items of
47
+ the ``forms`` variable.
48
+
49
+ The macro can then be called at will:
50
+
51
+ .. code-block:: jinja
52
+
53
+ <p>{{ forms.input('username') }}</p>
54
+ <p>{{ forms.input('password', null, 'password') }}</p>
55
+
56
+ If macros are defined and used in the same template, you can use the
57
+ special ``_self`` variable to import them:
58
+
59
+ .. code-block:: jinja
60
+
61
+ {% import _self as forms %}
62
+
63
+ <p>{{ forms.input('username') }}</p>
64
+
65
+ .. warning::
66
+
67
+ When you define a macro in the template where you are going to use it, you
68
+ might be tempted to call the macro directly via ``_self.input()`` instead
69
+ of importing it; even if seems to work, this is just a side-effect of the
70
+ current implementation and it won't work anymore in Twig 2.x.
71
+
72
+ When you want to use a macro in another macro from the same file, you need to
73
+ import it locally:
74
+
75
+ .. code-block:: jinja
76
+
77
+ {% macro input(name, value, type, size) %}
78
+ <input type="{{ type|default('text') }}" name="{{ name }}" value="{{ value|e }}" size="{{ size|default(20) }}" />
79
+ {% endmacro %}
80
+
81
+ {% macro wrapped_input(name, value, type, size) %}
82
+ {% import _self as forms %}
83
+
84
+ <div class="field">
85
+ {{ forms.input(name, value, type, size) }}
86
+ </div>
87
+ {% endmacro %}
88
+
89
+ Named Macro End-Tags
90
+ --------------------
91
+
92
+ Twig allows you to put the name of the macro after the end tag for better
93
+ readability:
94
+
95
+ .. code-block:: jinja
96
+
97
+ {% macro input() %}
98
+ ...
99
+ {% endmacro input %}
100
+
101
+ Of course, the name after the ``endmacro`` word must match the macro name.
102
+
103
+ .. seealso:: :doc:`from<../tags/from>`, :doc:`import<../tags/import>`
library/twig/twig/doc/tags/sandbox.rst ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ``sandbox``
2
+ ===========
3
+
4
+ The ``sandbox`` tag can be used to enable the sandboxing mode for an included
5
+ template, when sandboxing is not enabled globally for the Twig environment:
6
+
7
+ .. code-block:: jinja
8
+
9
+ {% sandbox %}
10
+ {% include 'user.html' %}
11
+ {% endsandbox %}
12
+
13
+ .. warning::
14
+
15
+ The ``sandbox`` tag is only available when the sandbox extension is
16
+ enabled (see the :doc:`Twig for Developers<../api>` chapter).
17
+
18
+ .. note::
19
+
20
+ The ``sandbox`` tag can only be used to sandbox an include tag and it
21
+ cannot be used to sandbox a section of a template. The following example
22
+ won't work:
23
+
24
+ .. code-block:: jinja
25
+
26
+ {% sandbox %}
27
+ {% for i in 1..2 %}
28
+ {{ i }}
29
+ {% endfor %}
30
+ {% endsandbox %}
library/twig/twig/doc/tags/set.rst ADDED
@@ -0,0 +1,78 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ``set``
2
+ =======
3
+
4
+ Inside code blocks you can also assign values to variables. Assignments use
5
+ the ``set`` tag and can have multiple targets.
6
+
7
+ Here is how you can assign the ``bar`` value to the ``foo`` variable:
8
+
9
+ .. code-block:: jinja
10
+
11
+ {% set foo = 'bar' %}
12
+
13
+ After the ``set`` call, the ``foo`` variable is available in the template like
14
+ any other ones:
15
+
16
+ .. code-block:: jinja
17
+
18
+ {# displays bar #}
19
+ {{ foo }}
20
+
21
+ The assigned value can be any valid :ref:`Twig expressions
22
+ <twig-expressions>`:
23
+
24
+ .. code-block:: jinja
25
+
26
+ {% set foo = [1, 2] %}
27
+ {% set foo = {'foo': 'bar'} %}
28
+ {% set foo = 'foo' ~ 'bar' %}
29
+
30
+ Several variables can be assigned in one block:
31
+
32
+ .. code-block:: jinja
33
+
34
+ {% set foo, bar = 'foo', 'bar' %}
35
+
36
+ {# is equivalent to #}
37
+
38
+ {% set foo = 'foo' %}
39
+ {% set bar = 'bar' %}
40
+
41
+ The ``set`` tag can also be used to 'capture' chunks of text:
42
+
43
+ .. code-block:: jinja
44
+
45
+ {% set foo %}
46
+ <div id="pagination">
47
+ ...
48
+ </div>
49
+ {% endset %}
50
+
51
+ .. caution::
52
+
53
+ If you enable automatic output escaping, Twig will only consider the
54
+ content to be safe when capturing chunks of text.
55
+
56
+ .. note::
57
+
58
+ Note that loops are scoped in Twig; therefore a variable declared inside a
59
+ ``for`` loop is not accessible outside the loop itself:
60
+
61
+ .. code-block:: jinja
62
+
63
+ {% for item in list %}
64
+ {% set foo = item %}
65
+ {% endfor %}
66
+
67
+ {# foo is NOT available #}
68
+
69
+ If you want to access the variable, just declare it before the loop:
70
+
71
+ .. code-block:: jinja
72
+
73
+ {% set foo = "" %}
74
+ {% for item in list %}
75
+ {% set foo = item %}
76
+ {% endfor %}
77
+
78
+ {# foo is available #}
library/twig/twig/doc/tags/spaceless.rst ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ``spaceless``
2
+ =============
3
+
4
+ Use the ``spaceless`` tag to remove whitespace *between HTML tags*, not
5
+ whitespace within HTML tags or whitespace in plain text:
6
+
7
+ .. code-block:: jinja
8
+
9
+ {% spaceless %}
10
+ <div>
11
+ <strong>foo</strong>
12
+ </div>
13
+ {% endspaceless %}
14
+
15
+ {# output will be <div><strong>foo</strong></div> #}
16
+
17
+ This tag is not meant to "optimize" the size of the generated HTML content but
18
+ merely to avoid extra whitespace between HTML tags to avoid browser rendering
19
+ quirks under some circumstances.
20
+
21
+ .. tip::
22
+
23
+ If you want to optimize the size of the generated HTML content, gzip
24
+ compress the output instead.
25
+
26
+ .. tip::
27
+
28
+ If you want to create a tag that actually removes all extra whitespace in
29
+ an HTML string, be warned that this is not as easy as it seems to be
30
+ (think of ``textarea`` or ``pre`` tags for instance). Using a third-party
31
+ library like Tidy is probably a better idea.
32
+
33
+ .. tip::
34
+
35
+ For more information on whitespace control, read the
36
+ :ref:`dedicated section <templates-whitespace-control>` of the documentation and learn how
37
+ you can also use the whitespace control modifier on your tags.
library/twig/twig/doc/tags/use.rst ADDED
@@ -0,0 +1,124 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ``use``
2
+ =======
3
+
4
+ .. versionadded:: 1.1
5
+ Horizontal reuse was added in Twig 1.1.
6
+
7
+ .. note::
8
+
9
+ Horizontal reuse is an advanced Twig feature that is hardly ever needed in
10
+ regular templates. It is mainly used by projects that need to make
11
+ template blocks reusable without using inheritance.
12
+
13
+ Template inheritance is one of the most powerful features of Twig but it is
14
+ limited to single inheritance; a template can only extend one other template.
15
+ This limitation makes template inheritance simple to understand and easy to
16
+ debug:
17
+
18
+ .. code-block:: jinja
19
+
20
+ {% extends "base.html" %}
21
+
22
+ {% block title %}{% endblock %}
23
+ {% block content %}{% endblock %}
24
+
25
+ Horizontal reuse is a way to achieve the same goal as multiple inheritance,
26
+ but without the associated complexity:
27
+
28
+ .. code-block:: jinja
29
+
30
+ {% extends "base.html" %}
31
+
32
+ {% use "blocks.html" %}
33
+
34
+ {% block title %}{% endblock %}
35
+ {% block content %}{% endblock %}
36
+
37
+ The ``use`` statement tells Twig to import the blocks defined in
38
+ ``blocks.html`` into the current template (it's like macros, but for blocks):
39
+
40
+ .. code-block:: jinja
41
+
42
+ {# blocks.html #}
43
+
44
+ {% block sidebar %}{% endblock %}
45
+
46
+ In this example, the ``use`` statement imports the ``sidebar`` block into the
47
+ main template. The code is mostly equivalent to the following one (the
48
+ imported blocks are not outputted automatically):
49
+
50
+ .. code-block:: jinja
51
+
52
+ {% extends "base.html" %}
53
+
54
+ {% block sidebar %}{% endblock %}
55
+ {% block title %}{% endblock %}
56
+ {% block content %}{% endblock %}
57
+
58
+ .. note::
59
+
60
+ The ``use`` tag only imports a template if it does not extend another
61
+ template, if it does not define macros, and if the body is empty. But it
62
+ can *use* other templates.
63
+
64
+ .. note::
65
+
66
+ Because ``use`` statements are resolved independently of the context
67
+ passed to the template, the template reference cannot be an expression.
68
+
69
+ The main template can also override any imported block. If the template
70
+ already defines the ``sidebar`` block, then the one defined in ``blocks.html``
71
+ is ignored. To avoid name conflicts, you can rename imported blocks:
72
+
73
+ .. code-block:: jinja
74
+
75
+ {% extends "base.html" %}
76
+
77
+ {% use "blocks.html" with sidebar as base_sidebar, title as base_title %}
78
+
79
+ {% block sidebar %}{% endblock %}
80
+ {% block title %}{% endblock %}
81
+ {% block content %}{% endblock %}
82
+
83
+ .. versionadded:: 1.3
84
+ The ``parent()`` support was added in Twig 1.3.
85
+
86
+ The ``parent()`` function automatically determines the correct inheritance
87
+ tree, so it can be used when overriding a block defined in an imported
88
+ template:
89
+
90
+ .. code-block:: jinja
91
+
92
+ {% extends "base.html" %}
93
+
94
+ {% use "blocks.html" %}
95
+
96
+ {% block sidebar %}
97
+ {{ parent() }}
98
+ {% endblock %}
99
+
100
+ {% block title %}{% endblock %}
101
+ {% block content %}{% endblock %}
102
+
103
+ In this example, ``parent()`` will correctly call the ``sidebar`` block from
104
+ the ``blocks.html`` template.
105
+
106
+ .. tip::
107
+
108
+ In Twig 1.2, renaming allows you to simulate inheritance by calling the
109
+ "parent" block:
110
+
111
+ .. code-block:: jinja
112
+
113
+ {% extends "base.html" %}
114
+
115
+ {% use "blocks.html" with sidebar as parent_sidebar %}
116
+
117
+ {% block sidebar %}
118
+ {{ block('parent_sidebar') }}
119
+ {% endblock %}
120
+
121
+ .. note::
122
+
123
+ You can use as many ``use`` statements as you want in any given template.
124
+ If two imported templates define the same block, the latest one wins.
library/twig/twig/doc/tags/verbatim.rst ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ``verbatim``
2
+ ============
3
+
4
+ .. versionadded:: 1.12
5
+ The ``verbatim`` tag was added in Twig 1.12 (it was named ``raw`` before).
6
+
7
+ The ``verbatim`` tag marks sections as being raw text that should not be
8
+ parsed. For example to put Twig syntax as example into a template you can use
9
+ this snippet:
10
+
11
+ .. code-block:: jinja
12
+
13
+ {% verbatim %}
14
+ <ul>
15
+ {% for item in seq %}
16
+ <li>{{ item }}</li>
17
+ {% endfor %}
18
+ </ul>
19
+ {% endverbatim %}
20
+
21
+ .. note::
22
+
23
+ The ``verbatim`` tag works in the exact same way as the old ``raw`` tag,
24
+ but was renamed to avoid confusion with the ``raw`` filter.
library/twig/twig/doc/tags/with.rst ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ``with``
2
+ ========
3
+
4
+ .. versionadded:: 1.28
5
+ The ``with`` tag was added in Twig 1.28.
6
+
7
+ Use the ``with`` tag to create a new inner scope. Variables set within this
8
+ scope are not visible outside of the scope:
9
+
10
+ .. code-block:: jinja
11
+
12
+ {% with %}
13
+ {% set foo = 42 %}
14
+ {{ foo }} foo is 42 here
15
+ {% endwith %}
16
+ foo is not visible here any longer
17
+
18
+ Instead of defining variables at the beginning of the scope, you can pass a
19
+ hash of variables you want to define in the ``with`` tag; the previous example
20
+ is equivalent to the following one:
21
+
22
+ .. code-block:: jinja
23
+
24
+ {% with { foo: 42 } %}
25
+ {{ foo }} foo is 42 here
26
+ {% endwith %}
27
+ foo is not visible here any longer
28
+
29
+ {# it works with any expression that resolves to a hash #}
30
+ {% set vars = { foo: 42 } %}
31
+ {% with vars %}
32
+ ...
33
+ {% endwith %}
34
+
35
+ By default, the inner scope has access to the outer scope context; you can
36
+ disable this behavior by appending the ``only`` keyword:
37
+
38
+ .. code-block:: jinja
39
+
40
+ {% set bar = 'bar' %}
41
+ {% with { foo: 42 } only %}
42
+ {# only foo is defined #}
43
+ {# bar is not defined #}
44
+ {% endwith %}
library/twig/twig/doc/templates.rst ADDED
@@ -0,0 +1,908 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Twig for Template Designers
2
+ ===========================
3
+
4
+ This document describes the syntax and semantics of the template engine and
5
+ will be most useful as reference to those creating Twig templates.
6
+
7
+ Synopsis
8
+ --------
9
+
10
+ A template is simply a text file. It can generate any text-based format (HTML,
11
+ XML, CSV, LaTeX, etc.). It doesn't have a specific extension, ``.html`` or
12
+ ``.xml`` are just fine.
13
+
14
+ A template contains **variables** or **expressions**, which get replaced with
15
+ values when the template is evaluated, and **tags**, which control the logic
16
+ of the template.
17
+
18
+ Below is a minimal template that illustrates a few basics. We will cover further
19
+ details later on:
20
+
21
+ .. code-block:: html+jinja
22
+
23
+ <!DOCTYPE html>
24
+ <html>
25
+ <head>
26
+ <title>My Webpage</title>
27
+ </head>
28
+ <body>
29
+ <ul id="navigation">
30
+ {% for item in navigation %}
31
+ <li><a href="{{ item.href }}">{{ item.caption }}</a></li>
32
+ {% endfor %}
33
+ </ul>
34
+
35
+ <h1>My Webpage</h1>
36
+ {{ a_variable }}
37
+ </body>
38
+ </html>
39
+
40
+ There are two kinds of delimiters: ``{% ... %}`` and ``{{ ... }}``. The first
41
+ one is used to execute statements such as for-loops, the latter prints the
42
+ result of an expression to the template.
43
+
44
+ IDEs Integration
45
+ ----------------
46
+
47
+ Many IDEs support syntax highlighting and auto-completion for Twig:
48
+
49
+ * *Textmate* via the `Twig bundle`_
50
+ * *Vim* via the `Jinja syntax plugin`_ or the `vim-twig plugin`_
51
+ * *Netbeans* via the `Twig syntax plugin`_ (until 7.1, native as of 7.2)
52
+ * *PhpStorm* (native as of 2.1)
53
+ * *Eclipse* via the `Twig plugin`_
54
+ * *Sublime Text* via the `Twig bundle`_
55
+ * *GtkSourceView* via the `Twig language definition`_ (used by gedit and other projects)
56
+ * *Coda* and *SubEthaEdit* via the `Twig syntax mode`_
57
+ * *Coda 2* via the `other Twig syntax mode`_
58
+ * *Komodo* and *Komodo Edit* via the Twig highlight/syntax check mode
59
+ * *Notepad++* via the `Notepad++ Twig Highlighter`_
60
+ * *Emacs* via `web-mode.el`_
61
+ * *Atom* via the `PHP-twig for atom`_
62
+ * *Visual Studio Code* via the `Twig pack`_
63
+
64
+ Also, `TwigFiddle`_ is an online service that allows you to execute Twig templates
65
+ from a browser; it supports all versions of Twig.
66
+
67
+ Variables
68
+ ---------
69
+
70
+ The application passes variables to the templates for manipulation in the
71
+ template. Variables may have attributes or elements you can access,
72
+ too. The visual representation of a variable depends heavily on the application providing
73
+ it.
74
+
75
+ You can use a dot (``.``) to access attributes of a variable (methods or
76
+ properties of a PHP object, or items of a PHP array), or the so-called
77
+ "subscript" syntax (``[]``):
78
+
79
+ .. code-block:: jinja
80
+
81
+ {{ foo.bar }}
82
+ {{ foo['bar'] }}
83
+
84
+ When the attribute contains special characters (like ``-`` that would be
85
+ interpreted as the minus operator), use the ``attribute`` function instead to
86
+ access the variable attribute:
87
+
88
+ .. code-block:: jinja
89
+
90
+ {# equivalent to the non-working foo.data-foo #}
91
+ {{ attribute(foo, 'data-foo') }}
92
+
93
+ .. note::
94
+
95
+ It's important to know that the curly braces are *not* part of the
96
+ variable but the print statement. When accessing variables inside tags,
97
+ don't put the braces around them.
98
+
99
+ If a variable or attribute does not exist, you will receive a ``null`` value
100
+ when the ``strict_variables`` option is set to ``false``; alternatively, if ``strict_variables``
101
+ is set, Twig will throw an error (see :ref:`environment options<environment_options>`).
102
+
103
+ .. sidebar:: Implementation
104
+
105
+ For convenience's sake ``foo.bar`` does the following things on the PHP
106
+ layer:
107
+
108
+ * check if ``foo`` is an array and ``bar`` a valid element;
109
+ * if not, and if ``foo`` is an object, check that ``bar`` is a valid property;
110
+ * if not, and if ``foo`` is an object, check that ``bar`` is a valid method
111
+ (even if ``bar`` is the constructor - use ``__construct()`` instead);
112
+ * if not, and if ``foo`` is an object, check that ``getBar`` is a valid method;
113
+ * if not, and if ``foo`` is an object, check that ``isBar`` is a valid method;
114
+ * if not, return a ``null`` value.
115
+
116
+ ``foo['bar']`` on the other hand only works with PHP arrays:
117
+
118
+ * check if ``foo`` is an array and ``bar`` a valid element;
119
+ * if not, return a ``null`` value.
120
+
121
+ .. note::
122
+
123
+ If you want to access a dynamic attribute of a variable, use the
124
+ :doc:`attribute<functions/attribute>` function instead.
125
+
126
+ Global Variables
127
+ ~~~~~~~~~~~~~~~~
128
+
129
+ The following variables are always available in templates:
130
+
131
+ * ``_self``: references the current template;
132
+ * ``_context``: references the current context;
133
+ * ``_charset``: references the current charset.
134
+
135
+ Setting Variables
136
+ ~~~~~~~~~~~~~~~~~
137
+
138
+ You can assign values to variables inside code blocks. Assignments use the
139
+ :doc:`set<tags/set>` tag:
140
+
141
+ .. code-block:: jinja
142
+
143
+ {% set foo = 'foo' %}
144
+ {% set foo = [1, 2] %}
145
+ {% set foo = {'foo': 'bar'} %}
146
+
147
+ Filters
148
+ -------
149
+
150
+ Variables can be modified by **filters**. Filters are separated from the
151
+ variable by a pipe symbol (``|``) and may have optional arguments in
152
+ parentheses. Multiple filters can be chained. The output of one filter is
153
+ applied to the next.
154
+
155
+ The following example removes all HTML tags from the ``name`` and title-cases
156
+ it:
157
+
158
+ .. code-block:: jinja
159
+
160
+ {{ name|striptags|title }}
161
+
162
+ Filters that accept arguments have parentheses around the arguments. This
163
+ example will join a list by commas:
164
+
165
+ .. code-block:: jinja
166
+
167
+ {{ list|join(', ') }}
168
+
169
+ To apply a filter on a section of code, wrap it in the
170
+ :doc:`filter<tags/filter>` tag:
171
+
172
+ .. code-block:: jinja
173
+
174
+ {% filter upper %}
175
+ This text becomes uppercase
176
+ {% endfilter %}
177
+
178
+ Go to the :doc:`filters<filters/index>` page to learn more about built-in
179
+ filters.
180
+
181
+ Functions
182
+ ---------
183
+
184
+ Functions can be called to generate content. Functions are called by their
185
+ name followed by parentheses (``()``) and may have arguments.
186
+
187
+ For instance, the ``range`` function returns a list containing an arithmetic
188
+ progression of integers:
189
+
190
+ .. code-block:: jinja
191
+
192
+ {% for i in range(0, 3) %}
193
+ {{ i }},
194
+ {% endfor %}
195
+
196
+ Go to the :doc:`functions<functions/index>` page to learn more about the
197
+ built-in functions.
198
+
199
+ Named Arguments
200
+ ---------------
201
+
202
+ .. versionadded:: 1.12
203
+ Support for named arguments was added in Twig 1.12.
204
+
205
+ .. code-block:: jinja
206
+
207
+ {% for i in range(low=1, high=10, step=2) %}
208
+ {{ i }},
209
+ {% endfor %}
210
+
211
+ Using named arguments makes your templates more explicit about the meaning of
212
+ the values you pass as arguments:
213
+
214
+ .. code-block:: jinja
215
+
216
+ {{ data|convert_encoding('UTF-8', 'iso-2022-jp') }}
217
+
218
+ {# versus #}
219
+
220
+ {{ data|convert_encoding(from='iso-2022-jp', to='UTF-8') }}
221
+
222
+ Named arguments also allow you to skip some arguments for which you don't want
223
+ to change the default value:
224
+
225
+ .. code-block:: jinja
226
+
227
+ {# the first argument is the date format, which defaults to the global date format if null is passed #}
228
+ {{ "now"|date(null, "Europe/Paris") }}
229
+
230
+ {# or skip the format value by using a named argument for the time zone #}
231
+ {{ "now"|date(timezone="Europe/Paris") }}
232
+
233
+ You can also use both positional and named arguments in one call, in which
234
+ case positional arguments must always come before named arguments:
235
+
236
+ .. code-block:: jinja
237
+
238
+ {{ "now"|date('d/m/Y H:i', timezone="Europe/Paris") }}
239
+
240
+ .. tip::
241
+
242
+ Each function and filter documentation page has a section where the names
243
+ of all arguments are listed when supported.
244
+
245
+ Control Structure
246
+ -----------------
247
+
248
+ A control structure refers to all those things that control the flow of a
249
+ program - conditionals (i.e. ``if``/``elseif``/``else``), ``for``-loops, as
250
+ well as things like blocks. Control structures appear inside ``{% ... %}``
251
+ blocks.
252
+
253
+ For example, to display a list of users provided in a variable called
254
+ ``users``, use the :doc:`for<tags/for>` tag:
255
+
256
+ .. code-block:: jinja
257
+
258
+ <h1>Members</h1>
259
+ <ul>
260
+ {% for user in users %}
261
+ <li>{{ user.username|e }}</li>
262
+ {% endfor %}
263
+ </ul>
264
+
265
+ The :doc:`if<tags/if>` tag can be used to test an expression:
266
+
267
+ .. code-block:: jinja
268
+
269
+ {% if users|length > 0 %}
270
+ <ul>
271
+ {% for user in users %}
272
+ <li>{{ user.username|e }}</li>
273
+ {% endfor %}
274
+ </ul>
275
+ {% endif %}
276
+
277
+ Go to the :doc:`tags<tags/index>` page to learn more about the built-in tags.
278
+
279
+ Comments
280
+ --------
281
+
282
+ To comment-out part of a line in a template, use the comment syntax ``{# ...
283
+ #}``. This is useful for debugging or to add information for other template
284
+ designers or yourself:
285
+
286
+ .. code-block:: jinja
287
+
288
+ {# note: disabled template because we no longer use this
289
+ {% for user in users %}
290
+ ...
291
+ {% endfor %}
292
+ #}
293
+
294
+ Including other Templates
295
+ -------------------------
296
+
297
+ The :doc:`include<functions/include>` function is useful to include a template
298
+ and return the rendered content of that template into the current one:
299
+
300
+ .. code-block:: jinja
301
+
302
+ {{ include('sidebar.html') }}
303
+
304
+ By default, included templates have access to the same context as the template
305
+ which includes them. This means that any variable defined in the main template
306
+ will be available in the included template too:
307
+
308
+ .. code-block:: jinja
309
+
310
+ {% for box in boxes %}
311
+ {{ include('render_box.html') }}
312
+ {% endfor %}
313
+
314
+ The included template ``render_box.html`` is able to access the ``box`` variable.
315
+
316
+ The filename of the template depends on the template loader. For instance, the
317
+ ``Twig_Loader_Filesystem`` allows you to access other templates by giving the
318
+ filename. You can access templates in subdirectories with a slash:
319
+
320
+ .. code-block:: jinja
321
+
322
+ {{ include('sections/articles/sidebar.html') }}
323
+
324
+ This behavior depends on the application embedding Twig.
325
+
326
+ Template Inheritance
327
+ --------------------
328
+
329
+ The most powerful part of Twig is template inheritance. Template inheritance
330
+ allows you to build a base "skeleton" template that contains all the common
331
+ elements of your site and defines **blocks** that child templates can
332
+ override.
333
+
334
+ Sounds complicated but it is very basic. It's easier to understand it by
335
+ starting with an example.
336
+
337
+ Let's define a base template, ``base.html``, which defines a simple HTML
338
+ skeleton document that you might use for a simple two-column page:
339
+
340
+ .. code-block:: html+jinja
341
+
342
+ <!DOCTYPE html>
343
+ <html>
344
+ <head>
345
+ {% block head %}
346
+ <link rel="stylesheet" href="style.css" />
347
+ <title>{% block title %}{% endblock %} - My Webpage</title>
348
+ {% endblock %}
349
+ </head>
350
+ <body>
351
+ <div id="content">{% block content %}{% endblock %}</div>
352
+ <div id="footer">
353
+ {% block footer %}
354
+ &copy; Copyright 2011 by <a href="http://domain.invalid/">you</a>.
355
+ {% endblock %}
356
+ </div>
357
+ </body>
358
+ </html>
359
+
360
+ In this example, the :doc:`block<tags/block>` tags define four blocks that
361
+ child templates can fill in. All the ``block`` tag does is to tell the
362
+ template engine that a child template may override those portions of the
363
+ template.
364
+
365
+ A child template might look like this:
366
+
367
+ .. code-block:: jinja
368
+
369
+ {% extends "base.html" %}
370
+
371
+ {% block title %}Index{% endblock %}
372
+ {% block head %}
373
+ {{ parent() }}
374
+ <style type="text/css">
375
+ .important { color: #336699; }
376
+ </style>
377
+ {% endblock %}
378
+ {% block content %}
379
+ <h1>Index</h1>
380
+ <p class="important">
381
+ Welcome to my awesome homepage.
382
+ </p>
383
+ {% endblock %}
384
+
385
+ The :doc:`extends<tags/extends>` tag is the key here. It tells the template
386
+ engine that this template "extends" another template. When the template system
387
+ evaluates this template, first it locates the parent. The extends tag should
388
+ be the first tag in the template.
389
+
390
+ Note that since the child template doesn't define the ``footer`` block, the
391
+ value from the parent template is used instead.
392
+
393
+ It's possible to render the contents of the parent block by using the
394
+ :doc:`parent<functions/parent>` function. This gives back the results of the
395
+ parent block:
396
+
397
+ .. code-block:: jinja
398
+
399
+ {% block sidebar %}
400
+ <h3>Table Of Contents</h3>
401
+ ...
402
+ {{ parent() }}
403
+ {% endblock %}
404
+
405
+ .. tip::
406
+
407
+ The documentation page for the :doc:`extends<tags/extends>` tag describes
408
+ more advanced features like block nesting, scope, dynamic inheritance, and
409
+ conditional inheritance.
410
+
411
+ .. note::
412
+
413
+ Twig also supports multiple inheritance with the so called horizontal reuse
414
+ with the help of the :doc:`use<tags/use>` tag. This is an advanced feature
415
+ hardly ever needed in regular templates.
416
+
417
+ HTML Escaping
418
+ -------------
419
+
420
+ When generating HTML from templates, there's always a risk that a variable
421
+ will include characters that affect the resulting HTML. There are two
422
+ approaches: manually escaping each variable or automatically escaping
423
+ everything by default.
424
+
425
+ Twig supports both, automatic escaping is enabled by default.
426
+
427
+ The automatic escaping strategy can be configured via the
428
+ :ref:`autoescape<environment_options>` option and defaults to ``html``.
429
+
430
+ Working with Manual Escaping
431
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
432
+
433
+ If manual escaping is enabled, it is **your** responsibility to escape
434
+ variables if needed. What to escape? Any variable you don't trust.
435
+
436
+ Escaping works by piping the variable through the
437
+ :doc:`escape<filters/escape>` or ``e`` filter:
438
+
439
+ .. code-block:: jinja
440
+
441
+ {{ user.username|e }}
442
+
443
+ By default, the ``escape`` filter uses the ``html`` strategy, but depending on
444
+ the escaping context, you might want to explicitly use any other available
445
+ strategies:
446
+
447
+ .. code-block:: jinja
448
+
449
+ {{ user.username|e('js') }}
450
+ {{ user.username|e('css') }}
451
+ {{ user.username|e('url') }}
452
+ {{ user.username|e('html_attr') }}
453
+
454
+ Working with Automatic Escaping
455
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
456
+
457
+ Whether automatic escaping is enabled or not, you can mark a section of a
458
+ template to be escaped or not by using the :doc:`autoescape<tags/autoescape>`
459
+ tag:
460
+
461
+ .. code-block:: jinja
462
+
463
+ {% autoescape %}
464
+ Everything will be automatically escaped in this block (using the HTML strategy)
465
+ {% endautoescape %}
466
+
467
+ By default, auto-escaping uses the ``html`` escaping strategy. If you output
468
+ variables in other contexts, you need to explicitly escape them with the
469
+ appropriate escaping strategy:
470
+
471
+ .. code-block:: jinja
472
+
473
+ {% autoescape 'js' %}
474
+ Everything will be automatically escaped in this block (using the JS strategy)
475
+ {% endautoescape %}
476
+
477
+ Escaping
478
+ --------
479
+
480
+ It is sometimes desirable or even necessary to have Twig ignore parts it would
481
+ otherwise handle as variables or blocks. For example if the default syntax is
482
+ used and you want to use ``{{`` as raw string in the template and not start a
483
+ variable you have to use a trick.
484
+
485
+ The easiest way is to output the variable delimiter (``{{``) by using a variable
486
+ expression:
487
+
488
+ .. code-block:: jinja
489
+
490
+ {{ '{{' }}
491
+
492
+ For bigger sections it makes sense to mark a block
493
+ :doc:`verbatim<tags/verbatim>`.
494
+
495
+ Macros
496
+ ------
497
+
498
+ .. versionadded:: 1.12
499
+ Support for default argument values was added in Twig 1.12.
500
+
501
+ Macros are comparable with functions in regular programming languages. They
502
+ are useful to reuse often used HTML fragments to not repeat yourself.
503
+
504
+ A macro is defined via the :doc:`macro<tags/macro>` tag. Here is a small example
505
+ (subsequently called ``forms.html``) of a macro that renders a form element:
506
+
507
+ .. code-block:: jinja
508
+
509
+ {% macro input(name, value, type, size) %}
510
+ <input type="{{ type|default('text') }}" name="{{ name }}" value="{{ value|e }}" size="{{ size|default(20) }}" />
511
+ {% endmacro %}
512
+
513
+ Macros can be defined in any template, and need to be "imported" via the
514
+ :doc:`import<tags/import>` tag before being used:
515
+
516
+ .. code-block:: jinja
517
+
518
+ {% import "forms.html" as forms %}
519
+
520
+ <p>{{ forms.input('username') }}</p>
521
+
522
+ Alternatively, you can import individual macro names from a template into the
523
+ current namespace via the :doc:`from<tags/from>` tag and optionally alias them:
524
+
525
+ .. code-block:: jinja
526
+
527
+ {% from 'forms.html' import input as input_field %}
528
+
529
+ <dl>
530
+ <dt>Username</dt>
531
+ <dd>{{ input_field('username') }}</dd>
532
+ <dt>Password</dt>
533
+ <dd>{{ input_field('password', '', 'password') }}</dd>
534
+ </dl>
535
+
536
+ A default value can also be defined for macro arguments when not provided in a
537
+ macro call:
538
+
539
+ .. code-block:: jinja
540
+
541
+ {% macro input(name, value = "", type = "text", size = 20) %}
542
+ <input type="{{ type }}" name="{{ name }}" value="{{ value|e }}" size="{{ size }}" />
543
+ {% endmacro %}
544
+
545
+ If extra positional arguments are passed to a macro call, they end up in the
546
+ special ``varargs`` variable as a list of values.
547
+
548
+ .. _twig-expressions:
549
+
550
+ Expressions
551
+ -----------
552
+
553
+ Twig allows expressions everywhere. These work very similar to regular PHP and
554
+ even if you're not working with PHP you should feel comfortable with it.
555
+
556
+ .. note::
557
+
558
+ The operator precedence is as follows, with the lowest-precedence
559
+ operators listed first: ``b-and``, ``b-xor``, ``b-or``, ``or``, ``and``,
560
+ ``==``, ``!=``, ``<``, ``>``, ``>=``, ``<=``, ``in``, ``matches``,
561
+ ``starts with``, ``ends with``, ``..``, ``+``, ``-``, ``~``, ``*``, ``/``,
562
+ ``//``, ``%``, ``is``, ``**``, ``|``, ``[]``, and ``.``:
563
+
564
+ .. code-block:: jinja
565
+
566
+ {% set greeting = 'Hello ' %}
567
+ {% set name = 'Fabien' %}
568
+
569
+ {{ greeting ~ name|lower }} {# Hello fabien #}
570
+
571
+ {# use parenthesis to change precedence #}
572
+ {{ (greeting ~ name)|lower }} {# hello fabien #}
573
+
574
+ Literals
575
+ ~~~~~~~~
576
+
577
+ .. versionadded:: 1.5
578
+ Support for hash keys as names and expressions was added in Twig 1.5.
579
+
580
+ The simplest form of expressions are literals. Literals are representations
581
+ for PHP types such as strings, numbers, and arrays. The following literals
582
+ exist:
583
+
584
+ * ``"Hello World"``: Everything between two double or single quotes is a
585
+ string. They are useful whenever you need a string in the template (for
586
+ example as arguments to function calls, filters or just to extend or include
587
+ a template). A string can contain a delimiter if it is preceded by a
588
+ backslash (``\``) -- like in ``'It\'s good'``. If the string contains a
589
+ backslash (e.g. ``'c:\Program Files'``) escape it by doubling it
590
+ (e.g. ``'c:\\Program Files'``).
591
+
592
+ * ``42`` / ``42.23``: Integers and floating point numbers are created by just
593
+ writing the number down. If a dot is present the number is a float,
594
+ otherwise an integer.
595
+
596
+ * ``["foo", "bar"]``: Arrays are defined by a sequence of expressions
597
+ separated by a comma (``,``) and wrapped with squared brackets (``[]``).
598
+
599
+ * ``{"foo": "bar"}``: Hashes are defined by a list of keys and values
600
+ separated by a comma (``,``) and wrapped with curly braces (``{}``):
601
+
602
+ .. code-block:: jinja
603
+
604
+ {# keys as string #}
605
+ { 'foo': 'foo', 'bar': 'bar' }
606
+
607
+ {# keys as names (equivalent to the previous hash) -- as of Twig 1.5 #}
608
+ { foo: 'foo', bar: 'bar' }
609
+
610
+ {# keys as integer #}
611
+ { 2: 'foo', 4: 'bar' }
612
+
613
+ {# keys as expressions (the expression must be enclosed into parentheses) -- as of Twig 1.5 #}
614
+ { (1 + 1): 'foo', (a ~ 'b'): 'bar' }
615
+
616
+ * ``true`` / ``false``: ``true`` represents the true value, ``false``
617
+ represents the false value.
618
+
619
+ * ``null``: ``null`` represents no specific value. This is the value returned
620
+ when a variable does not exist. ``none`` is an alias for ``null``.
621
+
622
+ Arrays and hashes can be nested:
623
+
624
+ .. code-block:: jinja
625
+
626
+ {% set foo = [1, {"foo": "bar"}] %}
627
+
628
+ .. tip::
629
+
630
+ Using double-quoted or single-quoted strings has no impact on performance
631
+ but string interpolation is only supported in double-quoted strings.
632
+
633
+ Math
634
+ ~~~~
635
+
636
+ Twig allows you to calculate with values. This is rarely useful in templates
637
+ but exists for completeness' sake. The following operators are supported:
638
+
639
+ * ``+``: Adds two objects together (the operands are casted to numbers). ``{{
640
+ 1 + 1 }}`` is ``2``.
641
+
642
+ * ``-``: Subtracts the second number from the first one. ``{{ 3 - 2 }}`` is
643
+ ``1``.
644
+
645
+ * ``/``: Divides two numbers. The returned value will be a floating point
646
+ number. ``{{ 1 / 2 }}`` is ``{{ 0.5 }}``.
647
+
648
+ * ``%``: Calculates the remainder of an integer division. ``{{ 11 % 7 }}`` is
649
+ ``4``.
650
+
651
+ * ``//``: Divides two numbers and returns the floored integer result. ``{{ 20
652
+ // 7 }}`` is ``2``, ``{{ -20 // 7 }}`` is ``-3`` (this is just syntactic
653
+ sugar for the :doc:`round<filters/round>` filter).
654
+
655
+ * ``*``: Multiplies the left operand with the right one. ``{{ 2 * 2 }}`` would
656
+ return ``4``.
657
+
658
+ * ``**``: Raises the left operand to the power of the right operand. ``{{ 2 **
659
+ 3 }}`` would return ``8``.
660
+
661
+ Logic
662
+ ~~~~~
663
+
664
+ You can combine multiple expressions with the following operators:
665
+
666
+ * ``and``: Returns true if the left and the right operands are both true.
667
+
668
+ * ``or``: Returns true if the left or the right operand is true.
669
+
670
+ * ``not``: Negates a statement.
671
+
672
+ * ``(expr)``: Groups an expression.
673
+
674
+ .. note::
675
+
676
+ Twig also support bitwise operators (``b-and``, ``b-xor``, and ``b-or``).
677
+
678
+ .. note::
679
+
680
+ Operators are case sensitive.
681
+
682
+ Comparisons
683
+ ~~~~~~~~~~~
684
+
685
+ The following comparison operators are supported in any expression: ``==``,
686
+ ``!=``, ``<``, ``>``, ``>=``, and ``<=``.
687
+
688
+ You can also check if a string ``starts with`` or ``ends with`` another
689
+ string:
690
+
691
+ .. code-block:: jinja
692
+
693
+ {% if 'Fabien' starts with 'F' %}
694
+ {% endif %}
695
+
696
+ {% if 'Fabien' ends with 'n' %}
697
+ {% endif %}
698
+
699
+ .. note::
700
+
701
+ For complex string comparisons, the ``matches`` operator allows you to use
702
+ `regular expressions`_:
703
+
704
+ .. code-block:: jinja
705
+
706
+ {% if phone matches '/^[\\d\\.]+$/' %}
707
+ {% endif %}
708
+
709
+ Containment Operator
710
+ ~~~~~~~~~~~~~~~~~~~~
711
+
712
+ The ``in`` operator performs containment test.
713
+
714
+ It returns ``true`` if the left operand is contained in the right:
715
+
716
+ .. code-block:: jinja
717
+
718
+ {# returns true #}
719
+
720
+ {{ 1 in [1, 2, 3] }}
721
+
722
+ {{ 'cd' in 'abcde' }}
723
+
724
+ .. tip::
725
+
726
+ You can use this filter to perform a containment test on strings, arrays,
727
+ or objects implementing the ``Traversable`` interface.
728
+
729
+ To perform a negative test, use the ``not in`` operator:
730
+
731
+ .. code-block:: jinja
732
+
733
+ {% if 1 not in [1, 2, 3] %}
734
+
735
+ {# is equivalent to #}
736
+ {% if not (1 in [1, 2, 3]) %}
737
+
738
+ Test Operator
739
+ ~~~~~~~~~~~~~
740
+
741
+ The ``is`` operator performs tests. Tests can be used to test a variable against
742
+ a common expression. The right operand is name of the test:
743
+
744
+ .. code-block:: jinja
745
+
746
+ {# find out if a variable is odd #}
747
+
748
+ {{ name is odd }}
749
+
750
+ Tests can accept arguments too:
751
+
752
+ .. code-block:: jinja
753
+
754
+ {% if post.status is constant('Post::PUBLISHED') %}
755
+
756
+ Tests can be negated by using the ``is not`` operator:
757
+
758
+ .. code-block:: jinja
759
+
760
+ {% if post.status is not constant('Post::PUBLISHED') %}
761
+
762
+ {# is equivalent to #}
763
+ {% if not (post.status is constant('Post::PUBLISHED')) %}
764
+
765
+ Go to the :doc:`tests<tests/index>` page to learn more about the built-in
766
+ tests.
767
+
768
+ Other Operators
769
+ ~~~~~~~~~~~~~~~
770
+
771
+ .. versionadded:: 1.12.0
772
+ Support for the extended ternary operator was added in Twig 1.12.0.
773
+
774
+ The following operators don't fit into any of the other categories:
775
+
776
+ * ``|``: Applies a filter.
777
+
778
+ * ``..``: Creates a sequence based on the operand before and after the operator
779
+ (this is just syntactic sugar for the :doc:`range<functions/range>` function):
780
+
781
+ .. code-block:: jinja
782
+
783
+ {{ 1..5 }}
784
+
785
+ {# equivalent to #}
786
+ {{ range(1, 5) }}
787
+
788
+ Note that you must use parentheses when combining it with the filter operator
789
+ due to the :ref:`operator precedence rules <twig-expressions>`:
790
+
791
+ .. code-block:: jinja
792
+
793
+ (1..5)|join(', ')
794
+
795
+ * ``~``: Converts all operands into strings and concatenates them. ``{{ "Hello
796
+ " ~ name ~ "!" }}`` would return (assuming ``name`` is ``'John'``) ``Hello
797
+ John!``.
798
+
799
+ * ``.``, ``[]``: Gets an attribute of an object.
800
+
801
+ * ``?:``: The ternary operator:
802
+
803
+ .. code-block:: jinja
804
+
805
+ {{ foo ? 'yes' : 'no' }}
806
+
807
+ {# as of Twig 1.12.0 #}
808
+ {{ foo ?: 'no' }} is the same as {{ foo ? foo : 'no' }}
809
+ {{ foo ? 'yes' }} is the same as {{ foo ? 'yes' : '' }}
810
+
811
+ * ``??``: The null-coalescing operator:
812
+
813
+ .. code-block:: jinja
814
+
815
+ {# returns the value of foo if it is defined and not null, 'no' otherwise #}
816
+ {{ foo ?? 'no' }}
817
+
818
+ String Interpolation
819
+ ~~~~~~~~~~~~~~~~~~~~
820
+
821
+ .. versionadded:: 1.5
822
+ String interpolation was added in Twig 1.5.
823
+
824
+ String interpolation (``#{expression}``) allows any valid expression to appear
825
+ within a *double-quoted string*. The result of evaluating that expression is
826
+ inserted into the string:
827
+
828
+ .. code-block:: jinja
829
+
830
+ {{ "foo #{bar} baz" }}
831
+ {{ "foo #{1 + 2} baz" }}
832
+
833
+ .. _templates-whitespace-control:
834
+
835
+ Whitespace Control
836
+ ------------------
837
+
838
+ .. versionadded:: 1.1
839
+ Tag level whitespace control was added in Twig 1.1.
840
+
841
+ The first newline after a template tag is removed automatically (like in PHP.)
842
+ Whitespace is not further modified by the template engine, so each whitespace
843
+ (spaces, tabs, newlines etc.) is returned unchanged.
844
+
845
+ Use the ``spaceless`` tag to remove whitespace *between HTML tags*:
846
+
847
+ .. code-block:: jinja
848
+
849
+ {% spaceless %}
850
+ <div>
851
+ <strong>foo bar</strong>
852
+ </div>
853
+ {% endspaceless %}
854
+
855
+ {# output will be <div><strong>foo bar</strong></div> #}
856
+
857
+ In addition to the spaceless tag you can also control whitespace on a per tag
858
+ level. By using the whitespace control modifier on your tags, you can trim
859
+ leading and or trailing whitespace:
860
+
861
+ .. code-block:: jinja
862
+
863
+ {% set value = 'no spaces' %}
864
+ {#- No leading/trailing whitespace -#}
865
+ {%- if true -%}
866
+ {{- value -}}
867
+ {%- endif -%}
868
+
869
+ {# output 'no spaces' #}
870
+
871
+ The above sample shows the default whitespace control modifier, and how you can
872
+ use it to remove whitespace around tags. Trimming space will consume all whitespace
873
+ for that side of the tag. It is possible to use whitespace trimming on one side
874
+ of a tag:
875
+
876
+ .. code-block:: jinja
877
+
878
+ {% set value = 'no spaces' %}
879
+ <li> {{- value }} </li>
880
+
881
+ {# outputs '<li>no spaces </li>' #}
882
+
883
+ Extensions
884
+ ----------
885
+
886
+ Twig can be easily extended.
887
+
888
+ If you are looking for new tags, filters, or functions, have a look at the Twig official
889
+ `extension repository`_.
890
+
891
+ If you want to create your own, read the :ref:`Creating an
892
+ Extension<creating_extensions>` chapter.
893
+
894
+ .. _`Twig bundle`: https://github.com/Anomareh/PHP-Twig.tmbundle
895
+ .. _`Jinja syntax plugin`: http://jinja.pocoo.org/docs/integration/#vim
896
+ .. _`vim-twig plugin`: https://github.com/evidens/vim-twig
897
+ .. _`Twig syntax plugin`: http://plugins.netbeans.org/plugin/37069/php-twig
898
+ .. _`Twig plugin`: https://github.com/pulse00/Twig-Eclipse-Plugin
899
+ .. _`Twig language definition`: https://github.com/gabrielcorpse/gedit-twig-template-language
900
+ .. _`extension repository`: http://github.com/twigphp/Twig-extensions
901
+ .. _`Twig syntax mode`: https://github.com/bobthecow/Twig-HTML.mode
902
+ .. _`other Twig syntax mode`: https://github.com/muxx/Twig-HTML.mode
903
+ .. _`Notepad++ Twig Highlighter`: https://github.com/Banane9/notepadplusplus-twig
904
+ .. _`web-mode.el`: http://web-mode.org/
905
+ .. _`regular expressions`: http://php.net/manual/en/pcre.pattern.php
906
+ .. _`PHP-twig for atom`: https://github.com/reesef/php-twig
907
+ .. _`TwigFiddle`: http://twigfiddle.com/
908
+ .. _`Twig pack`: https://marketplace.visualstudio.com/items?itemName=bajdzis.vscode-twig-pack
library/twig/twig/doc/tests/constant.rst ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ``constant``
2
+ ============
3
+
4
+ .. versionadded: 1.13.1
5
+ constant now accepts object instances as the second argument.
6
+
7
+ ``constant`` checks if a variable has the exact same value as a constant. You
8
+ can use either global constants or class constants:
9
+
10
+ .. code-block:: jinja
11
+
12
+ {% if post.status is constant('Post::PUBLISHED') %}
13
+ the status attribute is exactly the same as Post::PUBLISHED
14
+ {% endif %}
15
+
16
+ You can test constants from object instances as well:
17
+
18
+ .. code-block:: jinja
19
+
20
+ {% if post.status is constant('PUBLISHED', post) %}
21
+ the status attribute is exactly the same as Post::PUBLISHED
22
+ {% endif %}
library/twig/twig/doc/tests/defined.rst ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ``defined``
2
+ ===========
3
+
4
+ ``defined`` checks if a variable is defined in the current context. This is very
5
+ useful if you use the ``strict_variables`` option:
6
+
7
+ .. code-block:: jinja
8
+
9
+ {# defined works with variable names #}
10
+ {% if foo is defined %}
11
+ ...
12
+ {% endif %}
13
+
14
+ {# and attributes on variables names #}
15
+ {% if foo.bar is defined %}
16
+ ...
17
+ {% endif %}
18
+
19
+ {% if foo['bar'] is defined %}
20
+ ...
21
+ {% endif %}
22
+
23
+ When using the ``defined`` test on an expression that uses variables in some
24
+ method calls, be sure that they are all defined first:
25
+
26
+ .. code-block:: jinja
27
+
28
+ {% if var is defined and foo.method(var) is defined %}
29
+ ...
30
+ {% endif %}
library/twig/twig/doc/tests/divisibleby.rst ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ``divisible by``
2
+ ================
3
+
4
+ .. versionadded:: 1.14.2
5
+ The ``divisible by`` test was added in Twig 1.14.2 as an alias for
6
+ ``divisibleby``.
7
+
8
+ ``divisible by`` checks if a variable is divisible by a number:
9
+
10
+ .. code-block:: jinja
11
+
12
+ {% if loop.index is divisible by(3) %}
13
+ ...
14
+ {% endif %}
library/twig/twig/doc/tests/empty.rst ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ ``empty``
2
+ =========
3
+
4
+ ``empty`` checks if a variable is an empty string, an empty array, an empty
5
+ hash, exactly ``false``, or exactly ``null``:
6
+
7
+ .. code-block:: jinja
8
+
9
+ {% if foo is empty %}
10
+ ...
11
+ {% endif %}
library/twig/twig/doc/tests/even.rst ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ ``even``
2
+ ========
3
+
4
+ ``even`` returns ``true`` if the given number is even:
5
+
6
+ .. code-block:: jinja
7
+
8
+ {{ var is even }}
9
+
10
+ .. seealso:: :doc:`odd<../tests/odd>`
library/twig/twig/doc/tests/index.rst ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Tests
2
+ =====
3
+
4
+ .. toctree::
5
+ :maxdepth: 1
6
+
7
+ constant
8
+ defined
9
+ divisibleby
10
+ empty
11
+ even
12
+ iterable
13
+ null
14
+ odd
15
+ sameas
library/twig/twig/doc/tests/iterable.rst ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ``iterable``
2
+ ============
3
+
4
+ .. versionadded:: 1.7
5
+ The iterable test was added in Twig 1.7.
6
+
7
+ ``iterable`` checks if a variable is an array or a traversable object:
8
+
9
+ .. code-block:: jinja
10
+
11
+ {# evaluates to true if the foo variable is iterable #}
12
+ {% if users is iterable %}
13
+ {% for user in users %}
14
+ Hello {{ user }}!
15
+ {% endfor %}
16
+ {% else %}
17
+ {# users is probably a string #}
18
+ Hello {{ users }}!
19
+ {% endif %}
library/twig/twig/doc/tests/null.rst ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ``null``
2
+ ========
3
+
4
+ ``null`` returns ``true`` if the variable is ``null``:
5
+
6
+ .. code-block:: jinja
7
+
8
+ {{ var is null }}
9
+
10
+ .. note::
11
+
12
+ ``none`` is an alias for ``null``.
library/twig/twig/doc/tests/odd.rst ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ ``odd``
2
+ =======
3
+
4
+ ``odd`` returns ``true`` if the given number is odd:
5
+
6
+ .. code-block:: jinja
7
+
8
+ {{ var is odd }}
9
+
10
+ .. seealso:: :doc:`even<../tests/even>`
library/twig/twig/doc/tests/sameas.rst ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ``same as``
2
+ ===========
3
+
4
+ .. versionadded:: 1.14.2
5
+ The ``same as`` test was added in Twig 1.14.2 as an alias for ``sameas``.
6
+
7
+ ``same as`` checks if a variable is the same as another variable.
8
+ This is the equivalent to ``===`` in PHP:
9
+
10
+ .. code-block:: jinja
11
+
12
+ {% if foo.attribute is same as(false) %}
13
+ the foo attribute really is the 'false' PHP value
14
+ {% endif %}
library/twig/twig/ext/twig/.gitignore ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ *.sw*
2
+ .deps
3
+ Makefile
4
+ Makefile.fragments
5
+ Makefile.global
6
+ Makefile.objects
7
+ acinclude.m4
8
+ aclocal.m4
9
+ build/
10
+ config.cache
11
+ config.guess
12
+ config.h
13
+ config.h.in
14
+ config.log
15
+ config.nice
16
+ config.status
17
+ config.sub
18
+ configure
19
+ configure.in
20
+ install-sh
21
+ libtool
22
+ ltmain.sh
23
+ missing
24
+ mkinstalldirs
25
+ run-tests.php
26
+ twig.loT
27
+ .libs/
28
+ modules/
29
+ twig.la
30
+ twig.lo
library/twig/twig/ext/twig/config.m4 ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
1
+ dnl config.m4 for extension twig
2
+
3
+ PHP_ARG_ENABLE(twig, whether to enable twig support,
4
+ [ --enable-twig Enable twig support])
5
+
6
+ if test "$PHP_TWIG" != "no"; then
7
+ PHP_NEW_EXTENSION(twig, twig.c, $ext_shared)
8
+ fi
library/twig/twig/ext/twig/config.w32 ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
1
+ // vim:ft=javascript
2
+
3
+ ARG_ENABLE("twig", "Twig support", "no");
4
+
5
+ if (PHP_TWIG != "no") {
6
+ AC_DEFINE('HAVE_TWIG', 1);
7
+ EXTENSION('twig', 'twig.c');
8
+ }
library/twig/twig/ext/twig/php_twig.h ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ +----------------------------------------------------------------------+
3
+ | Twig Extension |
4
+ +----------------------------------------------------------------------+
5
+ | Copyright (c) 2011 Derick Rethans |
6
+ +----------------------------------------------------------------------+
7
+ | Redistribution and use in source and binary forms, with or without |
8
+ | modification, are permitted provided that the conditions mentioned |
9
+ | in the accompanying LICENSE file are met (BSD-3-Clause). |
10
+ +----------------------------------------------------------------------+
11
+ | Author: Derick Rethans <derick@derickrethans.nl> |
12
+ +----------------------------------------------------------------------+
13
+ */
14
+
15
+ #ifndef PHP_TWIG_H
16
+ #define PHP_TWIG_H
17
+
18
+ #define PHP_TWIG_VERSION "1.31.0"
19
+
20
+ #include "php.h"
21
+
22
+ extern zend_module_entry twig_module_entry;
23
+ #define phpext_twig_ptr &twig_module_entry
24
+ #ifndef PHP_WIN32
25
+ zend_module_entry *get_module(void);
26
+ #endif
27
+
28
+ #ifdef ZTS
29
+ #include "TSRM.h"
30
+ #endif
31
+
32
+ PHP_FUNCTION(twig_template_get_attributes);
33
+ PHP_RSHUTDOWN_FUNCTION(twig);
34
+
35
+ #endif
library/twig/twig/ext/twig/twig.c ADDED
@@ -0,0 +1,1215 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ +----------------------------------------------------------------------+
3
+ | Twig Extension |
4
+ +----------------------------------------------------------------------+
5
+ | Copyright (c) 2011 Derick Rethans |
6
+ +----------------------------------------------------------------------+
7
+ | Redistribution and use in source and binary forms, with or without |
8
+ | modification, are permitted provided that the conditions mentioned |
9
+ | in the accompanying LICENSE file are met (BSD-3-Clause). |
10
+ +----------------------------------------------------------------------+
11
+ | Author: Derick Rethans <derick@derickrethans.nl> |
12
+ +----------------------------------------------------------------------+
13
+ */
14
+
15
+ #ifdef HAVE_CONFIG_H
16
+ #include "config.h"
17
+ #endif
18
+
19
+ #include "php.h"
20
+ #include "php_twig.h"
21
+ #include "ext/standard/php_var.h"
22
+ #include "ext/standard/php_string.h"
23
+ #include "ext/standard/php_smart_str.h"
24
+ #include "ext/spl/spl_exceptions.h"
25
+
26
+ #include "Zend/zend_object_handlers.h"
27
+ #include "Zend/zend_interfaces.h"
28
+ #include "Zend/zend_exceptions.h"
29
+
30
+ #ifndef Z_ADDREF_P
31
+ #define Z_ADDREF_P(pz) (pz)->refcount++
32
+ #endif
33
+
34
+ #ifndef E_USER_DEPRECATED
35
+ #define E_USER_DEPRECATED (1<<14L)
36
+ #endif
37
+
38
+ #define FREE_DTOR(z) \
39
+ zval_dtor(z); \
40
+ efree(z);
41
+
42
+ #if PHP_VERSION_ID >= 50300
43
+ #define APPLY_TSRMLS_DC TSRMLS_DC
44
+ #define APPLY_TSRMLS_CC TSRMLS_CC
45
+ #define APPLY_TSRMLS_FETCH()
46
+ #else
47
+ #define APPLY_TSRMLS_DC
48
+ #define APPLY_TSRMLS_CC
49
+ #define APPLY_TSRMLS_FETCH() TSRMLS_FETCH()
50
+ #endif
51
+
52
+ ZEND_BEGIN_ARG_INFO_EX(twig_template_get_attribute_args, ZEND_SEND_BY_VAL, ZEND_RETURN_VALUE, 6)
53
+ ZEND_ARG_INFO(0, template)
54
+ ZEND_ARG_INFO(0, object)
55
+ ZEND_ARG_INFO(0, item)
56
+ ZEND_ARG_INFO(0, arguments)
57
+ ZEND_ARG_INFO(0, type)
58
+ ZEND_ARG_INFO(0, isDefinedTest)
59
+ ZEND_END_ARG_INFO()
60
+
61
+ #ifndef PHP_FE_END
62
+ #define PHP_FE_END { NULL, NULL, NULL}
63
+ #endif
64
+
65
+ static const zend_function_entry twig_functions[] = {
66
+ PHP_FE(twig_template_get_attributes, twig_template_get_attribute_args)
67
+ PHP_FE_END
68
+ };
69
+
70
+ PHP_RSHUTDOWN_FUNCTION(twig)
71
+ {
72
+ #if ZEND_DEBUG
73
+ CG(unclean_shutdown) = 0; /* get rid of PHPUnit's exit() and report memleaks */
74
+ #endif
75
+ return SUCCESS;
76
+ }
77
+
78
+ zend_module_entry twig_module_entry = {
79
+ STANDARD_MODULE_HEADER,
80
+ "twig",
81
+ twig_functions,
82
+ NULL,
83
+ NULL,
84
+ NULL,
85
+ PHP_RSHUTDOWN(twig),
86
+ NULL,
87
+ PHP_TWIG_VERSION,
88
+ STANDARD_MODULE_PROPERTIES
89
+ };
90
+
91
+
92
+ #ifdef COMPILE_DL_TWIG
93
+ ZEND_GET_MODULE(twig)
94
+ #endif
95
+
96
+ static int TWIG_ARRAY_KEY_EXISTS(zval *array, zval *key)
97
+ {
98
+ if (Z_TYPE_P(array) != IS_ARRAY) {
99
+ return 0;
100
+ }
101
+
102
+ switch (Z_TYPE_P(key)) {
103
+ case IS_NULL:
104
+ return zend_hash_exists(Z_ARRVAL_P(array), "", 1);
105
+
106
+ case IS_BOOL:
107
+ case IS_DOUBLE:
108
+ convert_to_long(key);
109
+ case IS_LONG:
110
+ return zend_hash_index_exists(Z_ARRVAL_P(array), Z_LVAL_P(key));
111
+
112
+ default:
113
+ convert_to_string(key);
114
+ return zend_symtable_exists(Z_ARRVAL_P(array), Z_STRVAL_P(key), Z_STRLEN_P(key) + 1);
115
+ }
116
+ }
117
+
118
+ static int TWIG_INSTANCE_OF(zval *object, zend_class_entry *interface TSRMLS_DC)
119
+ {
120
+ if (Z_TYPE_P(object) != IS_OBJECT) {
121
+ return 0;
122
+ }
123
+ return instanceof_function(Z_OBJCE_P(object), interface TSRMLS_CC);
124
+ }
125
+
126
+ static int TWIG_INSTANCE_OF_USERLAND(zval *object, char *interface TSRMLS_DC)
127
+ {
128
+ zend_class_entry **pce;
129
+ if (Z_TYPE_P(object) != IS_OBJECT) {
130
+ return 0;
131
+ }
132
+ if (zend_lookup_class(interface, strlen(interface), &pce TSRMLS_CC) == FAILURE) {
133
+ return 0;
134
+ }
135
+ return instanceof_function(Z_OBJCE_P(object), *pce TSRMLS_CC);
136
+ }
137
+
138
+ static zval *TWIG_GET_ARRAYOBJECT_ELEMENT(zval *object, zval *offset TSRMLS_DC)
139
+ {
140
+ zend_class_entry *ce = Z_OBJCE_P(object);
141
+ zval *retval;
142
+
143
+ if (Z_TYPE_P(object) == IS_OBJECT) {
144
+ SEPARATE_ARG_IF_REF(offset);
145
+ zend_call_method_with_1_params(&object, ce, NULL, "offsetget", &retval, offset);
146
+
147
+ zval_ptr_dtor(&offset);
148
+
149
+ if (!retval) {
150
+ if (!EG(exception)) {
151
+ zend_error(E_ERROR, "Undefined offset for object of type %s used as array.", ce->name);
152
+ }
153
+ return NULL;
154
+ }
155
+
156
+ return retval;
157
+ }
158
+ return NULL;
159
+ }
160
+
161
+ static int TWIG_ISSET_ARRAYOBJECT_ELEMENT(zval *object, zval *offset TSRMLS_DC)
162
+ {
163
+ zend_class_entry *ce = Z_OBJCE_P(object);
164
+ zval *retval;
165
+
166
+ if (Z_TYPE_P(object) == IS_OBJECT) {
167
+ SEPARATE_ARG_IF_REF(offset);
168
+ zend_call_method_with_1_params(&object, ce, NULL, "offsetexists", &retval, offset);
169
+
170
+ zval_ptr_dtor(&offset);
171
+
172
+ if (!retval) {
173
+ if (!EG(exception)) {
174
+ zend_error(E_ERROR, "Undefined offset for object of type %s used as array.", ce->name);
175
+ }
176
+ return 0;
177
+ }
178
+
179
+ return (retval && Z_TYPE_P(retval) == IS_BOOL && Z_LVAL_P(retval));
180
+ }
181
+ return 0;
182
+ }
183
+
184
+ static char *TWIG_STRTOLOWER(const char *str, int str_len)
185
+ {
186
+ char *item_dup;
187
+
188
+ item_dup = estrndup(str, str_len);
189
+ php_strtolower(item_dup, str_len);
190
+ return item_dup;
191
+ }
192
+
193
+ static zval *TWIG_CALL_USER_FUNC_ARRAY(zval *object, char *function, zval *arguments TSRMLS_DC)
194
+ {
195
+ zend_fcall_info fci;
196
+ zval ***args = NULL;
197
+ int arg_count = 0;
198
+ HashTable *table;
199
+ HashPosition pos;
200
+ int i = 0;
201
+ zval *retval_ptr;
202
+ zval *zfunction;
203
+
204
+ if (arguments) {
205
+ table = HASH_OF(arguments);
206
+ args = safe_emalloc(sizeof(zval **), table->nNumOfElements, 0);
207
+
208
+ zend_hash_internal_pointer_reset_ex(table, &pos);
209
+
210
+ while (zend_hash_get_current_data_ex(table, (void **)&args[i], &pos) == SUCCESS) {
211
+ i++;
212
+ zend_hash_move_forward_ex(table, &pos);
213
+ }
214
+ arg_count = table->nNumOfElements;
215
+ }
216
+
217
+ MAKE_STD_ZVAL(zfunction);
218
+ ZVAL_STRING(zfunction, function, 1);
219
+ fci.size = sizeof(fci);
220
+ fci.function_table = EG(function_table);
221
+ fci.function_name = zfunction;
222
+ fci.symbol_table = NULL;
223
+ #if PHP_VERSION_ID >= 50300
224
+ fci.object_ptr = object;
225
+ #else
226
+ fci.object_pp = &object;
227
+ #endif
228
+ fci.retval_ptr_ptr = &retval_ptr;
229
+ fci.param_count = arg_count;
230
+ fci.params = args;
231
+ fci.no_separation = 0;
232
+
233
+ if (zend_call_function(&fci, NULL TSRMLS_CC) == FAILURE) {
234
+ ALLOC_INIT_ZVAL(retval_ptr);
235
+ ZVAL_BOOL(retval_ptr, 0);
236
+ }
237
+
238
+ if (args) {
239
+ efree(fci.params);
240
+ }
241
+ FREE_DTOR(zfunction);
242
+ return retval_ptr;
243
+ }
244
+
245
+ static int TWIG_CALL_BOOLEAN(zval *object, char *functionName TSRMLS_DC)
246
+ {
247
+ zval *ret;
248
+ int res;
249
+
250
+ ret = TWIG_CALL_USER_FUNC_ARRAY(object, functionName, NULL TSRMLS_CC);
251
+ res = Z_LVAL_P(ret);
252
+ zval_ptr_dtor(&ret);
253
+ return res;
254
+ }
255
+
256
+ static zval *TWIG_GET_STATIC_PROPERTY(zval *class, char *prop_name TSRMLS_DC)
257
+ {
258
+ zval **tmp_zval;
259
+ zend_class_entry *ce;
260
+
261
+ if (class == NULL || Z_TYPE_P(class) != IS_OBJECT) {
262
+ return NULL;
263
+ }
264
+
265
+ ce = zend_get_class_entry(class TSRMLS_CC);
266
+ #if PHP_VERSION_ID >= 50400
267
+ tmp_zval = zend_std_get_static_property(ce, prop_name, strlen(prop_name), 0, NULL TSRMLS_CC);
268
+ #else
269
+ tmp_zval = zend_std_get_static_property(ce, prop_name, strlen(prop_name), 0 TSRMLS_CC);
270
+ #endif
271
+ return *tmp_zval;
272
+ }
273
+
274
+ static zval *TWIG_GET_ARRAY_ELEMENT_ZVAL(zval *class, zval *prop_name TSRMLS_DC)
275
+ {
276
+ zval **tmp_zval;
277
+
278
+ if (class == NULL || Z_TYPE_P(class) != IS_ARRAY) {
279
+ if (class != NULL && Z_TYPE_P(class) == IS_OBJECT && TWIG_INSTANCE_OF(class, zend_ce_arrayaccess TSRMLS_CC)) {
280
+ // array access object
281
+ return TWIG_GET_ARRAYOBJECT_ELEMENT(class, prop_name TSRMLS_CC);
282
+ }
283
+ return NULL;
284
+ }
285
+
286
+ switch(Z_TYPE_P(prop_name)) {
287
+ case IS_NULL:
288
+ zend_hash_find(HASH_OF(class), "", 1, (void**) &tmp_zval);
289
+ return *tmp_zval;
290
+
291
+ case IS_BOOL:
292
+ case IS_DOUBLE:
293
+ convert_to_long(prop_name);
294
+ case IS_LONG:
295
+ zend_hash_index_find(HASH_OF(class), Z_LVAL_P(prop_name), (void **) &tmp_zval);
296
+ return *tmp_zval;
297
+
298
+ case IS_STRING:
299
+ zend_symtable_find(HASH_OF(class), Z_STRVAL_P(prop_name), Z_STRLEN_P(prop_name) + 1, (void**) &tmp_zval);
300
+ return *tmp_zval;
301
+ }
302
+
303
+ return NULL;
304
+ }
305
+
306
+ static zval *TWIG_GET_ARRAY_ELEMENT(zval *class, char *prop_name, int prop_name_length TSRMLS_DC)
307
+ {
308
+ zval **tmp_zval;
309
+
310
+ if (class == NULL/* || Z_TYPE_P(class) != IS_ARRAY*/) {
311
+ return NULL;
312
+ }
313
+
314
+ if (class != NULL && Z_TYPE_P(class) == IS_OBJECT && TWIG_INSTANCE_OF(class, zend_ce_arrayaccess TSRMLS_CC)) {
315
+ // array access object
316
+ zval *tmp_name_zval;
317
+ zval *tmp_ret_zval;
318
+
319
+ ALLOC_INIT_ZVAL(tmp_name_zval);
320
+ ZVAL_STRING(tmp_name_zval, prop_name, 1);
321
+ tmp_ret_zval = TWIG_GET_ARRAYOBJECT_ELEMENT(class, tmp_name_zval TSRMLS_CC);
322
+ FREE_DTOR(tmp_name_zval);
323
+ return tmp_ret_zval;
324
+ }
325
+
326
+ if (zend_symtable_find(HASH_OF(class), prop_name, prop_name_length+1, (void**)&tmp_zval) == SUCCESS) {
327
+ return *tmp_zval;
328
+ }
329
+ return NULL;
330
+ }
331
+
332
+ static zval *TWIG_PROPERTY(zval *object, zval *propname TSRMLS_DC)
333
+ {
334
+ zval *tmp = NULL;
335
+
336
+ if (Z_OBJ_HT_P(object)->read_property) {
337
+ #if PHP_VERSION_ID >= 50400
338
+ tmp = Z_OBJ_HT_P(object)->read_property(object, propname, BP_VAR_IS, NULL TSRMLS_CC);
339
+ #else
340
+ tmp = Z_OBJ_HT_P(object)->read_property(object, propname, BP_VAR_IS TSRMLS_CC);
341
+ #endif
342
+ if (tmp == EG(uninitialized_zval_ptr)) {
343
+ ZVAL_NULL(tmp);
344
+ }
345
+ }
346
+ return tmp;
347
+ }
348
+
349
+ static int TWIG_HAS_PROPERTY(zval *object, zval *propname TSRMLS_DC)
350
+ {
351
+ if (Z_OBJ_HT_P(object)->has_property) {
352
+ #if PHP_VERSION_ID >= 50400
353
+ return Z_OBJ_HT_P(object)->has_property(object, propname, 0, NULL TSRMLS_CC);
354
+ #else
355
+ return Z_OBJ_HT_P(object)->has_property(object, propname, 0 TSRMLS_CC);
356
+ #endif
357
+ }
358
+ return 0;
359
+ }
360
+
361
+ static int TWIG_HAS_DYNAMIC_PROPERTY(zval *object, char *prop, int prop_len TSRMLS_DC)
362
+ {
363
+ if (Z_OBJ_HT_P(object)->get_properties) {
364
+ return zend_hash_quick_exists(
365
+ Z_OBJ_HT_P(object)->get_properties(object TSRMLS_CC), // the properties hash
366
+ prop, // property name
367
+ prop_len + 1, // property length
368
+ zend_get_hash_value(prop, prop_len + 1) // hash value
369
+ );
370
+ }
371
+ return 0;
372
+ }
373
+
374
+ static zval *TWIG_PROPERTY_CHAR(zval *object, char *propname TSRMLS_DC)
375
+ {
376
+ zval *tmp_name_zval, *tmp;
377
+
378
+ ALLOC_INIT_ZVAL(tmp_name_zval);
379
+ ZVAL_STRING(tmp_name_zval, propname, 1);
380
+ tmp = TWIG_PROPERTY(object, tmp_name_zval TSRMLS_CC);
381
+ FREE_DTOR(tmp_name_zval);
382
+ return tmp;
383
+ }
384
+
385
+ static zval *TWIG_CALL_S(zval *object, char *method, char *arg0 TSRMLS_DC)
386
+ {
387
+ zend_fcall_info fci;
388
+ zval **args[1];
389
+ zval *argument;
390
+ zval *zfunction;
391
+ zval *retval_ptr;
392
+
393
+ MAKE_STD_ZVAL(argument);
394
+ ZVAL_STRING(argument, arg0, 1);
395
+ args[0] = &argument;
396
+
397
+ MAKE_STD_ZVAL(zfunction);
398
+ ZVAL_STRING(zfunction, method, 1);
399
+ fci.size = sizeof(fci);
400
+ fci.function_table = EG(function_table);
401
+ fci.function_name = zfunction;
402
+ fci.symbol_table = NULL;
403
+ #if PHP_VERSION_ID >= 50300
404
+ fci.object_ptr = object;
405
+ #else
406
+ fci.object_pp = &object;
407
+ #endif
408
+ fci.retval_ptr_ptr = &retval_ptr;
409
+ fci.param_count = 1;
410
+ fci.params = args;
411
+ fci.no_separation = 0;
412
+
413
+ if (zend_call_function(&fci, NULL TSRMLS_CC) == FAILURE) {
414
+ FREE_DTOR(zfunction);
415
+ zval_ptr_dtor(&argument);
416
+ return 0;
417
+ }
418
+ FREE_DTOR(zfunction);
419
+ zval_ptr_dtor(&argument);
420
+ return retval_ptr;
421
+ }
422
+
423
+ static int TWIG_CALL_SB(zval *object, char *method, char *arg0 TSRMLS_DC)
424
+ {
425
+ zval *retval_ptr;
426
+ int success;
427
+
428
+ retval_ptr = TWIG_CALL_S(object, method, arg0 TSRMLS_CC);
429
+ success = (retval_ptr && (Z_TYPE_P(retval_ptr) == IS_BOOL) && Z_LVAL_P(retval_ptr));
430
+
431
+ if (retval_ptr) {
432
+ zval_ptr_dtor(&retval_ptr);
433
+ }
434
+
435
+ return success;
436
+ }
437
+
438
+ static int TWIG_CALL_ZZ(zval *object, char *method, zval *arg1, zval *arg2 TSRMLS_DC)
439
+ {
440
+ zend_fcall_info fci;
441
+ zval **args[2];
442
+ zval *zfunction;
443
+ zval *retval_ptr;
444
+ int success;
445
+
446
+ args[0] = &arg1;
447
+ args[1] = &arg2;
448
+
449
+ MAKE_STD_ZVAL(zfunction);
450
+ ZVAL_STRING(zfunction, method, 1);
451
+ fci.size = sizeof(fci);
452
+ fci.function_table = EG(function_table);
453
+ fci.function_name = zfunction;
454
+ fci.symbol_table = NULL;
455
+ #if PHP_VERSION_ID >= 50300
456
+ fci.object_ptr = object;
457
+ #else
458
+ fci.object_pp = &object;
459
+ #endif
460
+ fci.retval_ptr_ptr = &retval_ptr;
461
+ fci.param_count = 2;
462
+ fci.params = args;
463
+ fci.no_separation = 0;
464
+
465
+ if (zend_call_function(&fci, NULL TSRMLS_CC) == FAILURE) {
466
+ FREE_DTOR(zfunction);
467
+ return 0;
468
+ }
469
+
470
+ FREE_DTOR(zfunction);
471
+
472
+ success = (retval_ptr && (Z_TYPE_P(retval_ptr) == IS_BOOL) && Z_LVAL_P(retval_ptr));
473
+ if (retval_ptr) {
474
+ zval_ptr_dtor(&retval_ptr);
475
+ }
476
+
477
+ return success;
478
+ }
479
+
480
+ #ifndef Z_SET_REFCOUNT_P
481
+ # define Z_SET_REFCOUNT_P(pz, rc) pz->refcount = rc
482
+ # define Z_UNSET_ISREF_P(pz) pz->is_ref = 0
483
+ #endif
484
+
485
+ static void TWIG_NEW(zval *object, char *class, zval *arg0, zval *arg1 TSRMLS_DC)
486
+ {
487
+ zend_class_entry **pce;
488
+
489
+ if (zend_lookup_class(class, strlen(class), &pce TSRMLS_CC) == FAILURE) {
490
+ return;
491
+ }
492
+
493
+ Z_TYPE_P(object) = IS_OBJECT;
494
+ object_init_ex(object, *pce);
495
+ Z_SET_REFCOUNT_P(object, 1);
496
+ Z_UNSET_ISREF_P(object);
497
+
498
+ TWIG_CALL_ZZ(object, "__construct", arg0, arg1 TSRMLS_CC);
499
+ }
500
+
501
+ static int twig_add_array_key_to_string(void *pDest APPLY_TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key)
502
+ {
503
+ smart_str *buf;
504
+ char *joiner;
505
+ APPLY_TSRMLS_FETCH();
506
+
507
+ buf = va_arg(args, smart_str*);
508
+ joiner = va_arg(args, char*);
509
+
510
+ if (buf->len != 0) {
511
+ smart_str_appends(buf, joiner);
512
+ }
513
+
514
+ if (hash_key->nKeyLength == 0) {
515
+ smart_str_append_long(buf, (long) hash_key->h);
516
+ } else {
517
+ char *key, *tmp_str;
518
+ int key_len, tmp_len;
519
+ key = php_addcslashes(hash_key->arKey, hash_key->nKeyLength - 1, &key_len, 0, "'\\", 2 TSRMLS_CC);
520
+ tmp_str = php_str_to_str_ex(key, key_len, "\0", 1, "' . \"\\0\" . '", 12, &tmp_len, 0, NULL);
521
+
522
+ smart_str_appendl(buf, tmp_str, tmp_len);
523
+ efree(key);
524
+ efree(tmp_str);
525
+ }
526
+
527
+ return 0;
528
+ }
529
+
530
+ static char *TWIG_IMPLODE_ARRAY_KEYS(char *joiner, zval *array TSRMLS_DC)
531
+ {
532
+ smart_str collector = { 0, 0, 0 };
533
+
534
+ smart_str_appendl(&collector, "", 0);
535
+ zend_hash_apply_with_arguments(HASH_OF(array) APPLY_TSRMLS_CC, twig_add_array_key_to_string, 2, &collector, joiner);
536
+ smart_str_0(&collector);
537
+
538
+ return collector.c;
539
+ }
540
+
541
+ static void TWIG_RUNTIME_ERROR(zval *template TSRMLS_DC, char *message, ...)
542
+ {
543
+ char *buffer;
544
+ va_list args;
545
+ zend_class_entry **pce;
546
+ zval *ex;
547
+ zval *constructor;
548
+ zval *zmessage;
549
+ zval *lineno;
550
+ zval *filename_func;
551
+ zval *filename;
552
+ zval *constructor_args[3];
553
+ zval *constructor_retval;
554
+
555
+ if (zend_lookup_class("Twig_Error_Runtime", strlen("Twig_Error_Runtime"), &pce TSRMLS_CC) == FAILURE) {
556
+ return;
557
+ }
558
+
559
+ va_start(args, message);
560
+ vspprintf(&buffer, 0, message, args);
561
+ va_end(args);
562
+
563
+ MAKE_STD_ZVAL(ex);
564
+ object_init_ex(ex, *pce);
565
+
566
+ // Call Twig_Error constructor
567
+ MAKE_STD_ZVAL(constructor);
568
+ MAKE_STD_ZVAL(zmessage);
569
+ MAKE_STD_ZVAL(lineno);
570
+ MAKE_STD_ZVAL(filename);
571
+ MAKE_STD_ZVAL(filename_func);
572
+ MAKE_STD_ZVAL(constructor_retval);
573
+
574
+ ZVAL_STRINGL(constructor, "__construct", sizeof("__construct")-1, 1);
575
+ ZVAL_STRING(zmessage, buffer, 1);
576
+ ZVAL_LONG(lineno, -1);
577
+
578
+ // Get template filename
579
+ ZVAL_STRINGL(filename_func, "getTemplateName", sizeof("getTemplateName")-1, 1);
580
+ call_user_function(EG(function_table), &template, filename_func, filename, 0, 0 TSRMLS_CC);
581
+
582
+ constructor_args[0] = zmessage;
583
+ constructor_args[1] = lineno;
584
+ constructor_args[2] = filename;
585
+ call_user_function(EG(function_table), &ex, constructor, constructor_retval, 3, constructor_args TSRMLS_CC);
586
+
587
+ zval_ptr_dtor(&constructor_retval);
588
+ zval_ptr_dtor(&zmessage);
589
+ zval_ptr_dtor(&lineno);
590
+ zval_ptr_dtor(&filename);
591
+ FREE_DTOR(constructor);
592
+ FREE_DTOR(filename_func);
593
+ efree(buffer);
594
+
595
+ zend_throw_exception_object(ex TSRMLS_CC);
596
+ }
597
+
598
+ static char *TWIG_GET_CLASS_NAME(zval *object TSRMLS_DC)
599
+ {
600
+ char *class_name;
601
+ zend_uint class_name_len;
602
+
603
+ if (Z_TYPE_P(object) != IS_OBJECT) {
604
+ return "";
605
+ }
606
+ #if PHP_API_VERSION >= 20100412
607
+ zend_get_object_classname(object, (const char **) &class_name, &class_name_len TSRMLS_CC);
608
+ #else
609
+ zend_get_object_classname(object, &class_name, &class_name_len TSRMLS_CC);
610
+ #endif
611
+ return class_name;
612
+ }
613
+
614
+ static int twig_add_method_to_class(void *pDest APPLY_TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key)
615
+ {
616
+ zend_class_entry *ce;
617
+ zval *retval;
618
+ char *item;
619
+ size_t item_len;
620
+ zend_function *mptr = (zend_function *) pDest;
621
+ APPLY_TSRMLS_FETCH();
622
+
623
+ if (!(mptr->common.fn_flags & ZEND_ACC_PUBLIC)) {
624
+ return 0;
625
+ }
626
+
627
+ ce = *va_arg(args, zend_class_entry**);
628
+ retval = va_arg(args, zval*);
629
+
630
+ item_len = strlen(mptr->common.function_name);
631
+ item = estrndup(mptr->common.function_name, item_len);
632
+ php_strtolower(item, item_len);
633
+
634
+ if (strcmp("getenvironment", item) == 0) {
635
+ zend_class_entry **twig_template_ce;
636
+ if (zend_lookup_class("Twig_Template", strlen("Twig_Template"), &twig_template_ce TSRMLS_CC) == FAILURE) {
637
+ return 0;
638
+ }
639
+ if (instanceof_function(ce, *twig_template_ce TSRMLS_CC)) {
640
+ return 0;
641
+ }
642
+ }
643
+
644
+ add_assoc_stringl_ex(retval, item, item_len+1, item, item_len, 0);
645
+
646
+ return 0;
647
+ }
648
+
649
+ static int twig_add_property_to_class(void *pDest APPLY_TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key)
650
+ {
651
+ zend_class_entry *ce;
652
+ zval *retval;
653
+ char *class_name, *prop_name;
654
+ zend_property_info *pptr = (zend_property_info *) pDest;
655
+ APPLY_TSRMLS_FETCH();
656
+
657
+ if (!(pptr->flags & ZEND_ACC_PUBLIC) || (pptr->flags & ZEND_ACC_STATIC)) {
658
+ return 0;
659
+ }
660
+
661
+ ce = *va_arg(args, zend_class_entry**);
662
+ retval = va_arg(args, zval*);
663
+
664
+ #if PHP_API_VERSION >= 20100412
665
+ zend_unmangle_property_name(pptr->name, pptr->name_length, (const char **) &class_name, (const char **) &prop_name);
666
+ #else
667
+ zend_unmangle_property_name(pptr->name, pptr->name_length, &class_name, &prop_name);
668
+ #endif
669
+
670
+ add_assoc_string(retval, prop_name, prop_name, 1);
671
+
672
+ return 0;
673
+ }
674
+
675
+ static void twig_add_class_to_cache(zval *cache, zval *object, char *class_name TSRMLS_DC)
676
+ {
677
+ zval *class_info, *class_methods, *class_properties;
678
+ zend_class_entry *class_ce;
679
+
680
+ class_ce = zend_get_class_entry(object TSRMLS_CC);
681
+
682
+ ALLOC_INIT_ZVAL(class_info);
683
+ ALLOC_INIT_ZVAL(class_methods);
684
+ ALLOC_INIT_ZVAL(class_properties);
685
+ array_init(class_info);
686
+ array_init(class_methods);
687
+ array_init(class_properties);
688
+ // add all methods to self::cache[$class]['methods']
689
+ zend_hash_apply_with_arguments(&class_ce->function_table APPLY_TSRMLS_CC, twig_add_method_to_class, 2, &class_ce, class_methods);
690
+ zend_hash_apply_with_arguments(&class_ce->properties_info APPLY_TSRMLS_CC, twig_add_property_to_class, 2, &class_ce, class_properties);
691
+
692
+ add_assoc_zval(class_info, "methods", class_methods);
693
+ add_assoc_zval(class_info, "properties", class_properties);
694
+ add_assoc_zval(cache, class_name, class_info);
695
+ }
696
+
697
+ /* {{{ proto mixed twig_template_get_attributes(TwigTemplate template, mixed object, mixed item, array arguments, string type, boolean isDefinedTest, boolean ignoreStrictCheck)
698
+ A C implementation of TwigTemplate::getAttribute() */
699
+ PHP_FUNCTION(twig_template_get_attributes)
700
+ {
701
+ zval *template;
702
+ zval *object;
703
+ char *item;
704
+ int item_len;
705
+ zval *zitem, ztmpitem;
706
+ zval *arguments = NULL;
707
+ zval *ret = NULL;
708
+ char *type = NULL;
709
+ int type_len = 0;
710
+ zend_bool isDefinedTest = 0;
711
+ zend_bool ignoreStrictCheck = 0;
712
+ int free_ret = 0;
713
+ zval *tmp_self_cache;
714
+ char *class_name = NULL;
715
+ zval *tmp_class;
716
+ char *type_name;
717
+
718
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ozz|asbb", &template, &object, &zitem, &arguments, &type, &type_len, &isDefinedTest, &ignoreStrictCheck) == FAILURE) {
719
+ return;
720
+ }
721
+
722
+ // convert the item to a string
723
+ ztmpitem = *zitem;
724
+ zval_copy_ctor(&ztmpitem);
725
+ convert_to_string(&ztmpitem);
726
+ item_len = Z_STRLEN(ztmpitem);
727
+ item = estrndup(Z_STRVAL(ztmpitem), item_len);
728
+ zval_dtor(&ztmpitem);
729
+
730
+ if (!type) {
731
+ type = "any";
732
+ }
733
+
734
+ /*
735
+ // array
736
+ if (Twig_Template::METHOD_CALL !== $type) {
737
+ $arrayItem = is_bool($item) || is_float($item) ? (int) $item : $item;
738
+
739
+ if ((is_array($object) && array_key_exists($arrayItem, $object))
740
+ || ($object instanceof ArrayAccess && isset($object[$arrayItem]))
741
+ ) {
742
+ if ($isDefinedTest) {
743
+ return true;
744
+ }
745
+
746
+ return $object[$arrayItem];
747
+ }
748
+ */
749
+
750
+
751
+ if (strcmp("method", type) != 0) {
752
+ if ((TWIG_ARRAY_KEY_EXISTS(object, zitem))
753
+ || (TWIG_INSTANCE_OF(object, zend_ce_arrayaccess TSRMLS_CC) && TWIG_ISSET_ARRAYOBJECT_ELEMENT(object, zitem TSRMLS_CC))
754
+ ) {
755
+
756
+ if (isDefinedTest) {
757
+ efree(item);
758
+ RETURN_TRUE;
759
+ }
760
+
761
+ ret = TWIG_GET_ARRAY_ELEMENT_ZVAL(object, zitem TSRMLS_CC);
762
+
763
+ if (!ret) {
764
+ ret = &EG(uninitialized_zval);
765
+ }
766
+ RETVAL_ZVAL(ret, 1, 0);
767
+ if (free_ret) {
768
+ zval_ptr_dtor(&ret);
769
+ }
770
+ efree(item);
771
+ return;
772
+ }
773
+ /*
774
+ if (Twig_Template::ARRAY_CALL === $type) {
775
+ if ($isDefinedTest) {
776
+ return false;
777
+ }
778
+ if ($ignoreStrictCheck || !$this->env->isStrictVariables()) {
779
+ return null;
780
+ }
781
+ */
782
+ if (strcmp("array", type) == 0 || Z_TYPE_P(object) != IS_OBJECT) {
783
+ if (isDefinedTest) {
784
+ efree(item);
785
+ RETURN_FALSE;
786
+ }
787
+ if (ignoreStrictCheck || !TWIG_CALL_BOOLEAN(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC), "isStrictVariables" TSRMLS_CC)) {
788
+ efree(item);
789
+ return;
790
+ }
791
+ /*
792
+ if ($object instanceof ArrayAccess) {
793
+ $message = sprintf('Key "%s" in object with ArrayAccess of class "%s" does not exist', $arrayItem, get_class($object));
794
+ } elseif (is_object($object)) {
795
+ $message = sprintf('Impossible to access a key "%s" on an object of class "%s" that does not implement ArrayAccess interface', $item, get_class($object));
796
+ } elseif (is_array($object)) {
797
+ if (empty($object)) {
798
+ $message = sprintf('Key "%s" does not exist as the array is empty', $arrayItem);
799
+ } else {
800
+ $message = sprintf('Key "%s" for array with keys "%s" does not exist', $arrayItem, implode(', ', array_keys($object)));
801
+ }
802
+ } elseif (Twig_Template::ARRAY_CALL === $type) {
803
+ if (null === $object) {
804
+ $message = sprintf('Impossible to access a key ("%s") on a null variable', $item);
805
+ } else {
806
+ $message = sprintf('Impossible to access a key ("%s") on a %s variable ("%s")', $item, gettype($object), $object);
807
+ }
808
+ } elseif (null === $object) {
809
+ $message = sprintf('Impossible to access an attribute ("%s") on a null variable', $item);
810
+ } else {
811
+ $message = sprintf('Impossible to access an attribute ("%s") on a %s variable ("%s")', $item, gettype($object), $object);
812
+ }
813
+ throw new Twig_Error_Runtime($message, -1, $this->getTemplateName());
814
+ }
815
+ }
816
+ */
817
+ if (TWIG_INSTANCE_OF(object, zend_ce_arrayaccess TSRMLS_CC)) {
818
+ TWIG_RUNTIME_ERROR(template TSRMLS_CC, "Key \"%s\" in object with ArrayAccess of class \"%s\" does not exist.", item, TWIG_GET_CLASS_NAME(object TSRMLS_CC));
819
+ } else if (Z_TYPE_P(object) == IS_OBJECT) {
820
+ TWIG_RUNTIME_ERROR(template TSRMLS_CC, "Impossible to access a key \"%s\" on an object of class \"%s\" that does not implement ArrayAccess interface.", item, TWIG_GET_CLASS_NAME(object TSRMLS_CC));
821
+ } else if (Z_TYPE_P(object) == IS_ARRAY) {
822
+ if (0 == zend_hash_num_elements(Z_ARRVAL_P(object))) {
823
+ TWIG_RUNTIME_ERROR(template TSRMLS_CC, "Key \"%s\" does not exist as the array is empty.", item);
824
+ } else {
825
+ char *array_keys = TWIG_IMPLODE_ARRAY_KEYS(", ", object TSRMLS_CC);
826
+ TWIG_RUNTIME_ERROR(template TSRMLS_CC, "Key \"%s\" for array with keys \"%s\" does not exist.", item, array_keys);
827
+ efree(array_keys);
828
+ }
829
+ } else {
830
+ char *type_name = zend_zval_type_name(object);
831
+ Z_ADDREF_P(object);
832
+ if (Z_TYPE_P(object) == IS_NULL) {
833
+ convert_to_string(object);
834
+ TWIG_RUNTIME_ERROR(template TSRMLS_CC,
835
+ (strcmp("array", type) == 0)
836
+ ? "Impossible to access a key (\"%s\") on a %s variable."
837
+ : "Impossible to access an attribute (\"%s\") on a %s variable.",
838
+ item, type_name);
839
+ } else {
840
+ convert_to_string(object);
841
+ TWIG_RUNTIME_ERROR(template TSRMLS_CC,
842
+ (strcmp("array", type) == 0)
843
+ ? "Impossible to access a key (\"%s\") on a %s variable (\"%s\")."
844
+ : "Impossible to access an attribute (\"%s\") on a %s variable (\"%s\").",
845
+ item, type_name, Z_STRVAL_P(object));
846
+ }
847
+ zval_ptr_dtor(&object);
848
+ }
849
+ efree(item);
850
+ return;
851
+ }
852
+ }
853
+
854
+ /*
855
+ if (!is_object($object)) {
856
+ if ($isDefinedTest) {
857
+ return false;
858
+ }
859
+ */
860
+
861
+ if (Z_TYPE_P(object) != IS_OBJECT) {
862
+ if (isDefinedTest) {
863
+ efree(item);
864
+ RETURN_FALSE;
865
+ }
866
+ /*
867
+ if ($ignoreStrictCheck || !$this->env->isStrictVariables()) {
868
+ return null;
869
+ }
870
+
871
+ if (null === $object) {
872
+ $message = sprintf('Impossible to invoke a method ("%s") on a null variable', $item);
873
+ } else {
874
+ $message = sprintf('Impossible to invoke a method ("%s") on a %s variable ("%s")', $item, gettype($object), $object);
875
+ }
876
+
877
+ throw new Twig_Error_Runtime($message, -1, $this->getTemplateName());
878
+ }
879
+ */
880
+ if (ignoreStrictCheck || !TWIG_CALL_BOOLEAN(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC), "isStrictVariables" TSRMLS_CC)) {
881
+ efree(item);
882
+ return;
883
+ }
884
+
885
+ type_name = zend_zval_type_name(object);
886
+ Z_ADDREF_P(object);
887
+ if (Z_TYPE_P(object) == IS_NULL) {
888
+ convert_to_string_ex(&object);
889
+
890
+ TWIG_RUNTIME_ERROR(template TSRMLS_CC, "Impossible to invoke a method (\"%s\") on a %s variable.", item, type_name);
891
+ } else {
892
+ convert_to_string_ex(&object);
893
+
894
+ TWIG_RUNTIME_ERROR(template TSRMLS_CC, "Impossible to invoke a method (\"%s\") on a %s variable (\"%s\").", item, type_name, Z_STRVAL_P(object));
895
+ }
896
+
897
+ zval_ptr_dtor(&object);
898
+ efree(item);
899
+ return;
900
+ }
901
+ /*
902
+ $class = get_class($object);
903
+ */
904
+
905
+ class_name = TWIG_GET_CLASS_NAME(object TSRMLS_CC);
906
+ tmp_self_cache = TWIG_GET_STATIC_PROPERTY(template, "cache" TSRMLS_CC);
907
+ tmp_class = TWIG_GET_ARRAY_ELEMENT(tmp_self_cache, class_name, strlen(class_name) TSRMLS_CC);
908
+
909
+ if (!tmp_class) {
910
+ twig_add_class_to_cache(tmp_self_cache, object, class_name TSRMLS_CC);
911
+ tmp_class = TWIG_GET_ARRAY_ELEMENT(tmp_self_cache, class_name, strlen(class_name) TSRMLS_CC);
912
+ }
913
+ efree(class_name);
914
+
915
+ /*
916
+ // object property
917
+ if (Twig_Template::METHOD_CALL !== $type && !$object instanceof Twig_Template) {
918
+ if (isset($object->$item) || array_key_exists((string) $item, $object)) {
919
+ if ($isDefinedTest) {
920
+ return true;
921
+ }
922
+
923
+ if ($this->env->hasExtension('Twig_Extension_Sandbox')) {
924
+ $this->env->getExtension('Twig_Extension_Sandbox')->checkPropertyAllowed($object, $item);
925
+ }
926
+
927
+ return $object->$item;
928
+ }
929
+ }
930
+ */
931
+ if (strcmp("method", type) != 0 && !TWIG_INSTANCE_OF_USERLAND(object, "Twig_Template" TSRMLS_CC)) {
932
+ zval *tmp_properties, *tmp_item;
933
+
934
+ tmp_properties = TWIG_GET_ARRAY_ELEMENT(tmp_class, "properties", strlen("properties") TSRMLS_CC);
935
+ tmp_item = TWIG_GET_ARRAY_ELEMENT(tmp_properties, item, item_len TSRMLS_CC);
936
+
937
+ if (tmp_item || TWIG_HAS_PROPERTY(object, zitem TSRMLS_CC) || TWIG_HAS_DYNAMIC_PROPERTY(object, item, item_len TSRMLS_CC)) {
938
+ if (isDefinedTest) {
939
+ efree(item);
940
+ RETURN_TRUE;
941
+ }
942
+ if (TWIG_CALL_SB(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC), "hasExtension", "Twig_Extension_Sandbox" TSRMLS_CC)) {
943
+ TWIG_CALL_ZZ(TWIG_CALL_S(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC), "getExtension", "Twig_Extension_Sandbox" TSRMLS_CC), "checkPropertyAllowed", object, zitem TSRMLS_CC);
944
+ }
945
+ if (EG(exception)) {
946
+ efree(item);
947
+ return;
948
+ }
949
+
950
+ ret = TWIG_PROPERTY(object, zitem TSRMLS_CC);
951
+ efree(item);
952
+ RETURN_ZVAL(ret, 1, 0);
953
+ }
954
+ }
955
+ /*
956
+ // object method
957
+ if (!isset(self::$cache[$class]['methods'])) {
958
+ if ($object instanceof self) {
959
+ $ref = new ReflectionClass($class);
960
+ $methods = array();
961
+
962
+ foreach ($ref->getMethods(ReflectionMethod::IS_PUBLIC) as $refMethod) {
963
+ $methodName = strtolower($refMethod->name);
964
+
965
+ // Accessing the environment from templates is forbidden to prevent untrusted changes to the environment
966
+ if ('getenvironment' !== $methodName) {
967
+ $methods[$methodName] = true;
968
+ }
969
+ }
970
+
971
+ self::$cache[$class]['methods'] = $methods;
972
+ } else {
973
+ self::$cache[$class]['methods'] = array_change_key_case(array_flip(get_class_methods($object)));
974
+ }
975
+ }
976
+
977
+ $call = false;
978
+ $lcItem = strtolower($item);
979
+ if (isset(self::$cache[$class]['methods'][$lcItem])) {
980
+ $method = (string) $item;
981
+ } elseif (isset(self::$cache[$class]['methods']['get'.$lcItem])) {
982
+ $method = 'get'.$item;
983
+ } elseif (isset(self::$cache[$class]['methods']['is'.$lcItem])) {
984
+ $method = 'is'.$item;
985
+ } elseif (isset(self::$cache[$class]['methods']['__call'])) {
986
+ $method = (string) $item;
987
+ $call = true;
988
+ */
989
+ {
990
+ int call = 0;
991
+ char *lcItem = TWIG_STRTOLOWER(item, item_len);
992
+ int lcItem_length;
993
+ char *method = NULL;
994
+ char *methodForDeprecation = NULL;
995
+ char *tmp_method_name_get;
996
+ char *tmp_method_name_is;
997
+ zval *zmethod;
998
+ zval *tmp_methods;
999
+
1000
+ lcItem_length = strlen(lcItem);
1001
+ tmp_method_name_get = emalloc(4 + lcItem_length);
1002
+ tmp_method_name_is = emalloc(3 + lcItem_length);
1003
+
1004
+ sprintf(tmp_method_name_get, "get%s", lcItem);
1005
+ sprintf(tmp_method_name_is, "is%s", lcItem);
1006
+
1007
+ tmp_methods = TWIG_GET_ARRAY_ELEMENT(tmp_class, "methods", strlen("methods") TSRMLS_CC);
1008
+ methodForDeprecation = emalloc(item_len + 1);
1009
+ sprintf(methodForDeprecation, "%s", item);
1010
+
1011
+ if (TWIG_GET_ARRAY_ELEMENT(tmp_methods, lcItem, lcItem_length TSRMLS_CC)) {
1012
+ method = item;
1013
+ } else if (TWIG_GET_ARRAY_ELEMENT(tmp_methods, tmp_method_name_get, lcItem_length + 3 TSRMLS_CC)) {
1014
+ method = tmp_method_name_get;
1015
+ } else if (TWIG_GET_ARRAY_ELEMENT(tmp_methods, tmp_method_name_is, lcItem_length + 2 TSRMLS_CC)) {
1016
+ method = tmp_method_name_is;
1017
+ } else if (TWIG_GET_ARRAY_ELEMENT(tmp_methods, "__call", 6 TSRMLS_CC)) {
1018
+ method = item;
1019
+ call = 1;
1020
+ /*
1021
+ } else {
1022
+ if ($isDefinedTest) {
1023
+ return false;
1024
+ }
1025
+
1026
+ if ($ignoreStrictCheck || !$this->env->isStrictVariables()) {
1027
+ return null;
1028
+ }
1029
+
1030
+ throw new Twig_Error_Runtime(sprintf('Method "%s" for object "%s" does not exist.', $item, get_class($object)), -1, $this->getTemplateName());
1031
+ }
1032
+
1033
+ if ($isDefinedTest) {
1034
+ return true;
1035
+ }
1036
+ */
1037
+ } else {
1038
+ efree(tmp_method_name_get);
1039
+ efree(tmp_method_name_is);
1040
+ efree(lcItem);
1041
+
1042
+ if (isDefinedTest) {
1043
+ efree(item);
1044
+ RETURN_FALSE;
1045
+ }
1046
+ if (ignoreStrictCheck || !TWIG_CALL_BOOLEAN(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC), "isStrictVariables" TSRMLS_CC)) {
1047
+ efree(item);
1048
+ return;
1049
+ }
1050
+ TWIG_RUNTIME_ERROR(template TSRMLS_CC, "Neither the property \"%s\" nor one of the methods \"%s()\", \"get%s()\"/\"is%s()\" or \"__call()\" exist and have public access in class \"%s\".", item, item, item, item, TWIG_GET_CLASS_NAME(object TSRMLS_CC));
1051
+ efree(item);
1052
+ return;
1053
+ }
1054
+
1055
+ if (isDefinedTest) {
1056
+ efree(tmp_method_name_get);
1057
+ efree(tmp_method_name_is);
1058
+ efree(lcItem);efree(item);
1059
+ RETURN_TRUE;
1060
+ }
1061
+ /*
1062
+ if ($this->env->hasExtension('Twig_Extension_Sandbox')) {
1063
+ $this->env->getExtension('Twig_Extension_Sandbox')->checkMethodAllowed($object, $method);
1064
+ }
1065
+ */
1066
+ MAKE_STD_ZVAL(zmethod);
1067
+ ZVAL_STRING(zmethod, method, 1);
1068
+ if (TWIG_CALL_SB(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC), "hasExtension", "Twig_Extension_Sandbox" TSRMLS_CC)) {
1069
+ TWIG_CALL_ZZ(TWIG_CALL_S(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC), "getExtension", "Twig_Extension_Sandbox" TSRMLS_CC), "checkMethodAllowed", object, zmethod TSRMLS_CC);
1070
+ }
1071
+ zval_ptr_dtor(&zmethod);
1072
+ if (EG(exception)) {
1073
+ efree(tmp_method_name_get);
1074
+ efree(tmp_method_name_is);
1075
+ efree(lcItem);efree(item);
1076
+ return;
1077
+ }
1078
+ /*
1079
+ // Some objects throw exceptions when they have __call, and the method we try
1080
+ // to call is not supported. If ignoreStrictCheck is true, we should return null.
1081
+ try {
1082
+ $ret = call_user_func_array(array($object, $method), $arguments);
1083
+ } catch (BadMethodCallException $e) {
1084
+ if ($call && ($ignoreStrictCheck || !$this->env->isStrictVariables())) {
1085
+ return null;
1086
+ }
1087
+ throw $e;
1088
+ }
1089
+ */
1090
+ ret = TWIG_CALL_USER_FUNC_ARRAY(object, method, arguments TSRMLS_CC);
1091
+ if (EG(exception) && TWIG_INSTANCE_OF(EG(exception), spl_ce_BadMethodCallException TSRMLS_CC)) {
1092
+ if (ignoreStrictCheck || !TWIG_CALL_BOOLEAN(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC), "isStrictVariables" TSRMLS_CC)) {
1093
+ efree(tmp_method_name_get);
1094
+ efree(tmp_method_name_is);
1095
+ efree(lcItem);efree(item);
1096
+ zend_clear_exception(TSRMLS_C);
1097
+ return;
1098
+ }
1099
+ }
1100
+ free_ret = 1;
1101
+ efree(tmp_method_name_get);
1102
+ efree(tmp_method_name_is);
1103
+ efree(lcItem);
1104
+ /*
1105
+ // @deprecated in 1.28
1106
+ if ($object instanceof Twig_TemplateInterface) {
1107
+ $self = $object->getTemplateName() === $this->getTemplateName();
1108
+ $message = sprintf('Calling "%s" on template "%s" from template "%s" is deprecated since version 1.28 and won\'t be supported anymore in 2.0.', $item, $object->getTemplateName(), $this->getTemplateName());
1109
+ if ('renderBlock' === $method || 'displayBlock' === $method) {
1110
+ $message .= sprintf(' Use block("%s"%s) instead).', $arguments[0], $self ? '' : ', template');
1111
+ } elseif ('hasBlock' === $method) {
1112
+ $message .= sprintf(' Use "block("%s"%s) is defined" instead).', $arguments[0], $self ? '' : ', template');
1113
+ } elseif ('render' === $method || 'display' === $method) {
1114
+ $message .= sprintf(' Use include("%s") instead).', $object->getTemplateName());
1115
+ }
1116
+ @trigger_error($message, E_USER_DEPRECATED);
1117
+
1118
+ return $ret === '' ? '' : new Twig_Markup($ret, $this->env->getCharset());
1119
+ }
1120
+
1121
+ return $ret;
1122
+ */
1123
+ efree(item);
1124
+ // ret can be null, if e.g. the called method throws an exception
1125
+ if (ret) {
1126
+ if (TWIG_INSTANCE_OF_USERLAND(object, "Twig_TemplateInterface" TSRMLS_CC)) {
1127
+ int self;
1128
+ int old_error_reporting;
1129
+ zval *object_filename;
1130
+ zval *this_filename;
1131
+ zval *filename_func;
1132
+ char *deprecation_message_complement = NULL;
1133
+ char *deprecation_message = NULL;
1134
+
1135
+ MAKE_STD_ZVAL(object_filename);
1136
+ MAKE_STD_ZVAL(this_filename);
1137
+ MAKE_STD_ZVAL(filename_func);
1138
+
1139
+ // Get templates names
1140
+ ZVAL_STRINGL(filename_func, "getTemplateName", sizeof("getTemplateName")-1, 1);
1141
+ call_user_function(EG(function_table), &object, filename_func, object_filename, 0, 0 TSRMLS_CC);
1142
+ ZVAL_STRINGL(filename_func, "getTemplateName", sizeof("getTemplateName")-1, 1);
1143
+ call_user_function(EG(function_table), &template, filename_func, this_filename, 0, 0 TSRMLS_CC);
1144
+
1145
+ self = (strcmp(Z_STRVAL_P(object_filename), Z_STRVAL_P(this_filename)) == 0);
1146
+
1147
+ if (strcmp(methodForDeprecation, "renderBlock") == 0 || strcmp(methodForDeprecation, "displayBlock") == 0) {
1148
+ zval **arg0;
1149
+ zend_hash_index_find(HASH_OF(arguments), 0, (void **) &arg0);
1150
+ asprintf(
1151
+ &deprecation_message_complement,
1152
+ " Use block(\"%s\"%s) instead).",
1153
+ Z_STRVAL_PP(arg0),
1154
+ self ? "" : ", template"
1155
+ );
1156
+ } else if (strcmp(methodForDeprecation, "hasBlock") == 0) {
1157
+ zval **arg0;
1158
+ zend_hash_index_find(HASH_OF(arguments), 0, (void **) &arg0);
1159
+ asprintf(
1160
+ &deprecation_message_complement,
1161
+ " Use \"block(\"%s\"%s) is defined\" instead).",
1162
+ Z_STRVAL_PP(arg0),
1163
+ self ? "" : ", template"
1164
+ );
1165
+ } else if (strcmp(methodForDeprecation, "render") == 0 || strcmp(methodForDeprecation, "display") == 0) {
1166
+ asprintf(
1167
+ &deprecation_message_complement,
1168
+ " Use include(\"%s\") instead).",
1169
+ Z_STRVAL_P(object_filename)
1170
+ );
1171
+ } else {
1172
+ deprecation_message_complement = (char*)calloc(0, sizeof(char));
1173
+ }
1174
+
1175
+ asprintf(
1176
+ &deprecation_message,
1177
+ "Calling \"%s\" on template \"%s\" from template \"%s\" is deprecated since version 1.28 and won't be supported anymore in 2.0.%s",
1178
+ methodForDeprecation,
1179
+ Z_STRVAL_P(object_filename),
1180
+ Z_STRVAL_P(this_filename),
1181
+ deprecation_message_complement
1182
+ );
1183
+
1184
+ old_error_reporting = EG(error_reporting);
1185
+ EG(error_reporting) = 0;
1186
+ zend_error(E_USER_DEPRECATED, "%s", deprecation_message);
1187
+ EG(error_reporting) = old_error_reporting;
1188
+
1189
+ FREE_DTOR(filename_func)
1190
+ FREE_DTOR(object_filename)
1191
+ FREE_DTOR(this_filename)
1192
+ free(deprecation_message);
1193
+ free(deprecation_message_complement);
1194
+
1195
+ if (Z_STRLEN_P(ret) != 0) {
1196
+ zval *charset = TWIG_CALL_USER_FUNC_ARRAY(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC), "getCharset", NULL TSRMLS_CC);
1197
+ TWIG_NEW(return_value, "Twig_Markup", ret, charset TSRMLS_CC);
1198
+ zval_ptr_dtor(&charset);
1199
+ if (ret) {
1200
+ zval_ptr_dtor(&ret);
1201
+ }
1202
+ efree(methodForDeprecation);
1203
+ return;
1204
+ }
1205
+ }
1206
+
1207
+ RETVAL_ZVAL(ret, 1, 0);
1208
+ if (free_ret) {
1209
+ zval_ptr_dtor(&ret);
1210
+ }
1211
+ }
1212
+
1213
+ efree(methodForDeprecation);
1214
+ }
1215
+ }
library/twig/twig/lib/Twig/Autoloader.php CHANGED
@@ -3,7 +3,7 @@
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.
@@ -23,7 +23,7 @@ class Twig_Autoloader
23
  /**
24
  * Registers Twig_Autoloader as an SPL autoloader.
25
  *
26
- * @param bool $prepend Whether to prepend the autoloader or not.
27
  */
28
  public static function register($prepend = false)
29
  {
@@ -39,7 +39,7 @@ class Twig_Autoloader
39
  /**
40
  * Handles autoloading of classes.
41
  *
42
- * @param string $class A class name.
43
  */
44
  public static function autoload($class)
45
  {
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
23
  /**
24
  * Registers Twig_Autoloader as an SPL autoloader.
25
  *
26
+ * @param bool $prepend whether to prepend the autoloader or not
27
  */
28
  public static function register($prepend = false)
29
  {
39
  /**
40
  * Handles autoloading of classes.
41
  *
42
+ * @param string $class a class name
43
  */
44
  public static function autoload($class)
45
  {
library/twig/twig/lib/Twig/BaseNodeVisitor.php CHANGED
@@ -16,9 +16,6 @@
16
  */
17
  abstract class Twig_BaseNodeVisitor implements Twig_NodeVisitorInterface
18
  {
19
- /**
20
- * {@inheritdoc}
21
- */
22
  final public function enterNode(Twig_NodeInterface $node, Twig_Environment $env)
23
  {
24
  if (!$node instanceof Twig_Node) {
@@ -28,9 +25,6 @@ abstract class Twig_BaseNodeVisitor implements Twig_NodeVisitorInterface
28
  return $this->doEnterNode($node, $env);
29
  }
30
 
31
- /**
32
- * {@inheritdoc}
33
- */
34
  final public function leaveNode(Twig_NodeInterface $node, Twig_Environment $env)
35
  {
36
  if (!$node instanceof Twig_Node) {
16
  */
17
  abstract class Twig_BaseNodeVisitor implements Twig_NodeVisitorInterface
18
  {
 
 
 
19
  final public function enterNode(Twig_NodeInterface $node, Twig_Environment $env)
20
  {
21
  if (!$node instanceof Twig_Node) {
25
  return $this->doEnterNode($node, $env);
26
  }
27
 
 
 
 
28
  final public function leaveNode(Twig_NodeInterface $node, Twig_Environment $env)
29
  {
30
  if (!$node instanceof Twig_Node) {
library/twig/twig/lib/Twig/Cache/Filesystem.php CHANGED
@@ -3,7 +3,7 @@
3
  /*
4
  * This file is part of Twig.
5
  *
6
- * (c) 2015 Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
@@ -31,9 +31,6 @@ class Twig_Cache_Filesystem implements Twig_CacheInterface
31
  $this->options = $options;
32
  }
33
 
34
- /**
35
- * {@inheritdoc}
36
- */
37
  public function generateKey($name, $className)
38
  {
39
  $hash = hash('sha256', $className);
@@ -41,9 +38,6 @@ class Twig_Cache_Filesystem implements Twig_CacheInterface
41
  return $this->directory.$hash[0].$hash[1].'/'.$hash.'.php';
42
  }
43
 
44
- /**
45
- * {@inheritdoc}
46
- */
47
  public function load($key)
48
  {
49
  if (file_exists($key)) {
@@ -51,9 +45,6 @@ class Twig_Cache_Filesystem implements Twig_CacheInterface
51
  }
52
  }
53
 
54
- /**
55
- * {@inheritdoc}
56
- */
57
  public function write($key, $content)
58
  {
59
  $dir = dirname($key);
@@ -84,9 +75,6 @@ class Twig_Cache_Filesystem implements Twig_CacheInterface
84
  throw new RuntimeException(sprintf('Failed to write cache file "%s".', $key));
85
  }
86
 
87
- /**
88
- * {@inheritdoc}
89
- */
90
  public function getTimestamp($key)
91
  {
92
  if (!file_exists($key)) {
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
31
  $this->options = $options;
32
  }
33
 
 
 
 
34
  public function generateKey($name, $className)
35
  {
36
  $hash = hash('sha256', $className);
38
  return $this->directory.$hash[0].$hash[1].'/'.$hash.'.php';
39
  }
40
 
 
 
 
41
  public function load($key)
42
  {
43
  if (file_exists($key)) {
45
  }
46
  }
47
 
 
 
 
48
  public function write($key, $content)
49
  {
50
  $dir = dirname($key);
75
  throw new RuntimeException(sprintf('Failed to write cache file "%s".', $key));
76
  }
77
 
 
 
 
78
  public function getTimestamp($key)
79
  {
80
  if (!file_exists($key)) {
library/twig/twig/lib/Twig/Cache/Null.php CHANGED
@@ -3,7 +3,7 @@
3
  /*
4
  * This file is part of Twig.
5
  *
6
- * (c) 2015 Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
@@ -12,35 +12,25 @@
12
  /**
13
  * Implements a no-cache strategy.
14
  *
 
 
15
  * @author Fabien Potencier <fabien@symfony.com>
16
  */
17
  class Twig_Cache_Null implements Twig_CacheInterface
18
  {
19
- /**
20
- * {@inheritdoc}
21
- */
22
  public function generateKey($name, $className)
23
  {
24
  return '';
25
  }
26
 
27
- /**
28
- * {@inheritdoc}
29
- */
30
  public function write($key, $content)
31
  {
32
  }
33
 
34
- /**
35
- * {@inheritdoc}
36
- */
37
  public function load($key)
38
  {
39
  }
40
 
41
- /**
42
- * {@inheritdoc}
43
- */
44
  public function getTimestamp($key)
45
  {
46
  return 0;
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
12
  /**
13
  * Implements a no-cache strategy.
14
  *
15
+ * @final
16
+ *
17
  * @author Fabien Potencier <fabien@symfony.com>
18
  */
19
  class Twig_Cache_Null implements Twig_CacheInterface
20
  {
 
 
 
21
  public function generateKey($name, $className)
22
  {
23
  return '';
24
  }
25
 
 
 
 
26
  public function write($key, $content)
27
  {
28
  }
29
 
 
 
 
30
  public function load($key)
31
  {
32
  }
33
 
 
 
 
34
  public function getTimestamp($key)
35
  {
36
  return 0;
library/twig/twig/lib/Twig/CacheInterface.php CHANGED
@@ -3,7 +3,7 @@
3
  /*
4
  * This file is part of Twig.
5
  *
6
- * (c) 2015 Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Compiler.php CHANGED
@@ -3,8 +3,8 @@
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.
@@ -216,6 +216,8 @@ class Twig_Compiler implements Twig_CompilerInterface
216
  // mb_substr_count() replaces substr_count()
217
  // but they have different signatures!
218
  if (((int) ini_get('mbstring.func_overload')) & 2) {
 
 
219
  // this is much slower than the "right" version
220
  $this->sourceLine += mb_substr_count(mb_substr($this->source, $this->sourceOffset), "\n");
221
  } else {
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
+ * (c) Armin Ronacher
8
  *
9
  * For the full copyright and license information, please view the LICENSE
10
  * file that was distributed with this source code.
216
  // mb_substr_count() replaces substr_count()
217
  // but they have different signatures!
218
  if (((int) ini_get('mbstring.func_overload')) & 2) {
219
+ @trigger_error('Support for having "mbstring.func_overload" different from 0 is deprecated version 1.29 and will be removed in 2.0.', E_USER_DEPRECATED);
220
+
221
  // this is much slower than the "right" version
222
  $this->sourceLine += mb_substr_count(mb_substr($this->source, $this->sourceOffset), "\n");
223
  } else {
library/twig/twig/lib/Twig/CompilerInterface.php CHANGED
@@ -3,7 +3,7 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Environment.php CHANGED
@@ -3,7 +3,7 @@
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.
@@ -16,11 +16,11 @@
16
  */
17
  class Twig_Environment
18
  {
19
- const VERSION = '1.28.2';
20
- const VERSION_ID = 12802;
21
  const MAJOR_VERSION = 1;
22
- const MINOR_VERSION = 28;
23
- const RELEASE_VERSION = 2;
24
  const EXTRA_VERSION = '';
25
 
26
  protected $charset;
@@ -408,14 +408,18 @@ class Twig_Environment
408
  *
409
  * @return Twig_TemplateInterface A template instance representing the given template name
410
  *
411
- * @throws Twig_Error_Loader When the template cannot be found
412
- * @throws Twig_Error_Syntax When an error occurred during compilation
 
413
  *
414
  * @internal
415
  */
416
  public function loadTemplate($name, $index = null)
417
  {
418
- $cls = $this->getTemplateClass($name, $index);
 
 
 
419
 
420
  if (isset($this->loadedTemplates[$cls])) {
421
  return $this->loadedTemplates[$cls];
@@ -425,7 +429,7 @@ class Twig_Environment
425
  if ($this->bcGetCacheFilename) {
426
  $key = $this->getCacheFilename($name);
427
  } else {
428
- $key = $this->cache->generateKey($name, $cls);
429
  }
430
 
431
  if (!$this->isAutoReload() || $this->isTemplateFresh($name, $this->cache->getTimestamp($key))) {
@@ -449,7 +453,7 @@ class Twig_Environment
449
  $this->cache->load($key);
450
  }
451
 
452
- if (!class_exists($cls, false)) {
453
  /* Last line of defense if either $this->bcWriteCacheFile was used,
454
  * $this->cache is implemented as a no-op or we have a race condition
455
  * where the cache was cleared between the above calls to write to and load from
@@ -458,6 +462,10 @@ class Twig_Environment
458
  eval('?>'.$content);
459
  }
460
  }
 
 
 
 
461
  }
462
 
463
  if (!$this->runtimeInitialized) {
@@ -741,10 +749,10 @@ class Twig_Environment
741
  try {
742
  return $this->compile($this->parse($this->tokenize($source)));
743
  } catch (Twig_Error $e) {
744
- $e->setTemplateName($source->getName());
745
  throw $e;
746
  } catch (Exception $e) {
747
- throw new Twig_Error_Syntax(sprintf('An exception has been thrown during the compilation of a template ("%s").', $e->getMessage()), -1, $source->getName(), $e);
748
  }
749
  }
750
 
@@ -831,7 +839,7 @@ class Twig_Environment
831
  return true;
832
  }
833
 
834
- return isset($this->extensionsByClass[ltrim($class, '\\')]);
835
  }
836
 
837
  /**
@@ -1439,7 +1447,6 @@ class Twig_Environment
1439
  return;
1440
  }
1441
 
1442
- $this->extensionInitialized = true;
1443
  $this->parsers = new Twig_TokenParserBroker(array(), array(), false);
1444
  $this->filters = array();
1445
  $this->functions = array();
@@ -1452,6 +1459,8 @@ class Twig_Environment
1452
  $this->initExtension($extension);
1453
  }
1454
  $this->initExtension($this->staging);
 
 
1455
  }
1456
 
1457
  /**
@@ -1512,8 +1521,12 @@ class Twig_Environment
1512
 
1513
  // operators
1514
  if ($operators = $extension->getOperators()) {
 
 
 
 
1515
  if (2 !== count($operators)) {
1516
- throw new InvalidArgumentException(sprintf('"%s::getOperators()" does not return a valid operators array.', get_class($extension)));
1517
  }
1518
 
1519
  $this->unaryOperators = array_merge($this->unaryOperators, $operators[0]);
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
16
  */
17
  class Twig_Environment
18
  {
19
+ const VERSION = '1.31.0';
20
+ const VERSION_ID = 13100;
21
  const MAJOR_VERSION = 1;
22
+ const MINOR_VERSION = 31;
23
+ const RELEASE_VERSION = 0;
24
  const EXTRA_VERSION = '';
25
 
26
  protected $charset;
408
  *
409
  * @return Twig_TemplateInterface A template instance representing the given template name
410
  *
411
+ * @throws Twig_Error_Loader When the template cannot be found
412
+ * @throws Twig_Error_Runtime When a previously generated cache is corrupted
413
+ * @throws Twig_Error_Syntax When an error occurred during compilation
414
  *
415
  * @internal
416
  */
417
  public function loadTemplate($name, $index = null)
418
  {
419
+ $cls = $mainCls = $this->getTemplateClass($name);
420
+ if (null !== $index) {
421
+ $cls .= '_'.$index;
422
+ }
423
 
424
  if (isset($this->loadedTemplates[$cls])) {
425
  return $this->loadedTemplates[$cls];
429
  if ($this->bcGetCacheFilename) {
430
  $key = $this->getCacheFilename($name);
431
  } else {
432
+ $key = $this->cache->generateKey($name, $mainCls);
433
  }
434
 
435
  if (!$this->isAutoReload() || $this->isTemplateFresh($name, $this->cache->getTimestamp($key))) {
453
  $this->cache->load($key);
454
  }
455
 
456
+ if (!class_exists($mainCls, false)) {
457
  /* Last line of defense if either $this->bcWriteCacheFile was used,
458
  * $this->cache is implemented as a no-op or we have a race condition
459
  * where the cache was cleared between the above calls to write to and load from
462
  eval('?>'.$content);
463
  }
464
  }
465
+
466
+ if (!class_exists($cls, false)) {
467
+ throw new Twig_Error_Runtime(sprintf('Failed to load Twig template "%s", index "%s": cache is corrupted.', $name, $index), -1, $source);
468
+ }
469
  }
470
 
471
  if (!$this->runtimeInitialized) {
749
  try {
750
  return $this->compile($this->parse($this->tokenize($source)));
751
  } catch (Twig_Error $e) {
752
+ $e->setSourceContext($source);
753
  throw $e;
754
  } catch (Exception $e) {
755
+ throw new Twig_Error_Syntax(sprintf('An exception has been thrown during the compilation of a template ("%s").', $e->getMessage()), -1, $source, $e);
756
  }
757
  }
758
 
839
  return true;
840
  }
841
 
842
+ return isset($this->extensionsByClass[$class]);
843
  }
844
 
845
  /**
1447
  return;
1448
  }
1449
 
 
1450
  $this->parsers = new Twig_TokenParserBroker(array(), array(), false);
1451
  $this->filters = array();
1452
  $this->functions = array();
1459
  $this->initExtension($extension);
1460
  }
1461
  $this->initExtension($this->staging);
1462
+ // Done at the end only, so that an exception during initialization does not mark the environment as initialized when catching the exception
1463
+ $this->extensionInitialized = true;
1464
  }
1465
 
1466
  /**
1521
 
1522
  // operators
1523
  if ($operators = $extension->getOperators()) {
1524
+ if (!is_array($operators)) {
1525
+ throw new InvalidArgumentException(sprintf('"%s::getOperators()" must return an array with operators, got "%s".', get_class($extension), is_object($operators) ? get_class($operators) : gettype($operators).(is_resource($operators) ? '' : '#'.$operators)));
1526
+ }
1527
+
1528
  if (2 !== count($operators)) {
1529
+ throw new InvalidArgumentException(sprintf('"%s::getOperators()" must return an array of 2 elements, got %d.', get_class($extension), count($operators)));
1530
  }
1531
 
1532
  $this->unaryOperators = array_merge($this->unaryOperators, $operators[0]);
library/twig/twig/lib/Twig/Error.php CHANGED
@@ -3,7 +3,7 @@
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.
@@ -39,6 +39,9 @@ class Twig_Error extends Exception
39
  protected $rawMessage;
40
  protected $previous;
41
 
 
 
 
42
  /**
43
  * Constructor.
44
  *
@@ -51,13 +54,23 @@ class Twig_Error extends Exception
51
  *
52
  * By default, automatic guessing is enabled.
53
  *
54
- * @param string $message The error message
55
- * @param int $lineno The template line where the error occurred
56
- * @param string $name The template logical name where the error occurred
57
- * @param Exception $previous The previous exception
58
  */
59
- public function __construct($message, $lineno = -1, $name = null, Exception $previous = null)
60
  {
 
 
 
 
 
 
 
 
 
 
61
  if (PHP_VERSION_ID < 50300) {
62
  $this->previous = $previous;
63
  parent::__construct('');
@@ -68,7 +81,7 @@ class Twig_Error extends Exception
68
  $this->lineno = $lineno;
69
  $this->filename = $name;
70
 
71
- if (-1 === $lineno || null === $name) {
72
  $this->guessTemplateInfo();
73
  }
74
 
@@ -92,11 +105,11 @@ class Twig_Error extends Exception
92
  *
93
  * @return string The name
94
  *
95
- * @deprecated since 1.27 (to be removed in 2.0). Use getTemplateName() instead.
96
  */
97
  public function getTemplateFile()
98
  {
99
- @trigger_error(sprintf('The "%s" method is deprecated since version 1.27 and will be removed in 2.0. Use getTemplateName() instead.', __METHOD__), E_USER_DEPRECATED);
100
 
101
  return $this->filename;
102
  }
@@ -106,11 +119,11 @@ class Twig_Error extends Exception
106
  *
107
  * @param string $name The name
108
  *
109
- * @deprecated since 1.27 (to be removed in 2.0). Use setTemplateName() instead.
110
  */
111
  public function setTemplateFile($name)
112
  {
113
- @trigger_error(sprintf('The "%s" method is deprecated since version 1.27 and will be removed in 2.0. Use setTemplateName() instead.', __METHOD__), E_USER_DEPRECATED);
114
 
115
  $this->filename = $name;
116
 
@@ -121,9 +134,13 @@ class Twig_Error extends Exception
121
  * Gets the logical name where the error occurred.
122
  *
123
  * @return string The name
 
 
124
  */
125
  public function getTemplateName()
126
  {
 
 
127
  return $this->filename;
128
  }
129
 
@@ -131,10 +148,15 @@ class Twig_Error extends Exception
131
  * Sets the logical name where the error occurred.
132
  *
133
  * @param string $name The name
 
 
134
  */
135
  public function setTemplateName($name)
136
  {
 
 
137
  $this->filename = $name;
 
138
 
139
  $this->updateRepr();
140
  }
@@ -161,6 +183,32 @@ class Twig_Error extends Exception
161
  $this->updateRepr();
162
  }
163
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
164
  public function guess()
165
  {
166
  $this->guessTemplateInfo();
@@ -199,6 +247,13 @@ class Twig_Error extends Exception
199
  {
200
  $this->message = $this->rawMessage;
201
 
 
 
 
 
 
 
 
202
  $dot = false;
203
  if ('.' === substr($this->message, -1)) {
204
  $this->message = substr($this->message, 0, -1);
@@ -263,6 +318,13 @@ class Twig_Error extends Exception
263
  $this->filename = $template->getTemplateName();
264
  }
265
 
 
 
 
 
 
 
 
266
  if (null === $template || $this->lineno > -1) {
267
  return;
268
  }
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
39
  protected $rawMessage;
40
  protected $previous;
41
 
42
+ private $sourcePath;
43
+ private $sourceCode;
44
+
45
  /**
46
  * Constructor.
47
  *
54
  *
55
  * By default, automatic guessing is enabled.
56
  *
57
+ * @param string $message The error message
58
+ * @param int $lineno The template line where the error occurred
59
+ * @param Twig_Source|string|null $source The source context where the error occurred
60
+ * @param Exception $previous The previous exception
61
  */
62
+ public function __construct($message, $lineno = -1, $source = null, Exception $previous = null)
63
  {
64
+ if (null === $source) {
65
+ $name = null;
66
+ } elseif (!$source instanceof Twig_Source) {
67
+ // for compat with the Twig C ext., passing the template name as string is accepted
68
+ $name = $source;
69
+ } else {
70
+ $name = $source->getName();
71
+ $this->sourceCode = $source->getCode();
72
+ $this->sourcePath = $source->getPath();
73
+ }
74
  if (PHP_VERSION_ID < 50300) {
75
  $this->previous = $previous;
76
  parent::__construct('');
81
  $this->lineno = $lineno;
82
  $this->filename = $name;
83
 
84
+ if (-1 === $lineno || null === $name || null === $this->sourcePath) {
85
  $this->guessTemplateInfo();
86
  }
87
 
105
  *
106
  * @return string The name
107
  *
108
+ * @deprecated since 1.27 (to be removed in 2.0). Use getSourceContext() instead.
109
  */
110
  public function getTemplateFile()
111
  {
112
+ @trigger_error(sprintf('The "%s" method is deprecated since version 1.27 and will be removed in 2.0. Use getSourceContext() instead.', __METHOD__), E_USER_DEPRECATED);
113
 
114
  return $this->filename;
115
  }
119
  *
120
  * @param string $name The name
121
  *
122
+ * @deprecated since 1.27 (to be removed in 2.0). Use setSourceContext() instead.
123
  */
124
  public function setTemplateFile($name)
125
  {
126
+ @trigger_error(sprintf('The "%s" method is deprecated since version 1.27 and will be removed in 2.0. Use setSourceContext() instead.', __METHOD__), E_USER_DEPRECATED);
127
 
128
  $this->filename = $name;
129
 
134
  * Gets the logical name where the error occurred.
135
  *
136
  * @return string The name
137
+ *
138
+ * @deprecated since 1.29 (to be removed in 2.0). Use getSourceContext() instead.
139
  */
140
  public function getTemplateName()
141
  {
142
+ @trigger_error(sprintf('The "%s" method is deprecated since version 1.29 and will be removed in 2.0. Use getSourceContext() instead.', __METHOD__), E_USER_DEPRECATED);
143
+
144
  return $this->filename;
145
  }
146
 
148
  * Sets the logical name where the error occurred.
149
  *
150
  * @param string $name The name
151
+ *
152
+ * @deprecated since 1.29 (to be removed in 2.0). Use setSourceContext() instead.
153
  */
154
  public function setTemplateName($name)
155
  {
156
+ @trigger_error(sprintf('The "%s" method is deprecated since version 1.29 and will be removed in 2.0. Use setSourceContext() instead.', __METHOD__), E_USER_DEPRECATED);
157
+
158
  $this->filename = $name;
159
+ $this->sourceCode = $this->sourcePath = null;
160
 
161
  $this->updateRepr();
162
  }
183
  $this->updateRepr();
184
  }
185
 
186
+ /**
187
+ * Gets the source context of the Twig template where the error occurred.
188
+ *
189
+ * @return Twig_Source|null
190
+ */
191
+ public function getSourceContext()
192
+ {
193
+ return $this->filename ? new Twig_Source($this->sourceCode, $this->filename, $this->sourcePath) : null;
194
+ }
195
+
196
+ /**
197
+ * Sets the source context of the Twig template where the error occurred.
198
+ */
199
+ public function setSourceContext(Twig_Source $source = null)
200
+ {
201
+ if (null === $source) {
202
+ $this->sourceCode = $this->filename = $this->sourcePath = null;
203
+ } else {
204
+ $this->sourceCode = $source->getCode();
205
+ $this->filename = $source->getName();
206
+ $this->sourcePath = $source->getPath();
207
+ }
208
+
209
+ $this->updateRepr();
210
+ }
211
+
212
  public function guess()
213
  {
214
  $this->guessTemplateInfo();
247
  {
248
  $this->message = $this->rawMessage;
249
 
250
+ if ($this->sourcePath && $this->lineno > 0) {
251
+ $this->file = $this->sourcePath;
252
+ $this->line = $this->lineno;
253
+
254
+ return;
255
+ }
256
+
257
  $dot = false;
258
  if ('.' === substr($this->message, -1)) {
259
  $this->message = substr($this->message, 0, -1);
318
  $this->filename = $template->getTemplateName();
319
  }
320
 
321
+ // update template path if any
322
+ if (null !== $template && null === $this->sourcePath) {
323
+ $src = $template->getSourceContext();
324
+ $this->sourceCode = $src->getCode();
325
+ $this->sourcePath = $src->getPath();
326
+ }
327
+
328
  if (null === $template || $this->lineno > -1) {
329
  return;
330
  }
library/twig/twig/lib/Twig/Error/Loader.php CHANGED
@@ -3,7 +3,7 @@
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.
@@ -24,8 +24,15 @@
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
  }
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
24
  */
25
  class Twig_Error_Loader extends Twig_Error
26
  {
27
+ public function __construct($message, $lineno = -1, $source = null, Exception $previous = null)
28
  {
29
+ if (PHP_VERSION_ID < 50300) {
30
+ $this->previous = $previous;
31
+ Exception::__construct('');
32
+ } else {
33
+ Exception::__construct('', 0, $previous);
34
+ }
35
+ $this->appendMessage($message);
36
+ $this->setTemplateLine(false);
37
  }
38
  }
library/twig/twig/lib/Twig/Error/Runtime.php CHANGED
@@ -3,8 +3,8 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
+ * (c) Armin Ronacher
8
  *
9
  * For the full copyright and license information, please view the LICENSE
10
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Error/Syntax.php CHANGED
@@ -3,8 +3,8 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
+ * (c) Armin Ronacher
8
  *
9
  * For the full copyright and license information, please view the LICENSE
10
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/ExistsLoaderInterface.php CHANGED
@@ -3,7 +3,7 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/ExpressionParser.php CHANGED
@@ -3,8 +3,8 @@
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.
@@ -33,7 +33,7 @@ class Twig_ExpressionParser
33
 
34
  private $env;
35
 
36
- public function __construct(Twig_Parser $parser, Twig_Environment $env = null)
37
  {
38
  $this->parser = $parser;
39
 
@@ -189,7 +189,7 @@ class Twig_ExpressionParser
189
  $negClass = 'Twig_Node_Expression_Unary_Neg';
190
  $posClass = 'Twig_Node_Expression_Unary_Pos';
191
  if (!(in_array($ref->getName(), array($negClass, $posClass)) || $ref->isSubclassOf($negClass) || $ref->isSubclassOf($posClass))) {
192
- throw new Twig_Error_Syntax(sprintf('Unexpected unary operator "%s".', $token->getValue()), $token->getLine(), $this->parser->getStream()->getSourceContext()->getName());
193
  }
194
 
195
  $this->parser->getStream()->next();
@@ -205,7 +205,7 @@ class Twig_ExpressionParser
205
  } elseif ($token->test(Twig_Token::PUNCTUATION_TYPE, '{')) {
206
  $node = $this->parseHashExpression();
207
  } else {
208
- throw new Twig_Error_Syntax(sprintf('Unexpected token "%s" of value "%s".', Twig_Token::typeToEnglish($token->getType()), $token->getValue()), $token->getLine(), $this->parser->getStream()->getSourceContext()->getName());
209
  }
210
  }
211
 
@@ -296,7 +296,7 @@ class Twig_ExpressionParser
296
  } else {
297
  $current = $stream->getCurrent();
298
 
299
- 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(), $stream->getSourceContext()->getName());
300
  }
301
 
302
  $stream->expect(Twig_Token::PUNCTUATION_TYPE, ':', 'A hash key must be followed by a colon (:)');
@@ -335,25 +335,25 @@ class Twig_ExpressionParser
335
  case 'parent':
336
  $this->parseArguments();
337
  if (!count($this->parser->getBlockStack())) {
338
- throw new Twig_Error_Syntax('Calling "parent" outside a block is forbidden.', $line, $this->parser->getStream()->getSourceContext()->getName());
339
  }
340
 
341
  if (!$this->parser->getParent() && !$this->parser->hasTraits()) {
342
- throw new Twig_Error_Syntax('Calling "parent" on a template that does not extend nor "use" another template is forbidden.', $line, $this->parser->getStream()->getSourceContext()->getName());
343
  }
344
 
345
  return new Twig_Node_Expression_Parent($this->parser->peekBlockStack(), $line);
346
  case 'block':
347
  $args = $this->parseArguments();
348
  if (count($args) < 1) {
349
- throw new Twig_Error_Syntax('The "block" function takes one argument (the block name).', $line, $this->parser->getStream()->getSourceContext()->getName());
350
  }
351
 
352
  return new Twig_Node_Expression_BlockReference($args->getNode(0), count($args) > 1 ? $args->getNode(1) : null, $line);
353
  case 'attribute':
354
  $args = $this->parseArguments();
355
  if (count($args) < 2) {
356
- throw new Twig_Error_Syntax('The "attribute" function takes at least two arguments (the variable and the attributes).', $line, $this->parser->getStream()->getSourceContext()->getName());
357
  }
358
 
359
  return new Twig_Node_Expression_GetAttr($args->getNode(0), $args->getNode(1), count($args) > 2 ? $args->getNode(2) : null, Twig_Template::ANY_CALL, $line);
@@ -402,18 +402,18 @@ class Twig_ExpressionParser
402
  }
403
  }
404
  } else {
405
- throw new Twig_Error_Syntax('Expected name or number.', $lineno, $stream->getSourceContext()->getName());
406
  }
407
 
408
  if ($node instanceof Twig_Node_Expression_Name && null !== $this->parser->getImportedSymbol('template', $node->getAttribute('name'))) {
409
  if (!$arg instanceof Twig_Node_Expression_Constant) {
410
- throw new Twig_Error_Syntax(sprintf('Dynamic macro names are not supported (called on "%s").', $node->getAttribute('name')), $token->getLine(), $stream->getSourceContext()->getName());
411
  }
412
 
413
  $name = $arg->getAttribute('value');
414
 
415
  if ($this->parser->isReservedMacroName($name)) {
416
- throw new Twig_Error_Syntax(sprintf('"%s" cannot be called as macro as it is a reserved keyword.', $name), $token->getLine(), $stream->getSourceContext()->getName());
417
  }
418
 
419
  $node = new Twig_Node_Expression_MethodCall($node, 'get'.$name, $arguments, $lineno);
@@ -523,7 +523,7 @@ class Twig_ExpressionParser
523
  $name = null;
524
  if ($namedArguments && $token = $stream->nextIf(Twig_Token::OPERATOR_TYPE, '=')) {
525
  if (!$value instanceof Twig_Node_Expression_Name) {
526
- throw new Twig_Error_Syntax(sprintf('A parameter name must be a string, "%s" given.', get_class($value)), $token->getLine(), $stream->getSourceContext()->getName());
527
  }
528
  $name = $value->getAttribute('name');
529
 
@@ -531,7 +531,7 @@ class Twig_ExpressionParser
531
  $value = $this->parsePrimaryExpression();
532
 
533
  if (!$this->checkConstantExpression($value)) {
534
- 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(), $stream->getSourceContext()->getName());
535
  }
536
  } else {
537
  $value = $this->parseExpression();
@@ -565,7 +565,7 @@ class Twig_ExpressionParser
565
  $token = $stream->expect(Twig_Token::NAME_TYPE, null, 'Only variables can be assigned to');
566
  $value = $token->getValue();
567
  if (in_array(strtolower($value), array('true', 'false', 'none', 'null'))) {
568
- throw new Twig_Error_Syntax(sprintf('You cannot assign a value to "%s".', $value), $token->getLine(), $stream->getSourceContext()->getName());
569
  }
570
  $targets[] = new Twig_Node_Expression_AssignName($value, $token->getLine());
571
 
@@ -629,7 +629,7 @@ class Twig_ExpressionParser
629
  }
630
  }
631
 
632
- $e = new Twig_Error_Syntax(sprintf('Unknown "%s" test.', $name), $line, $stream->getSourceContext()->getName());
633
  $e->addSuggestions($name, array_keys($this->env->getTests()));
634
 
635
  throw $e;
@@ -646,7 +646,8 @@ class Twig_ExpressionParser
646
  if ($test->getAlternative()) {
647
  $message .= sprintf('. Use "%s" instead', $test->getAlternative());
648
  }
649
- $message .= sprintf(' in %s at line %d.', $stream->getSourceContext()->getName(), $stream->getCurrent()->getLine());
 
650
 
651
  @trigger_error($message, E_USER_DEPRECATED);
652
  }
@@ -661,7 +662,7 @@ class Twig_ExpressionParser
661
  protected function getFunctionNodeClass($name, $line)
662
  {
663
  if (false === $function = $this->env->getFunction($name)) {
664
- $e = new Twig_Error_Syntax(sprintf('Unknown "%s" function.', $name), $line, $this->parser->getStream()->getSourceContext()->getName());
665
  $e->addSuggestions($name, array_keys($this->env->getFunctions()));
666
 
667
  throw $e;
@@ -675,7 +676,8 @@ class Twig_ExpressionParser
675
  if ($function->getAlternative()) {
676
  $message .= sprintf('. Use "%s" instead', $function->getAlternative());
677
  }
678
- $message .= sprintf(' in %s at line %d.', $this->parser->getStream()->getSourceContext()->getName(), $line);
 
679
 
680
  @trigger_error($message, E_USER_DEPRECATED);
681
  }
@@ -690,7 +692,7 @@ class Twig_ExpressionParser
690
  protected function getFilterNodeClass($name, $line)
691
  {
692
  if (false === $filter = $this->env->getFilter($name)) {
693
- $e = new Twig_Error_Syntax(sprintf('Unknown "%s" filter.', $name), $line, $this->parser->getStream()->getSourceContext()->getName());
694
  $e->addSuggestions($name, array_keys($this->env->getFilters()));
695
 
696
  throw $e;
@@ -704,7 +706,8 @@ class Twig_ExpressionParser
704
  if ($filter->getAlternative()) {
705
  $message .= sprintf('. Use "%s" instead', $filter->getAlternative());
706
  }
707
- $message .= sprintf(' in %s at line %d.', $this->parser->getStream()->getSourceContext()->getName(), $line);
 
708
 
709
  @trigger_error($message, E_USER_DEPRECATED);
710
  }
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
+ * (c) Armin Ronacher
8
  *
9
  * For the full copyright and license information, please view the LICENSE
10
  * file that was distributed with this source code.
33
 
34
  private $env;
35
 
36
+ public function __construct(Twig_Parser $parser, $env = null)
37
  {
38
  $this->parser = $parser;
39
 
189
  $negClass = 'Twig_Node_Expression_Unary_Neg';
190
  $posClass = 'Twig_Node_Expression_Unary_Pos';
191
  if (!(in_array($ref->getName(), array($negClass, $posClass)) || $ref->isSubclassOf($negClass) || $ref->isSubclassOf($posClass))) {
192
+ throw new Twig_Error_Syntax(sprintf('Unexpected unary operator "%s".', $token->getValue()), $token->getLine(), $this->parser->getStream()->getSourceContext());
193
  }
194
 
195
  $this->parser->getStream()->next();
205
  } elseif ($token->test(Twig_Token::PUNCTUATION_TYPE, '{')) {
206
  $node = $this->parseHashExpression();
207
  } else {
208
+ throw new Twig_Error_Syntax(sprintf('Unexpected token "%s" of value "%s".', Twig_Token::typeToEnglish($token->getType()), $token->getValue()), $token->getLine(), $this->parser->getStream()->getSourceContext());
209
  }
210
  }
211
 
296
  } else {
297
  $current = $stream->getCurrent();
298
 
299
+ 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(), $stream->getSourceContext());
300
  }
301
 
302
  $stream->expect(Twig_Token::PUNCTUATION_TYPE, ':', 'A hash key must be followed by a colon (:)');
335
  case 'parent':
336
  $this->parseArguments();
337
  if (!count($this->parser->getBlockStack())) {
338
+ throw new Twig_Error_Syntax('Calling "parent" outside a block is forbidden.', $line, $this->parser->getStream()->getSourceContext());
339
  }
340
 
341
  if (!$this->parser->getParent() && !$this->parser->hasTraits()) {
342
+ throw new Twig_Error_Syntax('Calling "parent" on a template that does not extend nor "use" another template is forbidden.', $line, $this->parser->getStream()->getSourceContext());
343
  }
344
 
345
  return new Twig_Node_Expression_Parent($this->parser->peekBlockStack(), $line);
346
  case 'block':
347
  $args = $this->parseArguments();
348
  if (count($args) < 1) {
349
+ throw new Twig_Error_Syntax('The "block" function takes one argument (the block name).', $line, $this->parser->getStream()->getSourceContext());
350
  }
351
 
352
  return new Twig_Node_Expression_BlockReference($args->getNode(0), count($args) > 1 ? $args->getNode(1) : null, $line);
353
  case 'attribute':
354
  $args = $this->parseArguments();
355
  if (count($args) < 2) {
356
+ throw new Twig_Error_Syntax('The "attribute" function takes at least two arguments (the variable and the attributes).', $line, $this->parser->getStream()->getSourceContext());
357
  }
358
 
359
  return new Twig_Node_Expression_GetAttr($args->getNode(0), $args->getNode(1), count($args) > 2 ? $args->getNode(2) : null, Twig_Template::ANY_CALL, $line);
402
  }
403
  }
404
  } else {
405
+ throw new Twig_Error_Syntax('Expected name or number.', $lineno, $stream->getSourceContext());
406
  }
407
 
408
  if ($node instanceof Twig_Node_Expression_Name && null !== $this->parser->getImportedSymbol('template', $node->getAttribute('name'))) {
409
  if (!$arg instanceof Twig_Node_Expression_Constant) {
410
+ throw new Twig_Error_Syntax(sprintf('Dynamic macro names are not supported (called on "%s").', $node->getAttribute('name')), $token->getLine(), $stream->getSourceContext());
411
  }
412
 
413
  $name = $arg->getAttribute('value');
414
 
415
  if ($this->parser->isReservedMacroName($name)) {
416
+ throw new Twig_Error_Syntax(sprintf('"%s" cannot be called as macro as it is a reserved keyword.', $name), $token->getLine(), $stream->getSourceContext());
417
  }
418
 
419
  $node = new Twig_Node_Expression_MethodCall($node, 'get'.$name, $arguments, $lineno);
523
  $name = null;
524
  if ($namedArguments && $token = $stream->nextIf(Twig_Token::OPERATOR_TYPE, '=')) {
525
  if (!$value instanceof Twig_Node_Expression_Name) {
526
+ throw new Twig_Error_Syntax(sprintf('A parameter name must be a string, "%s" given.', get_class($value)), $token->getLine(), $stream->getSourceContext());
527
  }
528
  $name = $value->getAttribute('name');
529
 
531
  $value = $this->parsePrimaryExpression();
532
 
533
  if (!$this->checkConstantExpression($value)) {
534
+ 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(), $stream->getSourceContext());
535
  }
536
  } else {
537
  $value = $this->parseExpression();
565
  $token = $stream->expect(Twig_Token::NAME_TYPE, null, 'Only variables can be assigned to');
566
  $value = $token->getValue();
567
  if (in_array(strtolower($value), array('true', 'false', 'none', 'null'))) {
568
+ throw new Twig_Error_Syntax(sprintf('You cannot assign a value to "%s".', $value), $token->getLine(), $stream->getSourceContext());
569
  }
570
  $targets[] = new Twig_Node_Expression_AssignName($value, $token->getLine());
571
 
629
  }
630
  }
631
 
632
+ $e = new Twig_Error_Syntax(sprintf('Unknown "%s" test.', $name), $line, $stream->getSourceContext());
633
  $e->addSuggestions($name, array_keys($this->env->getTests()));
634
 
635
  throw $e;
646
  if ($test->getAlternative()) {
647
  $message .= sprintf('. Use "%s" instead', $test->getAlternative());
648
  }
649
+ $src = $stream->getSourceContext();
650
+ $message .= sprintf(' in %s at line %d.', $src->getPath() ? $src->getPath() : $src->getName(), $stream->getCurrent()->getLine());
651
 
652
  @trigger_error($message, E_USER_DEPRECATED);
653
  }
662
  protected function getFunctionNodeClass($name, $line)
663
  {
664
  if (false === $function = $this->env->getFunction($name)) {
665
+ $e = new Twig_Error_Syntax(sprintf('Unknown "%s" function.', $name), $line, $this->parser->getStream()->getSourceContext());
666
  $e->addSuggestions($name, array_keys($this->env->getFunctions()));
667
 
668
  throw $e;
676
  if ($function->getAlternative()) {
677
  $message .= sprintf('. Use "%s" instead', $function->getAlternative());
678
  }
679
+ $src = $this->parser->getStream()->getSourceContext();
680
+ $message .= sprintf(' in %s at line %d.', $src->getPath() ? $src->getPath() : $src->getName(), $line);
681
 
682
  @trigger_error($message, E_USER_DEPRECATED);
683
  }
692
  protected function getFilterNodeClass($name, $line)
693
  {
694
  if (false === $filter = $this->env->getFilter($name)) {
695
+ $e = new Twig_Error_Syntax(sprintf('Unknown "%s" filter.', $name), $line, $this->parser->getStream()->getSourceContext());
696
  $e->addSuggestions($name, array_keys($this->env->getFilters()));
697
 
698
  throw $e;
706
  if ($filter->getAlternative()) {
707
  $message .= sprintf('. Use "%s" instead', $filter->getAlternative());
708
  }
709
+ $src = $this->parser->getStream()->getSourceContext();
710
+ $message .= sprintf(' in %s at line %d.', $src->getPath() ? $src->getPath() : $src->getName(), $line);
711
 
712
  @trigger_error($message, E_USER_DEPRECATED);
713
  }
library/twig/twig/lib/Twig/Extension.php CHANGED
@@ -3,7 +3,7 @@
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.
@@ -11,65 +11,43 @@
11
  abstract class Twig_Extension implements Twig_ExtensionInterface
12
  {
13
  /**
14
- * {@inheritdoc}
15
- *
16
  * @deprecated since 1.23 (to be removed in 2.0), implement Twig_Extension_InitRuntimeInterface instead
17
  */
18
  public function initRuntime(Twig_Environment $environment)
19
  {
20
  }
21
 
22
- /**
23
- * {@inheritdoc}
24
- */
25
  public function getTokenParsers()
26
  {
27
  return array();
28
  }
29
 
30
- /**
31
- * {@inheritdoc}
32
- */
33
  public function getNodeVisitors()
34
  {
35
  return array();
36
  }
37
 
38
- /**
39
- * {@inheritdoc}
40
- */
41
  public function getFilters()
42
  {
43
  return array();
44
  }
45
 
46
- /**
47
- * {@inheritdoc}
48
- */
49
  public function getTests()
50
  {
51
  return array();
52
  }
53
 
54
- /**
55
- * {@inheritdoc}
56
- */
57
  public function getFunctions()
58
  {
59
  return array();
60
  }
61
 
62
- /**
63
- * {@inheritdoc}
64
- */
65
  public function getOperators()
66
  {
67
  return array();
68
  }
69
 
70
  /**
71
- * {@inheritdoc}
72
- *
73
  * @deprecated since 1.23 (to be removed in 2.0), implement Twig_Extension_GlobalsInterface instead
74
  */
75
  public function getGlobals()
@@ -78,8 +56,6 @@ abstract class Twig_Extension implements Twig_ExtensionInterface
78
  }
79
 
80
  /**
81
- * {@inheritdoc}
82
- *
83
  * @deprecated since 1.26 (to be removed in 2.0), not used anymore internally
84
  */
85
  public function getName()
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
11
  abstract class Twig_Extension implements Twig_ExtensionInterface
12
  {
13
  /**
 
 
14
  * @deprecated since 1.23 (to be removed in 2.0), implement Twig_Extension_InitRuntimeInterface instead
15
  */
16
  public function initRuntime(Twig_Environment $environment)
17
  {
18
  }
19
 
 
 
 
20
  public function getTokenParsers()
21
  {
22
  return array();
23
  }
24
 
 
 
 
25
  public function getNodeVisitors()
26
  {
27
  return array();
28
  }
29
 
 
 
 
30
  public function getFilters()
31
  {
32
  return array();
33
  }
34
 
 
 
 
35
  public function getTests()
36
  {
37
  return array();
38
  }
39
 
 
 
 
40
  public function getFunctions()
41
  {
42
  return array();
43
  }
44
 
 
 
 
45
  public function getOperators()
46
  {
47
  return array();
48
  }
49
 
50
  /**
 
 
51
  * @deprecated since 1.23 (to be removed in 2.0), implement Twig_Extension_GlobalsInterface instead
52
  */
53
  public function getGlobals()
56
  }
57
 
58
  /**
 
 
59
  * @deprecated since 1.26 (to be removed in 2.0), not used anymore internally
60
  */
61
  public function getName()
library/twig/twig/lib/Twig/Extension/Core.php CHANGED
@@ -8,11 +8,15 @@ if (!defined('ENT_SUBSTITUTE')) {
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');
@@ -95,9 +99,9 @@ class Twig_Extension_Core extends Twig_Extension
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
  {
@@ -299,7 +303,7 @@ function twig_cycle($values, $position)
299
  * @param Twig_Environment $env
300
  * @param Traversable|array|int|float|string $values The values to pick a random item from
301
  *
302
- * @throws Twig_Error_Runtime When $values is an empty array (does not apply to an empty string which is returned as is).
303
  *
304
  * @return mixed A random value from the given sequence
305
  */
@@ -514,9 +518,9 @@ function twig_round($value, $precision = 0, $method = 'common')
514
  *
515
  * @param Twig_Environment $env
516
  * @param mixed $number A float/int/string of the number to format
517
- * @param int $decimal The number of decimal points to display.
518
- * @param string $decimalPoint The character(s) to use for the decimal point.
519
- * @param string $thousandSep The character(s) to use for the thousands separator.
520
  *
521
  * @return string The formatted number
522
  */
@@ -562,7 +566,7 @@ if (PHP_VERSION_ID < 50300) {
562
  /**
563
  * JSON encodes a variable.
564
  *
565
- * @param mixed $value The value to encode.
566
  * @param int $options Not used on PHP 5.2.x
567
  *
568
  * @return mixed The JSON encoded value
@@ -581,7 +585,7 @@ if (PHP_VERSION_ID < 50300) {
581
  /**
582
  * JSON encodes a variable.
583
  *
584
- * @param mixed $value The value to encode.
585
  * @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
586
  *
587
  * @return mixed The JSON encoded value
@@ -652,7 +656,7 @@ function twig_array_merge($arr1, $arr2)
652
  function twig_slice(Twig_Environment $env, $item, $start, $length = null, $preserveKeys = false)
653
  {
654
  if ($item instanceof Traversable) {
655
- if ($item instanceof IteratorAggregate) {
656
  $item = $item->getIterator();
657
  }
658
 
@@ -821,7 +825,27 @@ function _twig_default_filter($value, $default = '')
821
  function twig_get_array_keys_filter($array)
822
  {
823
  if ($array instanceof Traversable) {
824
- return array_keys(iterator_to_array($array));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
825
  }
826
 
827
  if (!is_array($array)) {
@@ -901,7 +925,21 @@ function twig_in_filter($value, $compare)
901
  } elseif (is_string($compare) && (is_string($value) || is_int($value) || is_float($value))) {
902
  return '' === $value || false !== strpos($compare, (string) $value);
903
  } elseif ($compare instanceof Traversable) {
904
- return in_array($value, iterator_to_array($compare, false), is_object($value) || is_resource($value));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
905
  }
906
 
907
  return false;
@@ -1402,6 +1440,18 @@ function twig_include(Twig_Environment $env, $context, $template, $variables = a
1402
 
1403
  throw $e;
1404
  }
 
 
 
 
 
 
 
 
 
 
 
 
1405
  }
1406
 
1407
  if ($isSandboxed && !$alreadySandboxed) {
8
  /*
9
  * This file is part of Twig.
10
  *
11
+ * (c) 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
+
17
+ /**
18
+ * @final
19
+ */
20
  class Twig_Extension_Core extends Twig_Extension
21
  {
22
  protected $dateFormats = array('F j, Y H:i', '%d days');
99
  /**
100
  * Sets the default format to be used by the number_format filter.
101
  *
102
+ * @param int $decimal the number of decimal places to use
103
+ * @param string $decimalPoint the character(s) to use for the decimal point
104
+ * @param string $thousandSep the character(s) to use for the thousands separator
105
  */
106
  public function setNumberFormat($decimal, $decimalPoint, $thousandSep)
107
  {
303
  * @param Twig_Environment $env
304
  * @param Traversable|array|int|float|string $values The values to pick a random item from
305
  *
306
+ * @throws Twig_Error_Runtime when $values is an empty array (does not apply to an empty string which is returned as is)
307
  *
308
  * @return mixed A random value from the given sequence
309
  */
518
  *
519
  * @param Twig_Environment $env
520
  * @param mixed $number A float/int/string of the number to format
521
+ * @param int $decimal the number of decimal points to display
522
+ * @param string $decimalPoint the character(s) to use for the decimal point
523
+ * @param string $thousandSep the character(s) to use for the thousands separator
524
  *
525
  * @return string The formatted number
526
  */
566
  /**
567
  * JSON encodes a variable.
568
  *
569
+ * @param mixed $value the value to encode
570
  * @param int $options Not used on PHP 5.2.x
571
  *
572
  * @return mixed The JSON encoded value
585
  /**
586
  * JSON encodes a variable.
587
  *
588
+ * @param mixed $value the value to encode
589
  * @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
590
  *
591
  * @return mixed The JSON encoded value
656
  function twig_slice(Twig_Environment $env, $item, $start, $length = null, $preserveKeys = false)
657
  {
658
  if ($item instanceof Traversable) {
659
+ while ($item instanceof IteratorAggregate) {
660
  $item = $item->getIterator();
661
  }
662
 
825
  function twig_get_array_keys_filter($array)
826
  {
827
  if ($array instanceof Traversable) {
828
+ while ($array instanceof IteratorAggregate) {
829
+ $array = $array->getIterator();
830
+ }
831
+
832
+ if ($array instanceof Iterator) {
833
+ $keys = array();
834
+ $array->rewind();
835
+ while ($array->valid()) {
836
+ $keys[] = $array->key();
837
+ $array->next();
838
+ }
839
+
840
+ return $keys;
841
+ }
842
+
843
+ $keys = array();
844
+ foreach ($array as $key => $item) {
845
+ $keys[] = $key;
846
+ }
847
+
848
+ return $keys;
849
  }
850
 
851
  if (!is_array($array)) {
925
  } elseif (is_string($compare) && (is_string($value) || is_int($value) || is_float($value))) {
926
  return '' === $value || false !== strpos($compare, (string) $value);
927
  } elseif ($compare instanceof Traversable) {
928
+ if (is_object($value) || is_resource($value)) {
929
+ foreach ($compare as $item) {
930
+ if ($item === $value) {
931
+ return true;
932
+ }
933
+ }
934
+ } else {
935
+ foreach ($compare as $item) {
936
+ if ($item == $value) {
937
+ return true;
938
+ }
939
+ }
940
+ }
941
+
942
+ return false;
943
  }
944
 
945
  return false;
1440
 
1441
  throw $e;
1442
  }
1443
+ } catch (Throwable $e) {
1444
+ if ($isSandboxed && !$alreadySandboxed) {
1445
+ $sandbox->disableSandbox();
1446
+ }
1447
+
1448
+ throw $e;
1449
+ } catch (Exception $e) {
1450
+ if ($isSandboxed && !$alreadySandboxed) {
1451
+ $sandbox->disableSandbox();
1452
+ }
1453
+
1454
+ throw $e;
1455
  }
1456
 
1457
  if ($isSandboxed && !$alreadySandboxed) {
library/twig/twig/lib/Twig/Extension/Debug.php CHANGED
@@ -3,11 +3,15 @@
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
  public function getFunctions()
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) 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
+ * @final
14
+ */
15
  class Twig_Extension_Debug extends Twig_Extension
16
  {
17
  public function getFunctions()
library/twig/twig/lib/Twig/Extension/Escaper.php CHANGED
@@ -3,11 +3,15 @@
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;
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) 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
+ * @final
14
+ */
15
  class Twig_Extension_Escaper extends Twig_Extension
16
  {
17
  protected $defaultStrategy;
library/twig/twig/lib/Twig/Extension/Optimizer.php CHANGED
@@ -3,11 +3,15 @@
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;
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) 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
+ * @final
14
+ */
15
  class Twig_Extension_Optimizer extends Twig_Extension
16
  {
17
  protected $optimizers;
library/twig/twig/lib/Twig/Extension/Profiler.php CHANGED
@@ -3,7 +3,7 @@
3
  /*
4
  * This file is part of Twig.
5
  *
6
- * (c) 2015 Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Extension/Sandbox.php CHANGED
@@ -3,11 +3,15 @@
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;
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) 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
+ * @final
14
+ */
15
  class Twig_Extension_Sandbox extends Twig_Extension
16
  {
17
  protected $sandboxedGlobally;
library/twig/twig/lib/Twig/Extension/Staging.php CHANGED
@@ -3,7 +3,7 @@
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.
@@ -29,6 +29,10 @@ class Twig_Extension_Staging extends Twig_Extension
29
 
30
  public function addFunction($name, $function)
31
  {
 
 
 
 
32
  $this->functions[$name] = $function;
33
  }
34
 
@@ -39,6 +43,10 @@ class Twig_Extension_Staging extends Twig_Extension
39
 
40
  public function addFilter($name, $filter)
41
  {
 
 
 
 
42
  $this->filters[$name] = $filter;
43
  }
44
 
@@ -59,7 +67,11 @@ class Twig_Extension_Staging extends Twig_Extension
59
 
60
  public function addTokenParser(Twig_TokenParserInterface $parser)
61
  {
62
- $this->tokenParsers[] = $parser;
 
 
 
 
63
  }
64
 
65
  public function getTokenParsers()
@@ -79,6 +91,10 @@ class Twig_Extension_Staging extends Twig_Extension
79
 
80
  public function addTest($name, $test)
81
  {
 
 
 
 
82
  $this->tests[$name] = $test;
83
  }
84
 
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
29
 
30
  public function addFunction($name, $function)
31
  {
32
+ if (isset($this->functions[$name])) {
33
+ @trigger_error(sprintf('Overriding function "%s" that is already registered is deprecated since version 1.30 and won\'t be possible anymore in 2.0.', $name), E_USER_DEPRECATED);
34
+ }
35
+
36
  $this->functions[$name] = $function;
37
  }
38
 
43
 
44
  public function addFilter($name, $filter)
45
  {
46
+ if (isset($this->filters[$name])) {
47
+ @trigger_error(sprintf('Overriding filter "%s" that is already registered is deprecated since version 1.30 and won\'t be possible anymore in 2.0.', $name), E_USER_DEPRECATED);
48
+ }
49
+
50
  $this->filters[$name] = $filter;
51
  }
52
 
67
 
68
  public function addTokenParser(Twig_TokenParserInterface $parser)
69
  {
70
+ if (isset($this->tokenParsers[$parser->getTag()])) {
71
+ @trigger_error(sprintf('Overriding tag "%s" that is already registered is deprecated since version 1.30 and won\'t be possible anymore in 2.0.', $parser->getTag()), E_USER_DEPRECATED);
72
+ }
73
+
74
+ $this->tokenParsers[$parser->getTag()] = $parser;
75
  }
76
 
77
  public function getTokenParsers()
91
 
92
  public function addTest($name, $test)
93
  {
94
+ if (isset($this->tests[$name])) {
95
+ @trigger_error(sprintf('Overriding test "%s" that is already registered is deprecated since version 1.30 and won\'t be possible anymore in 2.0.', $name), E_USER_DEPRECATED);
96
+ }
97
+
98
  $this->tests[$name] = $test;
99
  }
100
 
library/twig/twig/lib/Twig/Extension/StringLoader.php CHANGED
@@ -3,11 +3,15 @@
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
  public function getFunctions()
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) 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
+ * @final
14
+ */
15
  class Twig_Extension_StringLoader extends Twig_Extension
16
  {
17
  public function getFunctions()
library/twig/twig/lib/Twig/ExtensionInterface.php CHANGED
@@ -3,7 +3,7 @@
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.
@@ -63,7 +63,7 @@ interface Twig_ExtensionInterface
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
 
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
63
  /**
64
  * Returns a list of operators to add to the existing list.
65
  *
66
+ * @return array<array> First array of unary operators, second array of binary operators
67
  */
68
  public function getOperators();
69
 
library/twig/twig/lib/Twig/FactoryRuntimeLoader.php ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 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
+ * Lazy loads the runtime implementations for a Twig element.
14
+ *
15
+ * @author Robin Chalas <robin.chalas@gmail.com>
16
+ */
17
+ class Twig_FactoryRuntimeLoader implements Twig_RuntimeLoaderInterface
18
+ {
19
+ private $map;
20
+
21
+ /**
22
+ * @param array $map An array where keys are class names and values factory callables
23
+ */
24
+ public function __construct($map = array())
25
+ {
26
+ $this->map = $map;
27
+ }
28
+
29
+ public function load($class)
30
+ {
31
+ if (isset($this->map[$class])) {
32
+ $runtimeFactory = $this->map[$class];
33
+
34
+ return $runtimeFactory();
35
+ }
36
+ }
37
+ }
library/twig/twig/lib/Twig/FileExtensionEscapingStrategy.php CHANGED
@@ -3,7 +3,7 @@
3
  /*
4
  * This file is part of Twig.
5
  *
6
- * (c) 2015 Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Filter.php CHANGED
@@ -3,7 +3,7 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Filter/Function.php CHANGED
@@ -3,7 +3,7 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Filter/Method.php CHANGED
@@ -3,7 +3,7 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Filter/Node.php CHANGED
@@ -3,7 +3,7 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/FilterCallableInterface.php CHANGED
@@ -3,7 +3,7 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/FilterInterface.php CHANGED
@@ -3,7 +3,7 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Function.php CHANGED
@@ -3,7 +3,7 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Function/Function.php CHANGED
@@ -3,8 +3,8 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
+ * (c) 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.
library/twig/twig/lib/Twig/Function/Method.php CHANGED
@@ -3,8 +3,8 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
+ * (c) 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.
library/twig/twig/lib/Twig/Function/Node.php CHANGED
@@ -3,7 +3,7 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/FunctionCallableInterface.php CHANGED
@@ -3,7 +3,7 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/FunctionInterface.php CHANGED
@@ -3,8 +3,8 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
+ * (c) 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.
library/twig/twig/lib/Twig/Lexer.php CHANGED
@@ -3,8 +3,8 @@
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.
@@ -34,6 +34,8 @@ class Twig_Lexer implements Twig_LexerInterface
34
  protected $positions;
35
  protected $currentVarBlockLine;
36
 
 
 
37
  const STATE_DATA = 0;
38
  const STATE_BLOCK = 1;
39
  const STATE_VAR = 2;
@@ -73,16 +75,17 @@ class Twig_Lexer implements Twig_LexerInterface
73
  );
74
  }
75
 
76
- /**
77
- * {@inheritdoc}
78
- */
79
  public function tokenize($code, $name = null)
80
  {
81
  if (!$code instanceof Twig_Source) {
82
  @trigger_error(sprintf('Passing a string as the $code argument of %s() is deprecated since version 1.27 and will be removed in 2.0. Pass a Twig_Source instance instead.', __METHOD__), E_USER_DEPRECATED);
83
- $source = new Twig_Source($code, $name);
84
  } else {
85
- $source = $code;
 
 
 
 
86
  }
87
 
88
  if (function_exists('mb_internal_encoding') && ((int) ini_get('mbstring.func_overload')) & 2) {
@@ -92,8 +95,8 @@ class Twig_Lexer implements Twig_LexerInterface
92
  $mbEncoding = null;
93
  }
94
 
95
- $this->code = str_replace(array("\r\n", "\r"), "\n", $source->getCode());
96
- $this->filename = $source->getName();
97
  $this->cursor = 0;
98
  $this->lineno = 1;
99
  $this->end = strlen($this->code);
@@ -137,14 +140,14 @@ class Twig_Lexer implements Twig_LexerInterface
137
 
138
  if (!empty($this->brackets)) {
139
  list($expect, $lineno) = array_pop($this->brackets);
140
- throw new Twig_Error_Syntax(sprintf('Unclosed "%s".', $expect), $lineno, $this->filename);
141
  }
142
 
143
  if ($mbEncoding) {
144
  mb_internal_encoding($mbEncoding);
145
  }
146
 
147
- return new Twig_TokenStream($this->tokens, $source);
148
  }
149
 
150
  protected function lexData()
@@ -232,7 +235,7 @@ class Twig_Lexer implements Twig_LexerInterface
232
  $this->moveCursor($match[0]);
233
 
234
  if ($this->cursor >= $this->end) {
235
- throw new Twig_Error_Syntax(sprintf('Unclosed "%s".', $this->state === self::STATE_BLOCK ? 'block' : 'variable'), $this->currentVarBlockLine, $this->filename);
236
  }
237
  }
238
 
@@ -264,12 +267,12 @@ class Twig_Lexer implements Twig_LexerInterface
264
  // closing bracket
265
  elseif (false !== strpos(')]}', $this->code[$this->cursor])) {
266
  if (empty($this->brackets)) {
267
- throw new Twig_Error_Syntax(sprintf('Unexpected "%s".', $this->code[$this->cursor]), $this->lineno, $this->filename);
268
  }
269
 
270
  list($expect, $lineno) = array_pop($this->brackets);
271
  if ($this->code[$this->cursor] != strtr($expect, '([{', ')]}')) {
272
- throw new Twig_Error_Syntax(sprintf('Unclosed "%s".', $expect), $lineno, $this->filename);
273
  }
274
  }
275
 
@@ -289,7 +292,7 @@ class Twig_Lexer implements Twig_LexerInterface
289
  }
290
  // unlexable
291
  else {
292
- throw new Twig_Error_Syntax(sprintf('Unexpected character "%s".', $this->code[$this->cursor]), $this->lineno, $this->filename);
293
  }
294
  }
295
 
@@ -300,7 +303,7 @@ class Twig_Lexer implements Twig_LexerInterface
300
  }
301
 
302
  if (!preg_match(str_replace('%s', $tag, $this->regexes['lex_raw_data']), $this->code, $match, PREG_OFFSET_CAPTURE, $this->cursor)) {
303
- throw new Twig_Error_Syntax(sprintf('Unexpected end of file: Unclosed "%s" block.', $tag), $this->lineno, $this->filename);
304
  }
305
 
306
  $text = substr($this->code, $this->cursor, $match[0][1] - $this->cursor);
@@ -316,7 +319,7 @@ class Twig_Lexer implements Twig_LexerInterface
316
  protected function lexComment()
317
  {
318
  if (!preg_match($this->regexes['lex_comment'], $this->code, $match, PREG_OFFSET_CAPTURE, $this->cursor)) {
319
- throw new Twig_Error_Syntax('Unclosed comment.', $this->lineno, $this->filename);
320
  }
321
 
322
  $this->moveCursor(substr($this->code, $this->cursor, $match[0][1] - $this->cursor).$match[0][0]);
@@ -335,7 +338,7 @@ class Twig_Lexer implements Twig_LexerInterface
335
  } elseif (preg_match(self::REGEX_DQ_STRING_DELIM, $this->code, $match, null, $this->cursor)) {
336
  list($expect, $lineno) = array_pop($this->brackets);
337
  if ($this->code[$this->cursor] != '"') {
338
- throw new Twig_Error_Syntax(sprintf('Unclosed "%s".', $expect), $lineno, $this->filename);
339
  }
340
 
341
  $this->popState();
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
+ * (c) Armin Ronacher
8
  *
9
  * For the full copyright and license information, please view the LICENSE
10
  * file that was distributed with this source code.
34
  protected $positions;
35
  protected $currentVarBlockLine;
36
 
37
+ private $source;
38
+
39
  const STATE_DATA = 0;
40
  const STATE_BLOCK = 1;
41
  const STATE_VAR = 2;
75
  );
76
  }
77
 
 
 
 
78
  public function tokenize($code, $name = null)
79
  {
80
  if (!$code instanceof Twig_Source) {
81
  @trigger_error(sprintf('Passing a string as the $code argument of %s() is deprecated since version 1.27 and will be removed in 2.0. Pass a Twig_Source instance instead.', __METHOD__), E_USER_DEPRECATED);
82
+ $this->source = new Twig_Source($code, $name);
83
  } else {
84
+ $this->source = $code;
85
+ }
86
+
87
+ if (((int) ini_get('mbstring.func_overload')) & 2) {
88
+ @trigger_error('Support for having "mbstring.func_overload" different from 0 is deprecated version 1.29 and will be removed in 2.0.', E_USER_DEPRECATED);
89
  }
90
 
91
  if (function_exists('mb_internal_encoding') && ((int) ini_get('mbstring.func_overload')) & 2) {
95
  $mbEncoding = null;
96
  }
97
 
98
+ $this->code = str_replace(array("\r\n", "\r"), "\n", $this->source->getCode());
99
+ $this->filename = $this->source->getName();
100
  $this->cursor = 0;
101
  $this->lineno = 1;
102
  $this->end = strlen($this->code);
140
 
141
  if (!empty($this->brackets)) {
142
  list($expect, $lineno) = array_pop($this->brackets);
143
+ throw new Twig_Error_Syntax(sprintf('Unclosed "%s".', $expect), $lineno, $this->source);
144
  }
145
 
146
  if ($mbEncoding) {
147
  mb_internal_encoding($mbEncoding);
148
  }
149
 
150
+ return new Twig_TokenStream($this->tokens, $this->source);
151
  }
152
 
153
  protected function lexData()
235
  $this->moveCursor($match[0]);
236
 
237
  if ($this->cursor >= $this->end) {
238
+ throw new Twig_Error_Syntax(sprintf('Unclosed "%s".', $this->state === self::STATE_BLOCK ? 'block' : 'variable'), $this->currentVarBlockLine, $this->source);
239
  }
240
  }
241
 
267
  // closing bracket
268
  elseif (false !== strpos(')]}', $this->code[$this->cursor])) {
269
  if (empty($this->brackets)) {
270
+ throw new Twig_Error_Syntax(sprintf('Unexpected "%s".', $this->code[$this->cursor]), $this->lineno, $this->source);
271
  }
272
 
273
  list($expect, $lineno) = array_pop($this->brackets);
274
  if ($this->code[$this->cursor] != strtr($expect, '([{', ')]}')) {
275
+ throw new Twig_Error_Syntax(sprintf('Unclosed "%s".', $expect), $lineno, $this->source);
276
  }
277
  }
278
 
292
  }
293
  // unlexable
294
  else {
295
+ throw new Twig_Error_Syntax(sprintf('Unexpected character "%s".', $this->code[$this->cursor]), $this->lineno, $this->source);
296
  }
297
  }
298
 
303
  }
304
 
305
  if (!preg_match(str_replace('%s', $tag, $this->regexes['lex_raw_data']), $this->code, $match, PREG_OFFSET_CAPTURE, $this->cursor)) {
306
+ throw new Twig_Error_Syntax(sprintf('Unexpected end of file: Unclosed "%s" block.', $tag), $this->lineno, $this->source);
307
  }
308
 
309
  $text = substr($this->code, $this->cursor, $match[0][1] - $this->cursor);
319
  protected function lexComment()
320
  {
321
  if (!preg_match($this->regexes['lex_comment'], $this->code, $match, PREG_OFFSET_CAPTURE, $this->cursor)) {
322
+ throw new Twig_Error_Syntax('Unclosed comment.', $this->lineno, $this->source);
323
  }
324
 
325
  $this->moveCursor(substr($this->code, $this->cursor, $match[0][1] - $this->cursor).$match[0][0]);
338
  } elseif (preg_match(self::REGEX_DQ_STRING_DELIM, $this->code, $match, null, $this->cursor)) {
339
  list($expect, $lineno) = array_pop($this->brackets);
340
  if ($this->code[$this->cursor] != '"') {
341
+ throw new Twig_Error_Syntax(sprintf('Unclosed "%s".', $expect), $lineno, $this->source);
342
  }
343
 
344
  $this->popState();
library/twig/twig/lib/Twig/LexerInterface.php CHANGED
@@ -3,7 +3,7 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Loader/Array.php CHANGED
@@ -3,7 +3,7 @@
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.
@@ -19,6 +19,8 @@
19
  *
20
  * This loader should only be used for unit testing.
21
  *
 
 
22
  * @author Fabien Potencier <fabien@symfony.com>
23
  */
24
  class Twig_Loader_Array implements Twig_LoaderInterface, Twig_ExistsLoaderInterface, Twig_SourceContextLoaderInterface
@@ -44,9 +46,6 @@ class Twig_Loader_Array implements Twig_LoaderInterface, Twig_ExistsLoaderInterf
44
  $this->templates[(string) $name] = $template;
45
  }
46
 
47
- /**
48
- * {@inheritdoc}
49
- */
50
  public function getSource($name)
51
  {
52
  @trigger_error(sprintf('Calling "getSource" on "%s" is deprecated since 1.27. Use getSourceContext() instead.', get_class($this)), E_USER_DEPRECATED);
@@ -59,9 +58,6 @@ class Twig_Loader_Array implements Twig_LoaderInterface, Twig_ExistsLoaderInterf
59
  return $this->templates[$name];
60
  }
61
 
62
- /**
63
- * {@inheritdoc}
64
- */
65
  public function getSourceContext($name)
66
  {
67
  $name = (string) $name;
@@ -72,17 +68,11 @@ class Twig_Loader_Array implements Twig_LoaderInterface, Twig_ExistsLoaderInterf
72
  return new Twig_Source($this->templates[$name], $name);
73
  }
74
 
75
- /**
76
- * {@inheritdoc}
77
- */
78
  public function exists($name)
79
  {
80
  return isset($this->templates[(string) $name]);
81
  }
82
 
83
- /**
84
- * {@inheritdoc}
85
- */
86
  public function getCacheKey($name)
87
  {
88
  $name = (string) $name;
@@ -93,9 +83,6 @@ class Twig_Loader_Array implements Twig_LoaderInterface, Twig_ExistsLoaderInterf
93
  return $this->templates[$name];
94
  }
95
 
96
- /**
97
- * {@inheritdoc}
98
- */
99
  public function isFresh($name, $time)
100
  {
101
  $name = (string) $name;
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
19
  *
20
  * This loader should only be used for unit testing.
21
  *
22
+ * @final
23
+ *
24
  * @author Fabien Potencier <fabien@symfony.com>
25
  */
26
  class Twig_Loader_Array implements Twig_LoaderInterface, Twig_ExistsLoaderInterface, Twig_SourceContextLoaderInterface
46
  $this->templates[(string) $name] = $template;
47
  }
48
 
 
 
 
49
  public function getSource($name)
50
  {
51
  @trigger_error(sprintf('Calling "getSource" on "%s" is deprecated since 1.27. Use getSourceContext() instead.', get_class($this)), E_USER_DEPRECATED);
58
  return $this->templates[$name];
59
  }
60
 
 
 
 
61
  public function getSourceContext($name)
62
  {
63
  $name = (string) $name;
68
  return new Twig_Source($this->templates[$name], $name);
69
  }
70
 
 
 
 
71
  public function exists($name)
72
  {
73
  return isset($this->templates[(string) $name]);
74
  }
75
 
 
 
 
76
  public function getCacheKey($name)
77
  {
78
  $name = (string) $name;
83
  return $this->templates[$name];
84
  }
85
 
 
 
 
86
  public function isFresh($name, $time)
87
  {
88
  $name = (string) $name;
library/twig/twig/lib/Twig/Loader/Chain.php CHANGED
@@ -3,7 +3,7 @@
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.
@@ -12,6 +12,8 @@
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, Twig_SourceContextLoaderInterface
@@ -35,9 +37,6 @@ class Twig_Loader_Chain implements Twig_LoaderInterface, Twig_ExistsLoaderInterf
35
  $this->hasSourceCache = array();
36
  }
37
 
38
- /**
39
- * {@inheritdoc}
40
- */
41
  public function getSource($name)
42
  {
43
  @trigger_error(sprintf('Calling "getSource" on "%s" is deprecated since 1.27. Use getSourceContext() instead.', get_class($this)), E_USER_DEPRECATED);
@@ -58,9 +57,6 @@ class Twig_Loader_Chain implements Twig_LoaderInterface, Twig_ExistsLoaderInterf
58
  throw new Twig_Error_Loader(sprintf('Template "%s" is not defined%s.', $name, $exceptions ? ' ('.implode(', ', $exceptions).')' : ''));
59
  }
60
 
61
- /**
62
- * {@inheritdoc}
63
- */
64
  public function getSourceContext($name)
65
  {
66
  $exceptions = array();
@@ -83,9 +79,6 @@ class Twig_Loader_Chain implements Twig_LoaderInterface, Twig_ExistsLoaderInterf
83
  throw new Twig_Error_Loader(sprintf('Template "%s" is not defined%s.', $name, $exceptions ? ' ('.implode(', ', $exceptions).')' : ''));
84
  }
85
 
86
- /**
87
- * {@inheritdoc}
88
- */
89
  public function exists($name)
90
  {
91
  $name = (string) $name;
@@ -118,9 +111,6 @@ class Twig_Loader_Chain implements Twig_LoaderInterface, Twig_ExistsLoaderInterf
118
  return $this->hasSourceCache[$name] = false;
119
  }
120
 
121
- /**
122
- * {@inheritdoc}
123
- */
124
  public function getCacheKey($name)
125
  {
126
  $exceptions = array();
@@ -139,9 +129,6 @@ class Twig_Loader_Chain implements Twig_LoaderInterface, Twig_ExistsLoaderInterf
139
  throw new Twig_Error_Loader(sprintf('Template "%s" is not defined%s.', $name, $exceptions ? ' ('.implode(', ', $exceptions).')' : ''));
140
  }
141
 
142
- /**
143
- * {@inheritdoc}
144
- */
145
  public function isFresh($name, $time)
146
  {
147
  $exceptions = array();
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
12
  /**
13
  * Loads templates from other loaders.
14
  *
15
+ * @final
16
+ *
17
  * @author Fabien Potencier <fabien@symfony.com>
18
  */
19
  class Twig_Loader_Chain implements Twig_LoaderInterface, Twig_ExistsLoaderInterface, Twig_SourceContextLoaderInterface
37
  $this->hasSourceCache = array();
38
  }
39
 
 
 
 
40
  public function getSource($name)
41
  {
42
  @trigger_error(sprintf('Calling "getSource" on "%s" is deprecated since 1.27. Use getSourceContext() instead.', get_class($this)), E_USER_DEPRECATED);
57
  throw new Twig_Error_Loader(sprintf('Template "%s" is not defined%s.', $name, $exceptions ? ' ('.implode(', ', $exceptions).')' : ''));
58
  }
59
 
 
 
 
60
  public function getSourceContext($name)
61
  {
62
  $exceptions = array();
79
  throw new Twig_Error_Loader(sprintf('Template "%s" is not defined%s.', $name, $exceptions ? ' ('.implode(', ', $exceptions).')' : ''));
80
  }
81
 
 
 
 
82
  public function exists($name)
83
  {
84
  $name = (string) $name;
111
  return $this->hasSourceCache[$name] = false;
112
  }
113
 
 
 
 
114
  public function getCacheKey($name)
115
  {
116
  $exceptions = array();
129
  throw new Twig_Error_Loader(sprintf('Template "%s" is not defined%s.', $name, $exceptions ? ' ('.implode(', ', $exceptions).')' : ''));
130
  }
131
 
 
 
 
132
  public function isFresh($name, $time)
133
  {
134
  $exceptions = array();
library/twig/twig/lib/Twig/Loader/Filesystem.php CHANGED
@@ -3,7 +3,7 @@
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.
@@ -131,9 +131,6 @@ class Twig_Loader_Filesystem implements Twig_LoaderInterface, Twig_ExistsLoaderI
131
  }
132
  }
133
 
134
- /**
135
- * {@inheritdoc}
136
- */
137
  public function getSource($name)
138
  {
139
  @trigger_error(sprintf('Calling "getSource" on "%s" is deprecated since 1.27. Use getSourceContext() instead.', get_class($this)), E_USER_DEPRECATED);
@@ -141,9 +138,6 @@ class Twig_Loader_Filesystem implements Twig_LoaderInterface, Twig_ExistsLoaderI
141
  return file_get_contents($this->findTemplate($name));
142
  }
143
 
144
- /**
145
- * {@inheritdoc}
146
- */
147
  public function getSourceContext($name)
148
  {
149
  $path = $this->findTemplate($name);
@@ -151,9 +145,6 @@ class Twig_Loader_Filesystem implements Twig_LoaderInterface, Twig_ExistsLoaderI
151
  return new Twig_Source(file_get_contents($path), $name, $path);
152
  }
153
 
154
- /**
155
- * {@inheritdoc}
156
- */
157
  public function getCacheKey($name)
158
  {
159
  $path = $this->findTemplate($name);
@@ -165,9 +156,6 @@ class Twig_Loader_Filesystem implements Twig_LoaderInterface, Twig_ExistsLoaderI
165
  return $path;
166
  }
167
 
168
- /**
169
- * {@inheritdoc}
170
- */
171
  public function exists($name)
172
  {
173
  $name = $this->normalizeName($name);
@@ -185,9 +173,6 @@ class Twig_Loader_Filesystem implements Twig_LoaderInterface, Twig_ExistsLoaderI
185
  }
186
  }
187
 
188
- /**
189
- * {@inheritdoc}
190
- */
191
  public function isFresh($name, $time)
192
  {
193
  return filemtime($this->findTemplate($name)) <= $time;
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
131
  }
132
  }
133
 
 
 
 
134
  public function getSource($name)
135
  {
136
  @trigger_error(sprintf('Calling "getSource" on "%s" is deprecated since 1.27. Use getSourceContext() instead.', get_class($this)), E_USER_DEPRECATED);
138
  return file_get_contents($this->findTemplate($name));
139
  }
140
 
 
 
 
141
  public function getSourceContext($name)
142
  {
143
  $path = $this->findTemplate($name);
145
  return new Twig_Source(file_get_contents($path), $name, $path);
146
  }
147
 
 
 
 
148
  public function getCacheKey($name)
149
  {
150
  $path = $this->findTemplate($name);
156
  return $path;
157
  }
158
 
 
 
 
159
  public function exists($name)
160
  {
161
  $name = $this->normalizeName($name);
173
  }
174
  }
175
 
 
 
 
176
  public function isFresh($name, $time)
177
  {
178
  return filemtime($this->findTemplate($name)) <= $time;
library/twig/twig/lib/Twig/Loader/String.php CHANGED
@@ -3,7 +3,7 @@
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.
@@ -29,9 +29,6 @@
29
  */
30
  class Twig_Loader_String implements Twig_LoaderInterface, Twig_ExistsLoaderInterface, Twig_SourceContextLoaderInterface
31
  {
32
- /**
33
- * {@inheritdoc}
34
- */
35
  public function getSource($name)
36
  {
37
  @trigger_error(sprintf('Calling "getSource" on "%s" is deprecated since 1.27. Use getSourceContext() instead.', get_class($this)), E_USER_DEPRECATED);
@@ -39,33 +36,21 @@ class Twig_Loader_String implements Twig_LoaderInterface, Twig_ExistsLoaderInter
39
  return $name;
40
  }
41
 
42
- /**
43
- * {@inheritdoc}
44
- */
45
  public function getSourceContext($name)
46
  {
47
  return new Twig_Source($name, $name);
48
  }
49
 
50
- /**
51
- * {@inheritdoc}
52
- */
53
  public function exists($name)
54
  {
55
  return true;
56
  }
57
 
58
- /**
59
- * {@inheritdoc}
60
- */
61
  public function getCacheKey($name)
62
  {
63
  return $name;
64
  }
65
 
66
- /**
67
- * {@inheritdoc}
68
- */
69
  public function isFresh($name, $time)
70
  {
71
  return true;
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
29
  */
30
  class Twig_Loader_String implements Twig_LoaderInterface, Twig_ExistsLoaderInterface, Twig_SourceContextLoaderInterface
31
  {
 
 
 
32
  public function getSource($name)
33
  {
34
  @trigger_error(sprintf('Calling "getSource" on "%s" is deprecated since 1.27. Use getSourceContext() instead.', get_class($this)), E_USER_DEPRECATED);
36
  return $name;
37
  }
38
 
 
 
 
39
  public function getSourceContext($name)
40
  {
41
  return new Twig_Source($name, $name);
42
  }
43
 
 
 
 
44
  public function exists($name)
45
  {
46
  return true;
47
  }
48
 
 
 
 
49
  public function getCacheKey($name)
50
  {
51
  return $name;
52
  }
53
 
 
 
 
54
  public function isFresh($name, $time)
55
  {
56
  return true;
library/twig/twig/lib/Twig/LoaderInterface.php CHANGED
@@ -3,7 +3,7 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Markup.php CHANGED
@@ -3,7 +3,7 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Node.php CHANGED
@@ -3,8 +3,8 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
+ * (c) Armin Ronacher
8
  *
9
  * For the full copyright and license information, please view the LICENSE
10
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Node/AutoEscape.php CHANGED
@@ -3,7 +3,7 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Node/Block.php CHANGED
@@ -3,8 +3,8 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
+ * (c) Armin Ronacher
8
  *
9
  * For the full copyright and license information, please view the LICENSE
10
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Node/BlockReference.php CHANGED
@@ -3,8 +3,8 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
+ * (c) Armin Ronacher
8
  *
9
  * For the full copyright and license information, please view the LICENSE
10
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Node/Body.php CHANGED
@@ -3,7 +3,7 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Node/CheckSecurity.php CHANGED
@@ -3,7 +3,7 @@
3
  /*
4
  * This file is part of Twig.
5
  *
6
- * (c) 2015 Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
@@ -56,7 +56,7 @@ class Twig_Node_CheckSecurity extends Twig_Node
56
  ->outdent()
57
  ->write("} catch (Twig_Sandbox_SecurityError \$e) {\n")
58
  ->indent()
59
- ->write("\$e->setTemplateName(\$this->getTemplateName());\n\n")
60
  ->write("if (\$e instanceof Twig_Sandbox_SecurityNotAllowedTagError && isset(\$tags[\$e->getTagName()])) {\n")
61
  ->indent()
62
  ->write("\$e->setTemplateLine(\$tags[\$e->getTagName()]);\n")
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
56
  ->outdent()
57
  ->write("} catch (Twig_Sandbox_SecurityError \$e) {\n")
58
  ->indent()
59
+ ->write("\$e->setSourceContext(\$this->getSourceContext());\n\n")
60
  ->write("if (\$e instanceof Twig_Sandbox_SecurityNotAllowedTagError && isset(\$tags[\$e->getTagName()])) {\n")
61
  ->indent()
62
  ->write("\$e->setTemplateLine(\$tags[\$e->getTagName()]);\n")
library/twig/twig/lib/Twig/Node/Do.php CHANGED
@@ -3,7 +3,7 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Node/Embed.php CHANGED
@@ -3,7 +3,7 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Node/Expression.php CHANGED
@@ -3,8 +3,8 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
+ * (c) Armin Ronacher
8
  *
9
  * For the full copyright and license information, please view the LICENSE
10
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Node/Expression/Array.php CHANGED
@@ -3,7 +3,7 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Node/Expression/AssignName.php CHANGED
@@ -3,8 +3,8 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
+ * (c) Armin Ronacher
8
  *
9
  * For the full copyright and license information, please view the LICENSE
10
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Node/Expression/Binary.php CHANGED
@@ -3,8 +3,8 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
+ * (c) Armin Ronacher
8
  *
9
  * For the full copyright and license information, please view the LICENSE
10
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Node/Expression/Binary/Add.php CHANGED
@@ -3,8 +3,8 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
+ * (c) Armin Ronacher
8
  *
9
  * For the full copyright and license information, please view the LICENSE
10
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Node/Expression/Binary/And.php CHANGED
@@ -3,8 +3,8 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
+ * (c) Armin Ronacher
8
  *
9
  * For the full copyright and license information, please view the LICENSE
10
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Node/Expression/Binary/BitwiseAnd.php CHANGED
@@ -3,8 +3,8 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
+ * (c) Armin Ronacher
8
  *
9
  * For the full copyright and license information, please view the LICENSE
10
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Node/Expression/Binary/BitwiseOr.php CHANGED
@@ -3,8 +3,8 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
+ * (c) Armin Ronacher
8
  *
9
  * For the full copyright and license information, please view the LICENSE
10
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Node/Expression/Binary/BitwiseXor.php CHANGED
@@ -3,8 +3,8 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
+ * (c) Armin Ronacher
8
  *
9
  * For the full copyright and license information, please view the LICENSE
10
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Node/Expression/Binary/Concat.php CHANGED
@@ -3,8 +3,8 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
+ * (c) Armin Ronacher
8
  *
9
  * For the full copyright and license information, please view the LICENSE
10
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Node/Expression/Binary/Div.php CHANGED
@@ -3,8 +3,8 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
+ * (c) Armin Ronacher
8
  *
9
  * For the full copyright and license information, please view the LICENSE
10
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Node/Expression/Binary/EndsWith.php CHANGED
@@ -3,7 +3,7 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Node/Expression/Binary/Equal.php CHANGED
@@ -3,7 +3,7 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Node/Expression/Binary/FloorDiv.php CHANGED
@@ -3,7 +3,7 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Node/Expression/Binary/Greater.php CHANGED
@@ -3,7 +3,7 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Node/Expression/Binary/GreaterEqual.php CHANGED
@@ -3,7 +3,7 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Node/Expression/Binary/In.php CHANGED
@@ -3,7 +3,7 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Node/Expression/Binary/Less.php CHANGED
@@ -3,7 +3,7 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Node/Expression/Binary/LessEqual.php CHANGED
@@ -3,7 +3,7 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Node/Expression/Binary/Matches.php CHANGED
@@ -3,7 +3,7 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Node/Expression/Binary/Mod.php CHANGED
@@ -3,8 +3,8 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
+ * (c) Armin Ronacher
8
  *
9
  * For the full copyright and license information, please view the LICENSE
10
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Node/Expression/Binary/Mul.php CHANGED
@@ -3,8 +3,8 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
+ * (c) Armin Ronacher
8
  *
9
  * For the full copyright and license information, please view the LICENSE
10
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Node/Expression/Binary/NotEqual.php CHANGED
@@ -3,7 +3,7 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Node/Expression/Binary/NotIn.php CHANGED
@@ -3,7 +3,7 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Node/Expression/Binary/Or.php CHANGED
@@ -3,8 +3,8 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
+ * (c) Armin Ronacher
8
  *
9
  * For the full copyright and license information, please view the LICENSE
10
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Node/Expression/Binary/Power.php CHANGED
@@ -3,7 +3,7 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Node/Expression/Binary/Range.php CHANGED
@@ -3,7 +3,7 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Node/Expression/Binary/StartsWith.php CHANGED
@@ -3,7 +3,7 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Node/Expression/Binary/Sub.php CHANGED
@@ -3,8 +3,8 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
+ * (c) Armin Ronacher
8
  *
9
  * For the full copyright and license information, please view the LICENSE
10
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Node/Expression/BlockReference.php CHANGED
@@ -3,8 +3,8 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
+ * (c) Armin Ronacher
8
  *
9
  * For the full copyright and license information, please view the LICENSE
10
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Node/Expression/Call.php CHANGED
@@ -3,7 +3,7 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Node/Expression/Conditional.php CHANGED
@@ -3,8 +3,8 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
+ * (c) Armin Ronacher
8
  *
9
  * For the full copyright and license information, please view the LICENSE
10
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Node/Expression/Constant.php CHANGED
@@ -3,8 +3,8 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
+ * (c) Armin Ronacher
8
  *
9
  * For the full copyright and license information, please view the LICENSE
10
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Node/Expression/ExtensionReference.php CHANGED
@@ -3,7 +3,7 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Node/Expression/Filter.php CHANGED
@@ -3,8 +3,8 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
+ * (c) Armin Ronacher
8
  *
9
  * For the full copyright and license information, please view the LICENSE
10
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Node/Expression/Filter/Default.php CHANGED
@@ -3,7 +3,7 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Node/Expression/Function.php CHANGED
@@ -3,7 +3,7 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Node/Expression/GetAttr.php CHANGED
@@ -3,8 +3,8 @@
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.
@@ -23,6 +23,10 @@ class Twig_Node_Expression_GetAttr extends Twig_Node_Expression
23
 
24
  public function compile(Twig_Compiler $compiler)
25
  {
 
 
 
 
26
  if (function_exists('twig_template_get_attributes') && !$this->getAttribute('disable_c_ext')) {
27
  $compiler->raw('twig_template_get_attributes($this, ');
28
  } else {
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
+ * (c) Armin Ronacher
8
  *
9
  * For the full copyright and license information, please view the LICENSE
10
  * file that was distributed with this source code.
23
 
24
  public function compile(Twig_Compiler $compiler)
25
  {
26
+ if ($this->getAttribute('disable_c_ext')) {
27
+ @trigger_error(sprintf('Using the "disable_c_ext" attribute on %s is deprecated since version 1.30 and will be removed in 2.0.', __CLASS__), E_USER_DEPRECATED);
28
+ }
29
+
30
  if (function_exists('twig_template_get_attributes') && !$this->getAttribute('disable_c_ext')) {
31
  $compiler->raw('twig_template_get_attributes($this, ');
32
  } else {
library/twig/twig/lib/Twig/Node/Expression/MethodCall.php CHANGED
@@ -3,7 +3,7 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Node/Expression/Name.php CHANGED
@@ -3,8 +3,8 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
+ * (c) Armin Ronacher
8
  *
9
  * For the full copyright and license information, please view the LICENSE
10
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Node/Expression/Parent.php CHANGED
@@ -3,8 +3,8 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
+ * (c) Armin Ronacher
8
  *
9
  * For the full copyright and license information, please view the LICENSE
10
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Node/Expression/TempName.php CHANGED
@@ -3,7 +3,7 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Node/Expression/Test.php CHANGED
@@ -3,7 +3,7 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Node/Expression/Test/Constant.php CHANGED
@@ -3,7 +3,7 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Node/Expression/Test/Defined.php CHANGED
@@ -3,7 +3,7 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Node/Expression/Test/Divisibleby.php CHANGED
@@ -3,7 +3,7 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Node/Expression/Test/Even.php CHANGED
@@ -3,7 +3,7 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Node/Expression/Test/Null.php CHANGED
@@ -3,7 +3,7 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Node/Expression/Test/Odd.php CHANGED
@@ -3,7 +3,7 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Node/Expression/Test/Sameas.php CHANGED
@@ -3,7 +3,7 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Node/Expression/Unary.php CHANGED
@@ -3,8 +3,8 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
+ * (c) Armin Ronacher
8
  *
9
  * For the full copyright and license information, please view the LICENSE
10
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Node/Expression/Unary/Neg.php CHANGED
@@ -3,8 +3,8 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
+ * (c) Armin Ronacher
8
  *
9
  * For the full copyright and license information, please view the LICENSE
10
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Node/Expression/Unary/Not.php CHANGED
@@ -3,8 +3,8 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
+ * (c) Armin Ronacher
8
  *
9
  * For the full copyright and license information, please view the LICENSE
10
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Node/Expression/Unary/Pos.php CHANGED
@@ -3,8 +3,8 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
+ * (c) Armin Ronacher
8
  *
9
  * For the full copyright and license information, please view the LICENSE
10
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Node/Flush.php CHANGED
@@ -3,7 +3,7 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Node/For.php CHANGED
@@ -3,8 +3,8 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
+ * (c) Armin Ronacher
8
  *
9
  * For the full copyright and license information, please view the LICENSE
10
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Node/ForLoop.php CHANGED
@@ -3,7 +3,7 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Node/If.php CHANGED
@@ -3,8 +3,8 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
+ * (c) Armin Ronacher
8
  *
9
  * For the full copyright and license information, please view the LICENSE
10
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Node/Import.php CHANGED
@@ -3,7 +3,7 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Node/Include.php CHANGED
@@ -3,8 +3,8 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
+ * (c) Armin Ronacher
8
  *
9
  * For the full copyright and license information, please view the LICENSE
10
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Node/Macro.php CHANGED
@@ -3,7 +3,7 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Node/Module.php CHANGED
@@ -3,8 +3,8 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
+ * (c) Armin Ronacher
8
  *
9
  * For the full copyright and license information, please view the LICENSE
10
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Node/Print.php CHANGED
@@ -3,8 +3,8 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
+ * (c) Armin Ronacher
8
  *
9
  * For the full copyright and license information, please view the LICENSE
10
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Node/Sandbox.php CHANGED
@@ -3,7 +3,7 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Node/SandboxedPrint.php CHANGED
@@ -3,7 +3,7 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Node/Set.php CHANGED
@@ -3,7 +3,7 @@
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.
@@ -14,7 +14,7 @@
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
  {
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
14
  *
15
  * @author Fabien Potencier <fabien@symfony.com>
16
  */
17
+ class Twig_Node_Set extends Twig_Node implements Twig_NodeCaptureInterface
18
  {
19
  public function __construct($capture, Twig_NodeInterface $names, Twig_NodeInterface $values, $lineno, $tag = null)
20
  {
library/twig/twig/lib/Twig/Node/SetTemp.php CHANGED
@@ -3,7 +3,7 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Node/Spaceless.php CHANGED
@@ -3,7 +3,7 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Node/Text.php CHANGED
@@ -3,8 +3,8 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
+ * (c) Armin Ronacher
8
  *
9
  * For the full copyright and license information, please view the LICENSE
10
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Node/With.php CHANGED
@@ -3,7 +3,7 @@
3
  /*
4
  * This file is part of Twig.
5
  *
6
- * (c) 2016 Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/NodeCaptureInterface.php ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 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 that captures any nested displayable nodes.
14
+ *
15
+ * @author Fabien Potencier <fabien@symfony.com>
16
+ */
17
+ interface Twig_NodeCaptureInterface
18
+ {
19
+ }
library/twig/twig/lib/Twig/NodeInterface.php CHANGED
@@ -3,7 +3,7 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/NodeOutputInterface.php CHANGED
@@ -3,7 +3,7 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/NodeTraverser.php CHANGED
@@ -3,7 +3,7 @@
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.
@@ -14,6 +14,8 @@
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
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
14
  *
15
  * It visits all nodes and their children and calls the given visitor for each.
16
  *
17
+ * @final
18
+ *
19
  * @author Fabien Potencier <fabien@symfony.com>
20
  */
21
  class Twig_NodeTraverser
library/twig/twig/lib/Twig/NodeVisitor/Escaper.php CHANGED
@@ -3,7 +3,7 @@
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.
@@ -12,6 +12,8 @@
12
  /**
13
  * Twig_NodeVisitor_Escaper implements output escaping.
14
  *
 
 
15
  * @author Fabien Potencier <fabien@symfony.com>
16
  */
17
  class Twig_NodeVisitor_Escaper extends Twig_BaseNodeVisitor
@@ -28,9 +30,6 @@ class Twig_NodeVisitor_Escaper extends Twig_BaseNodeVisitor
28
  $this->safeAnalysis = new Twig_NodeVisitor_SafeAnalysis();
29
  }
30
 
31
- /**
32
- * {@inheritdoc}
33
- */
34
  protected function doEnterNode(Twig_Node $node, Twig_Environment $env)
35
  {
36
  if ($node instanceof Twig_Node_Module) {
@@ -50,9 +49,6 @@ class Twig_NodeVisitor_Escaper extends Twig_BaseNodeVisitor
50
  return $node;
51
  }
52
 
53
- /**
54
- * {@inheritdoc}
55
- */
56
  protected function doLeaveNode(Twig_Node $node, Twig_Environment $env)
57
  {
58
  if ($node instanceof Twig_Node_Module) {
@@ -149,9 +145,6 @@ class Twig_NodeVisitor_Escaper extends Twig_BaseNodeVisitor
149
  return new Twig_Node_Expression_Filter($node, $name, $args, $line);
150
  }
151
 
152
- /**
153
- * {@inheritdoc}
154
- */
155
  public function getPriority()
156
  {
157
  return 0;
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
12
  /**
13
  * Twig_NodeVisitor_Escaper implements output escaping.
14
  *
15
+ * @final
16
+ *
17
  * @author Fabien Potencier <fabien@symfony.com>
18
  */
19
  class Twig_NodeVisitor_Escaper extends Twig_BaseNodeVisitor
30
  $this->safeAnalysis = new Twig_NodeVisitor_SafeAnalysis();
31
  }
32
 
 
 
 
33
  protected function doEnterNode(Twig_Node $node, Twig_Environment $env)
34
  {
35
  if ($node instanceof Twig_Node_Module) {
49
  return $node;
50
  }
51
 
 
 
 
52
  protected function doLeaveNode(Twig_Node $node, Twig_Environment $env)
53
  {
54
  if ($node instanceof Twig_Node_Module) {
145
  return new Twig_Node_Expression_Filter($node, $name, $args, $line);
146
  }
147
 
 
 
 
148
  public function getPriority()
149
  {
150
  return 0;
library/twig/twig/lib/Twig/NodeVisitor/Optimizer.php CHANGED
@@ -3,7 +3,7 @@
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.
@@ -17,6 +17,8 @@
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 extends Twig_BaseNodeVisitor
@@ -45,9 +47,6 @@ class Twig_NodeVisitor_Optimizer extends Twig_BaseNodeVisitor
45
  $this->optimizers = $optimizers;
46
  }
47
 
48
- /**
49
- * {@inheritdoc}
50
- */
51
  protected function doEnterNode(Twig_Node $node, Twig_Environment $env)
52
  {
53
  if (self::OPTIMIZE_FOR === (self::OPTIMIZE_FOR & $this->optimizers)) {
@@ -71,9 +70,6 @@ class Twig_NodeVisitor_Optimizer extends Twig_BaseNodeVisitor
71
  return $node;
72
  }
73
 
74
- /**
75
- * {@inheritdoc}
76
- */
77
  protected function doLeaveNode(Twig_Node $node, Twig_Environment $env)
78
  {
79
  $expression = $node instanceof Twig_Node_Expression;
@@ -248,9 +244,6 @@ class Twig_NodeVisitor_Optimizer extends Twig_BaseNodeVisitor
248
  }
249
  }
250
 
251
- /**
252
- * {@inheritdoc}
253
- */
254
  public function getPriority()
255
  {
256
  return 255;
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
17
  * You can configure which optimizations you want to activate via the
18
  * optimizer mode.
19
  *
20
+ * @final
21
+ *
22
  * @author Fabien Potencier <fabien@symfony.com>
23
  */
24
  class Twig_NodeVisitor_Optimizer extends Twig_BaseNodeVisitor
47
  $this->optimizers = $optimizers;
48
  }
49
 
 
 
 
50
  protected function doEnterNode(Twig_Node $node, Twig_Environment $env)
51
  {
52
  if (self::OPTIMIZE_FOR === (self::OPTIMIZE_FOR & $this->optimizers)) {
70
  return $node;
71
  }
72
 
 
 
 
73
  protected function doLeaveNode(Twig_Node $node, Twig_Environment $env)
74
  {
75
  $expression = $node instanceof Twig_Node_Expression;
244
  }
245
  }
246
 
 
 
 
247
  public function getPriority()
248
  {
249
  return 255;
library/twig/twig/lib/Twig/NodeVisitor/SafeAnalysis.php CHANGED
@@ -9,6 +9,9 @@
9
  * file that was distributed with this source code.
10
  */
11
 
 
 
 
12
  class Twig_NodeVisitor_SafeAnalysis extends Twig_BaseNodeVisitor
13
  {
14
  protected $data = array();
@@ -57,17 +60,11 @@ class Twig_NodeVisitor_SafeAnalysis extends Twig_BaseNodeVisitor
57
  );
58
  }
59
 
60
- /**
61
- * {@inheritdoc}
62
- */
63
  protected function doEnterNode(Twig_Node $node, Twig_Environment $env)
64
  {
65
  return $node;
66
  }
67
 
68
- /**
69
- * {@inheritdoc}
70
- */
71
  protected function doLeaveNode(Twig_Node $node, Twig_Environment $env)
72
  {
73
  if ($node instanceof Twig_Node_Expression_Constant) {
@@ -144,9 +141,6 @@ class Twig_NodeVisitor_SafeAnalysis extends Twig_BaseNodeVisitor
144
  return array_intersect($a, $b);
145
  }
146
 
147
- /**
148
- * {@inheritdoc}
149
- */
150
  public function getPriority()
151
  {
152
  return 0;
9
  * file that was distributed with this source code.
10
  */
11
 
12
+ /**
13
+ * @final
14
+ */
15
  class Twig_NodeVisitor_SafeAnalysis extends Twig_BaseNodeVisitor
16
  {
17
  protected $data = array();
60
  );
61
  }
62
 
 
 
 
63
  protected function doEnterNode(Twig_Node $node, Twig_Environment $env)
64
  {
65
  return $node;
66
  }
67
 
 
 
 
68
  protected function doLeaveNode(Twig_Node $node, Twig_Environment $env)
69
  {
70
  if ($node instanceof Twig_Node_Expression_Constant) {
141
  return array_intersect($a, $b);
142
  }
143
 
 
 
 
144
  public function getPriority()
145
  {
146
  return 0;
library/twig/twig/lib/Twig/NodeVisitor/Sandbox.php CHANGED
@@ -3,7 +3,7 @@
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.
@@ -12,6 +12,8 @@
12
  /**
13
  * Twig_NodeVisitor_Sandbox implements sandboxing.
14
  *
 
 
15
  * @author Fabien Potencier <fabien@symfony.com>
16
  */
17
  class Twig_NodeVisitor_Sandbox extends Twig_BaseNodeVisitor
@@ -21,9 +23,6 @@ class Twig_NodeVisitor_Sandbox extends Twig_BaseNodeVisitor
21
  protected $filters;
22
  protected $functions;
23
 
24
- /**
25
- * {@inheritdoc}
26
- */
27
  protected function doEnterNode(Twig_Node $node, Twig_Environment $env)
28
  {
29
  if ($node instanceof Twig_Node_Module) {
@@ -58,9 +57,6 @@ class Twig_NodeVisitor_Sandbox extends Twig_BaseNodeVisitor
58
  return $node;
59
  }
60
 
61
- /**
62
- * {@inheritdoc}
63
- */
64
  protected function doLeaveNode(Twig_Node $node, Twig_Environment $env)
65
  {
66
  if ($node instanceof Twig_Node_Module) {
@@ -72,9 +68,6 @@ class Twig_NodeVisitor_Sandbox extends Twig_BaseNodeVisitor
72
  return $node;
73
  }
74
 
75
- /**
76
- * {@inheritdoc}
77
- */
78
  public function getPriority()
79
  {
80
  return 0;
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
12
  /**
13
  * Twig_NodeVisitor_Sandbox implements sandboxing.
14
  *
15
+ * @final
16
+ *
17
  * @author Fabien Potencier <fabien@symfony.com>
18
  */
19
  class Twig_NodeVisitor_Sandbox extends Twig_BaseNodeVisitor
23
  protected $filters;
24
  protected $functions;
25
 
 
 
 
26
  protected function doEnterNode(Twig_Node $node, Twig_Environment $env)
27
  {
28
  if ($node instanceof Twig_Node_Module) {
57
  return $node;
58
  }
59
 
 
 
 
60
  protected function doLeaveNode(Twig_Node $node, Twig_Environment $env)
61
  {
62
  if ($node instanceof Twig_Node_Module) {
68
  return $node;
69
  }
70
 
 
 
 
71
  public function getPriority()
72
  {
73
  return 0;
library/twig/twig/lib/Twig/NodeVisitorInterface.php CHANGED
@@ -3,7 +3,7 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Parser.php CHANGED
@@ -3,8 +3,8 @@
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.
@@ -62,9 +62,6 @@ class Twig_Parser implements Twig_ParserInterface
62
  return $this->stream->getSourceContext()->getName();
63
  }
64
 
65
- /**
66
- * {@inheritdoc}
67
- */
68
  public function parse(Twig_TokenStream $stream, $test = null, $dropNeedle = false)
69
  {
70
  // push all variables into the stack to keep the current state of the parser
@@ -109,8 +106,8 @@ class Twig_Parser implements Twig_ParserInterface
109
  $body = new Twig_Node();
110
  }
111
  } catch (Twig_Error_Syntax $e) {
112
- if (!$e->getTemplateName()) {
113
- $e->setTemplateName($this->stream->getSourceContext()->getName());
114
  }
115
 
116
  if (!$e->getTemplateLine()) {
@@ -157,7 +154,7 @@ class Twig_Parser implements Twig_ParserInterface
157
  $token = $this->getCurrentToken();
158
 
159
  if ($token->getType() !== Twig_Token::NAME_TYPE) {
160
- throw new Twig_Error_Syntax('A block must start with a tag name.', $token->getLine(), $this->stream->getSourceContext()->getName());
161
  }
162
 
163
  if (null !== $test && call_user_func($test, $token)) {
@@ -175,13 +172,13 @@ class Twig_Parser implements Twig_ParserInterface
175
  $subparser = $this->handlers->getTokenParser($token->getValue());
176
  if (null === $subparser) {
177
  if (null !== $test) {
178
- $e = new Twig_Error_Syntax(sprintf('Unexpected "%s" tag', $token->getValue()), $token->getLine(), $this->stream->getSourceContext()->getName());
179
 
180
  if (is_array($test) && isset($test[0]) && $test[0] instanceof Twig_TokenParserInterface) {
181
  $e->appendMessage(sprintf(' (expecting closing tag for the "%s" tag defined near line %s).', $test[0]->getTag(), $lineno));
182
  }
183
  } else {
184
- $e = new Twig_Error_Syntax(sprintf('Unknown "%s" tag.', $token->getValue()), $token->getLine(), $this->stream->getSourceContext()->getName());
185
  $e->addSuggestions($token->getValue(), array_keys($this->env->getTags()));
186
  }
187
 
@@ -197,7 +194,7 @@ class Twig_Parser implements Twig_ParserInterface
197
  break;
198
 
199
  default:
200
- throw new Twig_Error_Syntax('Lexer or parser ended up in unsupported state.', 0, $this->stream->getSourceContext()->getName());
201
  }
202
  }
203
 
@@ -271,7 +268,7 @@ class Twig_Parser implements Twig_ParserInterface
271
  public function setMacro($name, Twig_Node_Macro $node)
272
  {
273
  if ($this->isReservedMacroName($name)) {
274
- throw new Twig_Error_Syntax(sprintf('"%s" cannot be used as a macro name as it is a reserved keyword.', $name), $node->getTemplateLine(), $this->stream->getSourceContext()->getName());
275
  }
276
 
277
  $this->macros[$name] = $node;
@@ -383,14 +380,14 @@ class Twig_Parser implements Twig_ParserInterface
383
  (!$node instanceof Twig_Node_Text && !$node instanceof Twig_Node_BlockReference && $node instanceof Twig_NodeOutputInterface)
384
  ) {
385
  if (false !== strpos((string) $node, chr(0xEF).chr(0xBB).chr(0xBF))) {
386
- throw new Twig_Error_Syntax('A template that extends another one cannot start with a byte order mark (BOM); it must be removed.', $node->getTemplateLine(), $this->stream->getSourceContext()->getName());
387
  }
388
 
389
- throw new Twig_Error_Syntax('A template that extends another one cannot include contents outside Twig blocks. Did you forget to put the contents inside a {% block %} tag?', $node->getTemplateLine(), $this->stream->getSourceContext()->getName());
390
  }
391
 
392
- // bypass "set" nodes as they "capture" the output
393
- if ($node instanceof Twig_Node_Set) {
394
  return $node;
395
  }
396
 
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
+ * (c) Armin Ronacher
8
  *
9
  * For the full copyright and license information, please view the LICENSE
10
  * file that was distributed with this source code.
62
  return $this->stream->getSourceContext()->getName();
63
  }
64
 
 
 
 
65
  public function parse(Twig_TokenStream $stream, $test = null, $dropNeedle = false)
66
  {
67
  // push all variables into the stack to keep the current state of the parser
106
  $body = new Twig_Node();
107
  }
108
  } catch (Twig_Error_Syntax $e) {
109
+ if (!$e->getSourceContext()) {
110
+ $e->setSourceContext($this->stream->getSourceContext());
111
  }
112
 
113
  if (!$e->getTemplateLine()) {
154
  $token = $this->getCurrentToken();
155
 
156
  if ($token->getType() !== Twig_Token::NAME_TYPE) {
157
+ throw new Twig_Error_Syntax('A block must start with a tag name.', $token->getLine(), $this->stream->getSourceContext());
158
  }
159
 
160
  if (null !== $test && call_user_func($test, $token)) {
172
  $subparser = $this->handlers->getTokenParser($token->getValue());
173
  if (null === $subparser) {
174
  if (null !== $test) {
175
+ $e = new Twig_Error_Syntax(sprintf('Unexpected "%s" tag', $token->getValue()), $token->getLine(), $this->stream->getSourceContext());
176
 
177
  if (is_array($test) && isset($test[0]) && $test[0] instanceof Twig_TokenParserInterface) {
178
  $e->appendMessage(sprintf(' (expecting closing tag for the "%s" tag defined near line %s).', $test[0]->getTag(), $lineno));
179
  }
180
  } else {
181
+ $e = new Twig_Error_Syntax(sprintf('Unknown "%s" tag.', $token->getValue()), $token->getLine(), $this->stream->getSourceContext());
182
  $e->addSuggestions($token->getValue(), array_keys($this->env->getTags()));
183
  }
184
 
194
  break;
195
 
196
  default:
197
+ throw new Twig_Error_Syntax('Lexer or parser ended up in unsupported state.', $this->getCurrentToken()->getLine(), $this->stream->getSourceContext());
198
  }
199
  }
200
 
268
  public function setMacro($name, Twig_Node_Macro $node)
269
  {
270
  if ($this->isReservedMacroName($name)) {
271
+ throw new Twig_Error_Syntax(sprintf('"%s" cannot be used as a macro name as it is a reserved keyword.', $name), $node->getTemplateLine(), $this->stream->getSourceContext());
272
  }
273
 
274
  $this->macros[$name] = $node;
380
  (!$node instanceof Twig_Node_Text && !$node instanceof Twig_Node_BlockReference && $node instanceof Twig_NodeOutputInterface)
381
  ) {
382
  if (false !== strpos((string) $node, chr(0xEF).chr(0xBB).chr(0xBF))) {
383
+ throw new Twig_Error_Syntax('A template that extends another one cannot start with a byte order mark (BOM); it must be removed.', $node->getTemplateLine(), $this->stream->getSourceContext());
384
  }
385
 
386
+ throw new Twig_Error_Syntax('A template that extends another one cannot include contents outside Twig blocks. Did you forget to put the contents inside a {% block %} tag?', $node->getTemplateLine(), $this->stream->getSourceContext());
387
  }
388
 
389
+ // bypass nodes that will "capture" the output
390
+ if ($node instanceof Twig_NodeCaptureInterface) {
391
  return $node;
392
  }
393
 
library/twig/twig/lib/Twig/ParserInterface.php CHANGED
@@ -3,7 +3,7 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Profiler/Dumper/Blackfire.php CHANGED
@@ -3,7 +3,7 @@
3
  /*
4
  * This file is part of Twig.
5
  *
6
- * (c) 2015 Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
@@ -11,6 +11,8 @@
11
 
12
  /**
13
  * @author Fabien Potencier <fabien@symfony.com>
 
 
14
  */
15
  class Twig_Profiler_Dumper_Blackfire
16
  {
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
11
 
12
  /**
13
  * @author Fabien Potencier <fabien@symfony.com>
14
+ *
15
+ * @final
16
  */
17
  class Twig_Profiler_Dumper_Blackfire
18
  {
library/twig/twig/lib/Twig/Profiler/Dumper/Html.php CHANGED
@@ -3,7 +3,7 @@
3
  /*
4
  * This file is part of Twig.
5
  *
6
- * (c) 2015 Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
@@ -11,6 +11,8 @@
11
 
12
  /**
13
  * @author Fabien Potencier <fabien@symfony.com>
 
 
14
  */
15
  class Twig_Profiler_Dumper_Html extends Twig_Profiler_Dumper_Text
16
  {
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
11
 
12
  /**
13
  * @author Fabien Potencier <fabien@symfony.com>
14
+ *
15
+ * @final
16
  */
17
  class Twig_Profiler_Dumper_Html extends Twig_Profiler_Dumper_Text
18
  {
library/twig/twig/lib/Twig/Profiler/Dumper/Text.php CHANGED
@@ -3,7 +3,7 @@
3
  /*
4
  * This file is part of Twig.
5
  *
6
- * (c) 2015 Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
@@ -11,6 +11,8 @@
11
 
12
  /**
13
  * @author Fabien Potencier <fabien@symfony.com>
 
 
14
  */
15
  class Twig_Profiler_Dumper_Text
16
  {
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
11
 
12
  /**
13
  * @author Fabien Potencier <fabien@symfony.com>
14
+ *
15
+ * @final
16
  */
17
  class Twig_Profiler_Dumper_Text
18
  {
library/twig/twig/lib/Twig/Profiler/Node/EnterProfile.php CHANGED
@@ -3,7 +3,7 @@
3
  /*
4
  * This file is part of Twig.
5
  *
6
- * (c) 2015 Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
@@ -21,9 +21,6 @@ class Twig_Profiler_Node_EnterProfile extends Twig_Node
21
  parent::__construct(array(), array('extension_name' => $extensionName, 'name' => $name, 'type' => $type, 'var_name' => $varName));
22
  }
23
 
24
- /**
25
- * {@inheritdoc}
26
- */
27
  public function compile(Twig_Compiler $compiler)
28
  {
29
  $compiler
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
21
  parent::__construct(array(), array('extension_name' => $extensionName, 'name' => $name, 'type' => $type, 'var_name' => $varName));
22
  }
23
 
 
 
 
24
  public function compile(Twig_Compiler $compiler)
25
  {
26
  $compiler
library/twig/twig/lib/Twig/Profiler/Node/LeaveProfile.php CHANGED
@@ -3,7 +3,7 @@
3
  /*
4
  * This file is part of Twig.
5
  *
6
- * (c) 2015 Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
@@ -21,9 +21,6 @@ class Twig_Profiler_Node_LeaveProfile extends Twig_Node
21
  parent::__construct(array(), array('var_name' => $varName));
22
  }
23
 
24
- /**
25
- * {@inheritdoc}
26
- */
27
  public function compile(Twig_Compiler $compiler)
28
  {
29
  $compiler
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
21
  parent::__construct(array(), array('var_name' => $varName));
22
  }
23
 
 
 
 
24
  public function compile(Twig_Compiler $compiler)
25
  {
26
  $compiler
library/twig/twig/lib/Twig/Profiler/NodeVisitor/Profiler.php CHANGED
@@ -3,7 +3,7 @@
3
  /*
4
  * This file is part of Twig.
5
  *
6
- * (c) 2015 Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
@@ -11,6 +11,8 @@
11
 
12
  /**
13
  * @author Fabien Potencier <fabien@symfony.com>
 
 
14
  */
15
  class Twig_Profiler_NodeVisitor_Profiler extends Twig_BaseNodeVisitor
16
  {
@@ -21,17 +23,11 @@ class Twig_Profiler_NodeVisitor_Profiler extends Twig_BaseNodeVisitor
21
  $this->extensionName = $extensionName;
22
  }
23
 
24
- /**
25
- * {@inheritdoc}
26
- */
27
  protected function doEnterNode(Twig_Node $node, Twig_Environment $env)
28
  {
29
  return $node;
30
  }
31
 
32
- /**
33
- * {@inheritdoc}
34
- */
35
  protected function doLeaveNode(Twig_Node $node, Twig_Environment $env)
36
  {
37
  if ($node instanceof Twig_Node_Module) {
@@ -62,9 +58,6 @@ class Twig_Profiler_NodeVisitor_Profiler extends Twig_BaseNodeVisitor
62
  return sprintf('__internal_%s', hash('sha256', uniqid(mt_rand(), true), false));
63
  }
64
 
65
- /**
66
- * {@inheritdoc}
67
- */
68
  public function getPriority()
69
  {
70
  return 0;
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
11
 
12
  /**
13
  * @author Fabien Potencier <fabien@symfony.com>
14
+ *
15
+ * @final
16
  */
17
  class Twig_Profiler_NodeVisitor_Profiler extends Twig_BaseNodeVisitor
18
  {
23
  $this->extensionName = $extensionName;
24
  }
25
 
 
 
 
26
  protected function doEnterNode(Twig_Node $node, Twig_Environment $env)
27
  {
28
  return $node;
29
  }
30
 
 
 
 
31
  protected function doLeaveNode(Twig_Node $node, Twig_Environment $env)
32
  {
33
  if ($node instanceof Twig_Node_Module) {
58
  return sprintf('__internal_%s', hash('sha256', uniqid(mt_rand(), true), false));
59
  }
60
 
 
 
 
61
  public function getPriority()
62
  {
63
  return 0;
library/twig/twig/lib/Twig/Profiler/Profile.php CHANGED
@@ -3,7 +3,7 @@
3
  /*
4
  * This file is part of Twig.
5
  *
6
- * (c) 2015 Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
@@ -11,6 +11,8 @@
11
 
12
  /**
13
  * @author Fabien Potencier <fabien@symfony.com>
 
 
14
  */
15
  class Twig_Profiler_Profile implements IteratorAggregate, Serializable
16
  {
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
11
 
12
  /**
13
  * @author Fabien Potencier <fabien@symfony.com>
14
+ *
15
+ * @final
16
  */
17
  class Twig_Profiler_Profile implements IteratorAggregate, Serializable
18
  {
library/twig/twig/lib/Twig/Sandbox/SecurityError.php CHANGED
@@ -3,7 +3,7 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Sandbox/SecurityNotAllowedFilterError.php CHANGED
@@ -3,7 +3,7 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Sandbox/SecurityNotAllowedFunctionError.php CHANGED
@@ -3,7 +3,7 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Sandbox/SecurityNotAllowedMethodError.php CHANGED
@@ -3,7 +3,7 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Sandbox/SecurityNotAllowedPropertyError.php CHANGED
@@ -3,7 +3,7 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Sandbox/SecurityNotAllowedTagError.php CHANGED
@@ -3,7 +3,7 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Sandbox/SecurityPolicy.php CHANGED
@@ -3,7 +3,7 @@
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.
@@ -12,6 +12,8 @@
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
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
12
  /**
13
  * Represents a security policy which need to be enforced when sandbox mode is enabled.
14
  *
15
+ * @final
16
+ *
17
  * @author Fabien Potencier <fabien@symfony.com>
18
  */
19
  class Twig_Sandbox_SecurityPolicy implements Twig_Sandbox_SecurityPolicyInterface
library/twig/twig/lib/Twig/Sandbox/SecurityPolicyInterface.php CHANGED
@@ -3,7 +3,7 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/SimpleFilter.php CHANGED
@@ -3,7 +3,7 @@
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.
@@ -12,6 +12,8 @@
12
  /**
13
  * Represents a template filter.
14
  *
 
 
15
  * @author Fabien Potencier <fabien@symfony.com>
16
  */
17
  class Twig_SimpleFilter
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
12
  /**
13
  * Represents a template filter.
14
  *
15
+ * @final
16
+ *
17
  * @author Fabien Potencier <fabien@symfony.com>
18
  */
19
  class Twig_SimpleFilter
library/twig/twig/lib/Twig/SimpleFunction.php CHANGED
@@ -3,7 +3,7 @@
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.
@@ -12,6 +12,8 @@
12
  /**
13
  * Represents a template function.
14
  *
 
 
15
  * @author Fabien Potencier <fabien@symfony.com>
16
  */
17
  class Twig_SimpleFunction
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
12
  /**
13
  * Represents a template function.
14
  *
15
+ * @final
16
+ *
17
  * @author Fabien Potencier <fabien@symfony.com>
18
  */
19
  class Twig_SimpleFunction
library/twig/twig/lib/Twig/SimpleTest.php CHANGED
@@ -3,7 +3,7 @@
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.
@@ -12,6 +12,8 @@
12
  /**
13
  * Represents a template test.
14
  *
 
 
15
  * @author Fabien Potencier <fabien@symfony.com>
16
  */
17
  class Twig_SimpleTest
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
12
  /**
13
  * Represents a template test.
14
  *
15
+ * @final
16
+ *
17
  * @author Fabien Potencier <fabien@symfony.com>
18
  */
19
  class Twig_SimpleTest
library/twig/twig/lib/Twig/Source.php CHANGED
@@ -3,7 +3,7 @@
3
  /*
4
  * This file is part of Twig.
5
  *
6
- * (c) 2016 Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
@@ -12,6 +12,8 @@
12
  /**
13
  * Holds information about a non-compiled Twig template.
14
  *
 
 
15
  * @author Fabien Potencier <fabien@symfony.com>
16
  */
17
  class Twig_Source
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
12
  /**
13
  * Holds information about a non-compiled Twig template.
14
  *
15
+ * @final
16
+ *
17
  * @author Fabien Potencier <fabien@symfony.com>
18
  */
19
  class Twig_Source
library/twig/twig/lib/Twig/SourceContextLoaderInterface.php CHANGED
@@ -3,7 +3,7 @@
3
  /*
4
  * This file is part of Twig.
5
  *
6
- * (c) 2016 Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Template.php CHANGED
@@ -3,8 +3,8 @@
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.
@@ -39,6 +39,14 @@ abstract class Twig_Template implements Twig_TemplateInterface
39
  $this->env = $env;
40
  }
41
 
 
 
 
 
 
 
 
 
42
  /**
43
  * Returns the template name.
44
  *
@@ -125,7 +133,7 @@ abstract class Twig_Template implements Twig_TemplateInterface
125
  $this->parents[$parent] = $this->loadTemplate($parent);
126
  }
127
  } catch (Twig_Error_Loader $e) {
128
- $e->setTemplateName(null);
129
  $e->guess();
130
 
131
  throw $e;
@@ -165,7 +173,7 @@ abstract class Twig_Template implements Twig_TemplateInterface
165
  } elseif (false !== $parent = $this->getParent($context)) {
166
  $parent->displayBlock($name, $context, $blocks, false);
167
  } else {
168
- throw new Twig_Error_Runtime(sprintf('The template has no parent and no traits defining the "%s" block.', $name), -1, $this->getTemplateName());
169
  }
170
  }
171
 
@@ -197,17 +205,17 @@ abstract class Twig_Template implements Twig_TemplateInterface
197
  $block = null;
198
  }
199
 
200
- if (null !== $template) {
201
- // avoid RCEs when sandbox is enabled
202
- if (!$template instanceof self) {
203
- throw new LogicException('A block must be a method on a Twig_Template instance.');
204
- }
205
 
 
206
  try {
207
  $template->$block($context, $blocks);
208
  } catch (Twig_Error $e) {
209
- if (!$e->getTemplateName()) {
210
- $e->setTemplateName($template->getTemplateName());
211
  }
212
 
213
  // this is mostly useful for Twig_Error_Loader exceptions
@@ -219,10 +227,12 @@ abstract class Twig_Template implements Twig_TemplateInterface
219
 
220
  throw $e;
221
  } catch (Exception $e) {
222
- throw new Twig_Error_Runtime(sprintf('An exception has been thrown during the rendering of a template ("%s").', $e->getMessage()), -1, $template->getTemplateName(), $e);
223
  }
224
  } elseif (false !== $parent = $this->getParent($context)) {
225
  $parent->displayBlock($name, $context, array_merge($this->blocks, $blocks), false);
 
 
226
  }
227
  }
228
 
@@ -355,8 +365,8 @@ abstract class Twig_Template implements Twig_TemplateInterface
355
 
356
  return $this->env->loadTemplate($template, $index);
357
  } catch (Twig_Error $e) {
358
- if (!$e->getTemplateName()) {
359
- $e->setTemplateName($templateName ? $templateName : $this->getTemplateName());
360
  }
361
 
362
  if ($e->getTemplateLine()) {
@@ -388,17 +398,11 @@ abstract class Twig_Template implements Twig_TemplateInterface
388
  return $this->blocks;
389
  }
390
 
391
- /**
392
- * {@inheritdoc}
393
- */
394
  public function display(array $context, array $blocks = array())
395
  {
396
  $this->displayWithErrorHandling($this->env->mergeGlobals($context), array_merge($this->blocks, $blocks));
397
  }
398
 
399
- /**
400
- * {@inheritdoc}
401
- */
402
  public function render(array $context)
403
  {
404
  $level = ob_get_level();
@@ -427,8 +431,8 @@ abstract class Twig_Template implements Twig_TemplateInterface
427
  try {
428
  $this->doDisplay($context, $blocks);
429
  } catch (Twig_Error $e) {
430
- if (!$e->getTemplateName()) {
431
- $e->setTemplateName($this->getTemplateName());
432
  }
433
 
434
  // this is mostly useful for Twig_Error_Loader exceptions
@@ -440,7 +444,7 @@ abstract class Twig_Template implements Twig_TemplateInterface
440
 
441
  throw $e;
442
  } catch (Exception $e) {
443
- throw new Twig_Error_Runtime(sprintf('An exception has been thrown during the rendering of a template ("%s").', $e->getMessage()), -1, $this->getTemplateName(), $e);
444
  }
445
  }
446
 
@@ -480,7 +484,7 @@ abstract class Twig_Template implements Twig_TemplateInterface
480
  return;
481
  }
482
 
483
- throw new Twig_Error_Runtime(sprintf('Variable "%s" does not exist.', $item), -1, $this->getTemplateName());
484
  }
485
 
486
  return $context[$item];
@@ -549,7 +553,7 @@ abstract class Twig_Template implements Twig_TemplateInterface
549
  $message = sprintf('Impossible to access an attribute ("%s") on a %s variable ("%s").', $item, gettype($object), $object);
550
  }
551
 
552
- throw new Twig_Error_Runtime($message, -1, $this->getTemplateName());
553
  }
554
  }
555
 
@@ -568,7 +572,7 @@ abstract class Twig_Template implements Twig_TemplateInterface
568
  $message = sprintf('Impossible to invoke a method ("%s") on a %s variable ("%s").', $item, gettype($object), $object);
569
  }
570
 
571
- throw new Twig_Error_Runtime($message, -1, $this->getTemplateName());
572
  }
573
 
574
  // object property
@@ -650,7 +654,7 @@ abstract class Twig_Template implements Twig_TemplateInterface
650
  return;
651
  }
652
 
653
- throw new Twig_Error_Runtime(sprintf('Neither the property "%1$s" nor one of the methods "%1$s()", "get%1$s()"/"is%1$s()" or "__call()" exist and have public access in class "%2$s".', $item, $class), -1, $this->getTemplateName());
654
  }
655
 
656
  if ($isDefinedTest) {
@@ -679,7 +683,7 @@ abstract class Twig_Template implements Twig_TemplateInterface
679
  // @deprecated in 1.28
680
  if ($object instanceof Twig_TemplateInterface) {
681
  $self = $object->getTemplateName() === $this->getTemplateName();
682
- $message = sprintf('Calling "%s" on template "%s" from template "%s" is deprecated since version 1.28 and won\'t be supported anymore in 2.0.', $method, $object->getTemplateName(), $this->getTemplateName());
683
  if ('renderBlock' === $method || 'displayBlock' === $method) {
684
  $message .= sprintf(' Use block("%s"%s) instead).', $arguments[0], $self ? '' : ', template');
685
  } elseif ('hasBlock' === $method) {
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
+ * (c) Armin Ronacher
8
  *
9
  * For the full copyright and license information, please view the LICENSE
10
  * file that was distributed with this source code.
39
  $this->env = $env;
40
  }
41
 
42
+ /**
43
+ * @internal this method will be removed in 2.0 and is only used internally to provide an upgrade path from 1.x to 2.0
44
+ */
45
+ public function __toString()
46
+ {
47
+ return $this->getTemplateName();
48
+ }
49
+
50
  /**
51
  * Returns the template name.
52
  *
133
  $this->parents[$parent] = $this->loadTemplate($parent);
134
  }
135
  } catch (Twig_Error_Loader $e) {
136
+ $e->setSourceContext(null);
137
  $e->guess();
138
 
139
  throw $e;
173
  } elseif (false !== $parent = $this->getParent($context)) {
174
  $parent->displayBlock($name, $context, $blocks, false);
175
  } else {
176
+ throw new Twig_Error_Runtime(sprintf('The template has no parent and no traits defining the "%s" block.', $name), -1, $this->getSourceContext());
177
  }
178
  }
179
 
205
  $block = null;
206
  }
207
 
208
+ // avoid RCEs when sandbox is enabled
209
+ if (null !== $template && !$template instanceof self) {
210
+ throw new LogicException('A block must be a method on a Twig_Template instance.');
211
+ }
 
212
 
213
+ if (null !== $template) {
214
  try {
215
  $template->$block($context, $blocks);
216
  } catch (Twig_Error $e) {
217
+ if (!$e->getSourceContext()) {
218
+ $e->setSourceContext($template->getSourceContext());
219
  }
220
 
221
  // this is mostly useful for Twig_Error_Loader exceptions
227
 
228
  throw $e;
229
  } catch (Exception $e) {
230
+ throw new Twig_Error_Runtime(sprintf('An exception has been thrown during the rendering of a template ("%s").', $e->getMessage()), -1, $template->getSourceContext(), $e);
231
  }
232
  } elseif (false !== $parent = $this->getParent($context)) {
233
  $parent->displayBlock($name, $context, array_merge($this->blocks, $blocks), false);
234
+ } else {
235
+ @trigger_error(sprintf('Silent display of undefined block "%s" in template "%s" is deprecated since version 1.29 and will throw an exception in 2.0. Use the "block(\'%s\') is defined" expression to test for block existence.', $name, $this->getTemplateName(), $name), E_USER_DEPRECATED);
236
  }
237
  }
238
 
365
 
366
  return $this->env->loadTemplate($template, $index);
367
  } catch (Twig_Error $e) {
368
+ if (!$e->getSourceContext()) {
369
+ $e->setSourceContext($templateName ? new Twig_Source('', $templateName) : $this->getSourceContext());
370
  }
371
 
372
  if ($e->getTemplateLine()) {
398
  return $this->blocks;
399
  }
400
 
 
 
 
401
  public function display(array $context, array $blocks = array())
402
  {
403
  $this->displayWithErrorHandling($this->env->mergeGlobals($context), array_merge($this->blocks, $blocks));
404
  }
405
 
 
 
 
406
  public function render(array $context)
407
  {
408
  $level = ob_get_level();
431
  try {
432
  $this->doDisplay($context, $blocks);
433
  } catch (Twig_Error $e) {
434
+ if (!$e->getSourceContext()) {
435
+ $e->setSourceContext($this->getSourceContext());
436
  }
437
 
438
  // this is mostly useful for Twig_Error_Loader exceptions
444
 
445
  throw $e;
446
  } catch (Exception $e) {
447
+ throw new Twig_Error_Runtime(sprintf('An exception has been thrown during the rendering of a template ("%s").', $e->getMessage()), -1, $this->getSourceContext(), $e);
448
  }
449
  }
450
 
484
  return;
485
  }
486
 
487
+ throw new Twig_Error_Runtime(sprintf('Variable "%s" does not exist.', $item), -1, $this->getSourceContext());
488
  }
489
 
490
  return $context[$item];
553
  $message = sprintf('Impossible to access an attribute ("%s") on a %s variable ("%s").', $item, gettype($object), $object);
554
  }
555
 
556
+ throw new Twig_Error_Runtime($message, -1, $this->getSourceContext());
557
  }
558
  }
559
 
572
  $message = sprintf('Impossible to invoke a method ("%s") on a %s variable ("%s").', $item, gettype($object), $object);
573
  }
574
 
575
+ throw new Twig_Error_Runtime($message, -1, $this->getSourceContext());
576
  }
577
 
578
  // object property
654
  return;
655
  }
656
 
657
+ throw new Twig_Error_Runtime(sprintf('Neither the property "%1$s" nor one of the methods "%1$s()", "get%1$s()"/"is%1$s()" or "__call()" exist and have public access in class "%2$s".', $item, $class), -1, $this->getSourceContext());
658
  }
659
 
660
  if ($isDefinedTest) {
683
  // @deprecated in 1.28
684
  if ($object instanceof Twig_TemplateInterface) {
685
  $self = $object->getTemplateName() === $this->getTemplateName();
686
+ $message = sprintf('Calling "%s" on template "%s" from template "%s" is deprecated since version 1.28 and won\'t be supported anymore in 2.0.', $item, $object->getTemplateName(), $this->getTemplateName());
687
  if ('renderBlock' === $method || 'displayBlock' === $method) {
688
  $message .= sprintf(' Use block("%s"%s) instead).', $arguments[0], $self ? '' : ', template');
689
  } elseif ('hasBlock' === $method) {
library/twig/twig/lib/Twig/TemplateInterface.php CHANGED
@@ -3,7 +3,7 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/TemplateWrapper.php CHANGED
@@ -3,7 +3,7 @@
3
  /*
4
  * This file is part of Twig.
5
  *
6
- * (c) 2016 Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Test.php CHANGED
@@ -3,7 +3,7 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Test/Function.php CHANGED
@@ -3,7 +3,7 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Test/IntegrationTestCase.php CHANGED
@@ -3,7 +3,7 @@
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.
@@ -173,12 +173,6 @@ abstract class Twig_Test_IntegrationTestCase extends PHPUnit_Framework_TestCase
173
  return;
174
  }
175
 
176
- if ($e instanceof Twig_Error_Syntax) {
177
- $e->setTemplateName($file);
178
-
179
- throw $e;
180
- }
181
-
182
  throw new Twig_Error(sprintf('%s: %s', get_class($e), $e->getMessage()), -1, $file, $e);
183
  }
184
 
@@ -191,11 +185,7 @@ abstract class Twig_Test_IntegrationTestCase extends PHPUnit_Framework_TestCase
191
  return;
192
  }
193
 
194
- if ($e instanceof Twig_Error_Syntax) {
195
- $e->setTemplateName($file);
196
- } else {
197
- $e = new Twig_Error(sprintf('%s: %s', get_class($e), $e->getMessage()), -1, $file, $e);
198
- }
199
 
200
  $output = trim(sprintf('%s: %s', get_class($e), $e->getMessage()));
201
  }
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
173
  return;
174
  }
175
 
 
 
 
 
 
 
176
  throw new Twig_Error(sprintf('%s: %s', get_class($e), $e->getMessage()), -1, $file, $e);
177
  }
178
 
185
  return;
186
  }
187
 
188
+ $e = new Twig_Error(sprintf('%s: %s', get_class($e), $e->getMessage()), -1, $file, $e);
 
 
 
 
189
 
190
  $output = trim(sprintf('%s: %s', get_class($e), $e->getMessage()));
191
  }
library/twig/twig/lib/Twig/Test/Method.php CHANGED
@@ -3,7 +3,7 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Test/Node.php CHANGED
@@ -3,7 +3,7 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/TestCallableInterface.php CHANGED
@@ -3,7 +3,7 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/TestInterface.php CHANGED
@@ -3,7 +3,7 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/Token.php CHANGED
@@ -3,8 +3,8 @@
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.
@@ -14,6 +14,8 @@
14
  * Represents a Token.
15
  *
16
  * @author Fabien Potencier <fabien@symfony.com>
 
 
17
  */
18
  class Twig_Token
19
  {
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
+ * (c) Armin Ronacher
8
  *
9
  * For the full copyright and license information, please view the LICENSE
10
  * file that was distributed with this source code.
14
  * Represents a Token.
15
  *
16
  * @author Fabien Potencier <fabien@symfony.com>
17
+ *
18
+ * @final
19
  */
20
  class Twig_Token
21
  {
library/twig/twig/lib/Twig/TokenParser.php CHANGED
@@ -3,7 +3,7 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/TokenParser/AutoEscape.php CHANGED
@@ -3,7 +3,7 @@
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.
@@ -26,6 +26,8 @@
26
  * using the js escaping strategy
27
  * {% endautoescape %}
28
  * </pre>
 
 
29
  */
30
  class Twig_TokenParser_AutoEscape extends Twig_TokenParser
31
  {
@@ -39,7 +41,7 @@ class Twig_TokenParser_AutoEscape extends Twig_TokenParser
39
  } else {
40
  $expr = $this->parser->getExpressionParser()->parseExpression();
41
  if (!$expr instanceof Twig_Node_Expression_Constant) {
42
- throw new Twig_Error_Syntax('An escaping strategy must be a string or a bool.', $stream->getCurrent()->getLine(), $stream->getSourceContext()->getName());
43
  }
44
  $value = $expr->getAttribute('value');
45
 
@@ -53,7 +55,7 @@ class Twig_TokenParser_AutoEscape extends Twig_TokenParser
53
  @trigger_error('Using the autoescape tag with "true" or "false" before the strategy name is deprecated since version 1.21.', E_USER_DEPRECATED);
54
 
55
  if (false === $value) {
56
- throw new Twig_Error_Syntax('Unexpected escaping strategy as you set autoescaping to false.', $stream->getCurrent()->getLine(), $stream->getSourceContext()->getName());
57
  }
58
 
59
  $value = $stream->next()->getValue();
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
26
  * using the js escaping strategy
27
  * {% endautoescape %}
28
  * </pre>
29
+ *
30
+ * @final
31
  */
32
  class Twig_TokenParser_AutoEscape extends Twig_TokenParser
33
  {
41
  } else {
42
  $expr = $this->parser->getExpressionParser()->parseExpression();
43
  if (!$expr instanceof Twig_Node_Expression_Constant) {
44
+ throw new Twig_Error_Syntax('An escaping strategy must be a string or a bool.', $stream->getCurrent()->getLine(), $stream->getSourceContext());
45
  }
46
  $value = $expr->getAttribute('value');
47
 
55
  @trigger_error('Using the autoescape tag with "true" or "false" before the strategy name is deprecated since version 1.21.', E_USER_DEPRECATED);
56
 
57
  if (false === $value) {
58
+ throw new Twig_Error_Syntax('Unexpected escaping strategy as you set autoescaping to false.', $stream->getCurrent()->getLine(), $stream->getSourceContext());
59
  }
60
 
61
  $value = $stream->next()->getValue();
library/twig/twig/lib/Twig/TokenParser/Block.php CHANGED
@@ -3,8 +3,8 @@
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.
@@ -19,6 +19,8 @@
19
  * <title>{% block title %}{% endblock %} - My Webpage</title>
20
  * {% endblock %}
21
  * </pre>
 
 
22
  */
23
  class Twig_TokenParser_Block extends Twig_TokenParser
24
  {
@@ -28,7 +30,7 @@ class Twig_TokenParser_Block extends Twig_TokenParser
28
  $stream = $this->parser->getStream();
29
  $name = $stream->expect(Twig_Token::NAME_TYPE)->getValue();
30
  if ($this->parser->hasBlock($name)) {
31
- throw new Twig_Error_Syntax(sprintf("The block '%s' has already been defined line %d.", $name, $this->parser->getBlock($name)->getTemplateLine()), $stream->getCurrent()->getLine(), $stream->getSourceContext()->getName());
32
  }
33
  $this->parser->setBlock($name, $block = new Twig_Node_Block($name, new Twig_Node(array()), $lineno));
34
  $this->parser->pushLocalScope();
@@ -40,7 +42,7 @@ class Twig_TokenParser_Block extends Twig_TokenParser
40
  $value = $token->getValue();
41
 
42
  if ($value != $name) {
43
- throw new Twig_Error_Syntax(sprintf('Expected endblock for block "%s" (but "%s" given).', $name, $value), $stream->getCurrent()->getLine(), $stream->getSourceContext()->getName());
44
  }
45
  }
46
  } else {
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
+ * (c) Armin Ronacher
8
  *
9
  * For the full copyright and license information, please view the LICENSE
10
  * file that was distributed with this source code.
19
  * <title>{% block title %}{% endblock %} - My Webpage</title>
20
  * {% endblock %}
21
  * </pre>
22
+ *
23
+ * @final
24
  */
25
  class Twig_TokenParser_Block extends Twig_TokenParser
26
  {
30
  $stream = $this->parser->getStream();
31
  $name = $stream->expect(Twig_Token::NAME_TYPE)->getValue();
32
  if ($this->parser->hasBlock($name)) {
33
+ throw new Twig_Error_Syntax(sprintf("The block '%s' has already been defined line %d.", $name, $this->parser->getBlock($name)->getTemplateLine()), $stream->getCurrent()->getLine(), $stream->getSourceContext());
34
  }
35
  $this->parser->setBlock($name, $block = new Twig_Node_Block($name, new Twig_Node(array()), $lineno));
36
  $this->parser->pushLocalScope();
42
  $value = $token->getValue();
43
 
44
  if ($value != $name) {
45
+ throw new Twig_Error_Syntax(sprintf('Expected endblock for block "%s" (but "%s" given).', $name, $value), $stream->getCurrent()->getLine(), $stream->getSourceContext());
46
  }
47
  }
48
  } else {
library/twig/twig/lib/Twig/TokenParser/Do.php CHANGED
@@ -3,7 +3,7 @@
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.
@@ -11,6 +11,8 @@
11
 
12
  /**
13
  * Evaluates an expression, discarding the returned value.
 
 
14
  */
15
  class Twig_TokenParser_Do extends Twig_TokenParser
16
  {
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
11
 
12
  /**
13
  * Evaluates an expression, discarding the returned value.
14
+ *
15
+ * @final
16
  */
17
  class Twig_TokenParser_Do extends Twig_TokenParser
18
  {
library/twig/twig/lib/Twig/TokenParser/Embed.php CHANGED
@@ -3,7 +3,7 @@
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.
@@ -11,6 +11,8 @@
11
 
12
  /**
13
  * Embeds a template.
 
 
14
  */
15
  class Twig_TokenParser_Embed extends Twig_TokenParser_Include
16
  {
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
11
 
12
  /**
13
  * Embeds a template.
14
+ *
15
+ * @final
16
  */
17
  class Twig_TokenParser_Embed extends Twig_TokenParser_Include
18
  {
library/twig/twig/lib/Twig/TokenParser/Extends.php CHANGED
@@ -3,8 +3,8 @@
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.
@@ -16,6 +16,8 @@
16
  * <pre>
17
  * {% extends "base.html" %}
18
  * </pre>
 
 
19
  */
20
  class Twig_TokenParser_Extends extends Twig_TokenParser
21
  {
@@ -24,11 +26,11 @@ class Twig_TokenParser_Extends extends Twig_TokenParser
24
  $stream = $this->parser->getStream();
25
 
26
  if (!$this->parser->isMainScope()) {
27
- throw new Twig_Error_Syntax('Cannot extend from a block.', $token->getLine(), $stream->getSourceContext()->getName());
28
  }
29
 
30
  if (null !== $this->parser->getParent()) {
31
- throw new Twig_Error_Syntax('Multiple extends tags are forbidden.', $token->getLine(), $stream->getSourceContext()->getName());
32
  }
33
  $this->parser->setParent($this->parser->getExpressionParser()->parseExpression());
34
 
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
+ * (c) Armin Ronacher
8
  *
9
  * For the full copyright and license information, please view the LICENSE
10
  * file that was distributed with this source code.
16
  * <pre>
17
  * {% extends "base.html" %}
18
  * </pre>
19
+ *
20
+ * @final
21
  */
22
  class Twig_TokenParser_Extends extends Twig_TokenParser
23
  {
26
  $stream = $this->parser->getStream();
27
 
28
  if (!$this->parser->isMainScope()) {
29
+ throw new Twig_Error_Syntax('Cannot extend from a block.', $token->getLine(), $stream->getSourceContext());
30
  }
31
 
32
  if (null !== $this->parser->getParent()) {
33
+ throw new Twig_Error_Syntax('Multiple extends tags are forbidden.', $token->getLine(), $stream->getSourceContext());
34
  }
35
  $this->parser->setParent($this->parser->getExpressionParser()->parseExpression());
36
 
library/twig/twig/lib/Twig/TokenParser/Filter.php CHANGED
@@ -3,7 +3,7 @@
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.
@@ -17,6 +17,8 @@
17
  * This text becomes uppercase
18
  * {% endfilter %}
19
  * </pre>
 
 
20
  */
21
  class Twig_TokenParser_Filter extends Twig_TokenParser
22
  {
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
17
  * This text becomes uppercase
18
  * {% endfilter %}
19
  * </pre>
20
+ *
21
+ * @final
22
  */
23
  class Twig_TokenParser_Filter extends Twig_TokenParser
24
  {
library/twig/twig/lib/Twig/TokenParser/Flush.php CHANGED
@@ -3,7 +3,7 @@
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.
@@ -13,6 +13,8 @@
13
  * Flushes the output to the client.
14
  *
15
  * @see flush()
 
 
16
  */
17
  class Twig_TokenParser_Flush extends Twig_TokenParser
18
  {
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
13
  * Flushes the output to the client.
14
  *
15
  * @see flush()
16
+ *
17
+ * @final
18
  */
19
  class Twig_TokenParser_Flush extends Twig_TokenParser
20
  {
library/twig/twig/lib/Twig/TokenParser/For.php CHANGED
@@ -3,8 +3,8 @@
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.
@@ -20,6 +20,8 @@
20
  * {% endfor %}
21
  * </ul>
22
  * </pre>
 
 
23
  */
24
  class Twig_TokenParser_For extends Twig_TokenParser
25
  {
@@ -79,7 +81,7 @@ class Twig_TokenParser_For extends Twig_TokenParser
79
  protected function checkLoopUsageCondition(Twig_TokenStream $stream, Twig_NodeInterface $node)
80
  {
81
  if ($node instanceof Twig_Node_Expression_GetAttr && $node->getNode('node') instanceof Twig_Node_Expression_Name && 'loop' == $node->getNode('node')->getAttribute('name')) {
82
- throw new Twig_Error_Syntax('The "loop" variable cannot be used in a looping condition.', $node->getTemplateLine(), $stream->getSourceContext()->getName());
83
  }
84
 
85
  foreach ($node as $n) {
@@ -98,7 +100,7 @@ class Twig_TokenParser_For extends Twig_TokenParser
98
  if ($node instanceof Twig_Node_Expression_GetAttr && $node->getNode('node') instanceof Twig_Node_Expression_Name && 'loop' == $node->getNode('node')->getAttribute('name')) {
99
  $attribute = $node->getNode('attribute');
100
  if ($attribute instanceof Twig_Node_Expression_Constant && in_array($attribute->getAttribute('value'), array('length', 'revindex0', 'revindex', 'last'))) {
101
- throw new Twig_Error_Syntax(sprintf('The "loop.%s" variable is not defined when looping with a condition.', $attribute->getAttribute('value')), $node->getTemplateLine(), $stream->getSourceContext()->getName());
102
  }
103
  }
104
 
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
+ * (c) Armin Ronacher
8
  *
9
  * For the full copyright and license information, please view the LICENSE
10
  * file that was distributed with this source code.
20
  * {% endfor %}
21
  * </ul>
22
  * </pre>
23
+ *
24
+ * @final
25
  */
26
  class Twig_TokenParser_For extends Twig_TokenParser
27
  {
81
  protected function checkLoopUsageCondition(Twig_TokenStream $stream, Twig_NodeInterface $node)
82
  {
83
  if ($node instanceof Twig_Node_Expression_GetAttr && $node->getNode('node') instanceof Twig_Node_Expression_Name && 'loop' == $node->getNode('node')->getAttribute('name')) {
84
+ throw new Twig_Error_Syntax('The "loop" variable cannot be used in a looping condition.', $node->getTemplateLine(), $stream->getSourceContext());
85
  }
86
 
87
  foreach ($node as $n) {
100
  if ($node instanceof Twig_Node_Expression_GetAttr && $node->getNode('node') instanceof Twig_Node_Expression_Name && 'loop' == $node->getNode('node')->getAttribute('name')) {
101
  $attribute = $node->getNode('attribute');
102
  if ($attribute instanceof Twig_Node_Expression_Constant && in_array($attribute->getAttribute('value'), array('length', 'revindex0', 'revindex', 'last'))) {
103
+ throw new Twig_Error_Syntax(sprintf('The "loop.%s" variable is not defined when looping with a condition.', $attribute->getAttribute('value')), $node->getTemplateLine(), $stream->getSourceContext());
104
  }
105
  }
106
 
library/twig/twig/lib/Twig/TokenParser/From.php CHANGED
@@ -3,7 +3,7 @@
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.
@@ -15,6 +15,8 @@
15
  * <pre>
16
  * {% from 'forms.html' import forms %}
17
  * </pre>
 
 
18
  */
19
  class Twig_TokenParser_From extends Twig_TokenParser
20
  {
@@ -46,7 +48,7 @@ class Twig_TokenParser_From extends Twig_TokenParser
46
 
47
  foreach ($targets as $name => $alias) {
48
  if ($this->parser->isReservedMacroName($name)) {
49
- throw new Twig_Error_Syntax(sprintf('"%s" cannot be an imported macro as it is a reserved keyword.', $name), $token->getLine(), $stream->getSourceContext()->getName());
50
  }
51
 
52
  $this->parser->addImportedSymbol('function', $alias, 'get'.$name, $node->getNode('var'));
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
15
  * <pre>
16
  * {% from 'forms.html' import forms %}
17
  * </pre>
18
+ *
19
+ * @final
20
  */
21
  class Twig_TokenParser_From extends Twig_TokenParser
22
  {
48
 
49
  foreach ($targets as $name => $alias) {
50
  if ($this->parser->isReservedMacroName($name)) {
51
+ throw new Twig_Error_Syntax(sprintf('"%s" cannot be an imported macro as it is a reserved keyword.', $name), $token->getLine(), $stream->getSourceContext());
52
  }
53
 
54
  $this->parser->addImportedSymbol('function', $alias, 'get'.$name, $node->getNode('var'));
library/twig/twig/lib/Twig/TokenParser/If.php CHANGED
@@ -3,8 +3,8 @@
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.
@@ -22,6 +22,8 @@
22
  * </ul>
23
  * {% endif %}
24
  * </pre>
 
 
25
  */
26
  class Twig_TokenParser_If extends Twig_TokenParser
27
  {
@@ -56,7 +58,7 @@ class Twig_TokenParser_If extends Twig_TokenParser
56
  break;
57
 
58
  default:
59
- 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->getSourceContext()->getName());
60
  }
61
  }
62
 
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
+ * (c) Armin Ronacher
8
  *
9
  * For the full copyright and license information, please view the LICENSE
10
  * file that was distributed with this source code.
22
  * </ul>
23
  * {% endif %}
24
  * </pre>
25
+ *
26
+ * @final
27
  */
28
  class Twig_TokenParser_If extends Twig_TokenParser
29
  {
58
  break;
59
 
60
  default:
61
+ 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->getSourceContext());
62
  }
63
  }
64
 
library/twig/twig/lib/Twig/TokenParser/Import.php CHANGED
@@ -3,7 +3,7 @@
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.
@@ -15,6 +15,8 @@
15
  * <pre>
16
  * {% import 'forms.html' as forms %}
17
  * </pre>
 
 
18
  */
19
  class Twig_TokenParser_Import extends Twig_TokenParser
20
  {
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
15
  * <pre>
16
  * {% import 'forms.html' as forms %}
17
  * </pre>
18
+ *
19
+ * @final
20
  */
21
  class Twig_TokenParser_Import extends Twig_TokenParser
22
  {
library/twig/twig/lib/Twig/TokenParser/Include.php CHANGED
@@ -3,8 +3,8 @@
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.
@@ -18,6 +18,8 @@
18
  * Body
19
  * {% include 'footer.html' %}
20
  * </pre>
 
 
21
  */
22
  class Twig_TokenParser_Include extends Twig_TokenParser
23
  {
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
+ * (c) Armin Ronacher
8
  *
9
  * For the full copyright and license information, please view the LICENSE
10
  * file that was distributed with this source code.
18
  * Body
19
  * {% include 'footer.html' %}
20
  * </pre>
21
+ *
22
+ * @final
23
  */
24
  class Twig_TokenParser_Include extends Twig_TokenParser
25
  {
library/twig/twig/lib/Twig/TokenParser/Macro.php CHANGED
@@ -3,7 +3,7 @@
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.
@@ -17,6 +17,8 @@
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
  {
@@ -35,7 +37,7 @@ class Twig_TokenParser_Macro extends Twig_TokenParser
35
  $value = $token->getValue();
36
 
37
  if ($value != $name) {
38
- throw new Twig_Error_Syntax(sprintf('Expected endmacro for macro "%s" (but "%s" given).', $name, $value), $stream->getCurrent()->getLine(), $stream->getSourceContext()->getName());
39
  }
40
  }
41
  $this->parser->popLocalScope();
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
17
  * <input type="{{ type|default('text') }}" name="{{ name }}" value="{{ value|e }}" size="{{ size|default(20) }}" />
18
  * {% endmacro %}
19
  * </pre>
20
+ *
21
+ * @final
22
  */
23
  class Twig_TokenParser_Macro extends Twig_TokenParser
24
  {
37
  $value = $token->getValue();
38
 
39
  if ($value != $name) {
40
+ throw new Twig_Error_Syntax(sprintf('Expected endmacro for macro "%s" (but "%s" given).', $name, $value), $stream->getCurrent()->getLine(), $stream->getSourceContext());
41
  }
42
  }
43
  $this->parser->popLocalScope();
library/twig/twig/lib/Twig/TokenParser/Sandbox.php CHANGED
@@ -3,7 +3,7 @@
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.
@@ -19,6 +19,8 @@
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
  {
@@ -37,7 +39,7 @@ class Twig_TokenParser_Sandbox extends Twig_TokenParser
37
  }
38
 
39
  if (!$node instanceof Twig_Node_Include) {
40
- throw new Twig_Error_Syntax('Only "include" tags are allowed within a "sandbox" section.', $node->getTemplateLine(), $stream->getSourceContext()->getName());
41
  }
42
  }
43
  }
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
19
  * </pre>
20
  *
21
  * @see http://www.twig-project.org/doc/api.html#sandbox-extension for details
22
+ *
23
+ * @final
24
  */
25
  class Twig_TokenParser_Sandbox extends Twig_TokenParser
26
  {
39
  }
40
 
41
  if (!$node instanceof Twig_Node_Include) {
42
+ throw new Twig_Error_Syntax('Only "include" tags are allowed within a "sandbox" section.', $node->getTemplateLine(), $stream->getSourceContext());
43
  }
44
  }
45
  }
library/twig/twig/lib/Twig/TokenParser/Set.php CHANGED
@@ -3,7 +3,7 @@
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.
@@ -25,6 +25,8 @@
25
  *
26
  * {% set foo %}Some content{% endset %}
27
  * </pre>
 
 
28
  */
29
  class Twig_TokenParser_Set extends Twig_TokenParser
30
  {
@@ -41,13 +43,13 @@ class Twig_TokenParser_Set extends Twig_TokenParser
41
  $stream->expect(Twig_Token::BLOCK_END_TYPE);
42
 
43
  if (count($names) !== count($values)) {
44
- throw new Twig_Error_Syntax('When using set, you must have the same number of variables and assignments.', $stream->getCurrent()->getLine(), $stream->getSourceContext()->getName());
45
  }
46
  } else {
47
  $capture = true;
48
 
49
  if (count($names) > 1) {
50
- throw new Twig_Error_Syntax('When using set with a block, you cannot have a multi-target.', $stream->getCurrent()->getLine(), $stream->getSourceContext()->getName());
51
  }
52
 
53
  $stream->expect(Twig_Token::BLOCK_END_TYPE);
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
25
  *
26
  * {% set foo %}Some content{% endset %}
27
  * </pre>
28
+ *
29
+ * @final
30
  */
31
  class Twig_TokenParser_Set extends Twig_TokenParser
32
  {
43
  $stream->expect(Twig_Token::BLOCK_END_TYPE);
44
 
45
  if (count($names) !== count($values)) {
46
+ throw new Twig_Error_Syntax('When using set, you must have the same number of variables and assignments.', $stream->getCurrent()->getLine(), $stream->getSourceContext());
47
  }
48
  } else {
49
  $capture = true;
50
 
51
  if (count($names) > 1) {
52
+ throw new Twig_Error_Syntax('When using set with a block, you cannot have a multi-target.', $stream->getCurrent()->getLine(), $stream->getSourceContext());
53
  }
54
 
55
  $stream->expect(Twig_Token::BLOCK_END_TYPE);
library/twig/twig/lib/Twig/TokenParser/Spaceless.php CHANGED
@@ -3,7 +3,7 @@
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.
@@ -21,6 +21,8 @@
21
  *
22
  * {# output will be <div><strong>foo</strong></div> #}
23
  * </pre>
 
 
24
  */
25
  class Twig_TokenParser_Spaceless extends Twig_TokenParser
26
  {
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
21
  *
22
  * {# output will be <div><strong>foo</strong></div> #}
23
  * </pre>
24
+ *
25
+ * @final
26
  */
27
  class Twig_TokenParser_Spaceless extends Twig_TokenParser
28
  {
library/twig/twig/lib/Twig/TokenParser/Use.php CHANGED
@@ -3,7 +3,7 @@
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.
@@ -22,6 +22,8 @@
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
  {
@@ -31,7 +33,7 @@ class Twig_TokenParser_Use extends Twig_TokenParser
31
  $stream = $this->parser->getStream();
32
 
33
  if (!$template instanceof Twig_Node_Expression_Constant) {
34
- throw new Twig_Error_Syntax('The template references in a "use" statement must be a string.', $stream->getCurrent()->getLine(), $stream->getSourceContext()->getName());
35
  }
36
 
37
  $targets = array();
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
22
  * </pre>
23
  *
24
  * @see http://www.twig-project.org/doc/templates.html#horizontal-reuse for details.
25
+ *
26
+ * @final
27
  */
28
  class Twig_TokenParser_Use extends Twig_TokenParser
29
  {
33
  $stream = $this->parser->getStream();
34
 
35
  if (!$template instanceof Twig_Node_Expression_Constant) {
36
+ throw new Twig_Error_Syntax('The template references in a "use" statement must be a string.', $stream->getCurrent()->getLine(), $stream->getSourceContext());
37
  }
38
 
39
  $targets = array();
library/twig/twig/lib/Twig/TokenParser/With.php CHANGED
@@ -3,7 +3,7 @@
3
  /*
4
  * This file is part of Twig.
5
  *
6
- * (c) 2016 Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
@@ -13,6 +13,8 @@
13
  * Creates a nested scope.
14
  *
15
  * @author Fabien Potencier <fabien@symfony.com>
 
 
16
  */
17
  class Twig_TokenParser_With extends Twig_TokenParser
18
  {
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
13
  * Creates a nested scope.
14
  *
15
  * @author Fabien Potencier <fabien@symfony.com>
16
+ *
17
+ * @final
18
  */
19
  class Twig_TokenParser_With extends Twig_TokenParser
20
  {
library/twig/twig/lib/Twig/TokenParserBroker.php CHANGED
@@ -3,8 +3,8 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
+ * (c) 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.
library/twig/twig/lib/Twig/TokenParserBrokerInterface.php CHANGED
@@ -3,8 +3,8 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
+ * (c) 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.
library/twig/twig/lib/Twig/TokenParserInterface.php CHANGED
@@ -3,7 +3,7 @@
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.
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
  *
8
  * For the full copyright and license information, please view the LICENSE
9
  * file that was distributed with this source code.
library/twig/twig/lib/Twig/TokenStream.php CHANGED
@@ -3,8 +3,8 @@
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.
@@ -13,6 +13,8 @@
13
  /**
14
  * Represents a token stream.
15
  *
 
 
16
  * @author Fabien Potencier <fabien@symfony.com>
17
  */
18
  class Twig_TokenStream
@@ -63,7 +65,7 @@ class Twig_TokenStream
63
  public function next()
64
  {
65
  if (!isset($this->tokens[++$this->current])) {
66
- throw new Twig_Error_Syntax('Unexpected end of template.', $this->tokens[$this->current - 1]->getLine(), $this->source->getName());
67
  }
68
 
69
  return $this->tokens[$this->current - 1];
@@ -96,7 +98,7 @@ class Twig_TokenStream
96
  Twig_Token::typeToEnglish($token->getType()), $token->getValue(),
97
  Twig_Token::typeToEnglish($type), $value ? sprintf(' with value "%s"', $value) : ''),
98
  $line,
99
- $this->source->getName()
100
  );
101
  }
102
  $this->next();
@@ -114,7 +116,7 @@ class Twig_TokenStream
114
  public function look($number = 1)
115
  {
116
  if (!isset($this->tokens[$this->current + $number])) {
117
- throw new Twig_Error_Syntax('Unexpected end of template.', $this->tokens[$this->current + $number - 1]->getLine(), $this->source->getName());
118
  }
119
 
120
  return $this->tokens[$this->current + $number];
3
  /*
4
  * This file is part of Twig.
5
  *
6
+ * (c) Fabien Potencier
7
+ * (c) Armin Ronacher
8
  *
9
  * For the full copyright and license information, please view the LICENSE
10
  * file that was distributed with this source code.
13
  /**
14
  * Represents a token stream.
15
  *
16
+ * @final
17
+ *
18
  * @author Fabien Potencier <fabien@symfony.com>
19
  */
20
  class Twig_TokenStream
65
  public function next()
66
  {
67
  if (!isset($this->tokens[++$this->current])) {
68
+ throw new Twig_Error_Syntax('Unexpected end of template.', $this->tokens[$this->current - 1]->getLine(), $this->source);
69
  }
70
 
71
  return $this->tokens[$this->current - 1];
98
  Twig_Token::typeToEnglish($token->getType()), $token->getValue(),
99
  Twig_Token::typeToEnglish($type), $value ? sprintf(' with value "%s"', $value) : ''),
100
  $line,
101
+ $this->source
102
  );
103
  }
104
  $this->next();
116
  public function look($number = 1)
117
  {
118
  if (!isset($this->tokens[$this->current + $number])) {
119
+ throw new Twig_Error_Syntax('Unexpected end of template.', $this->tokens[$this->current + $number - 1]->getLine(), $this->source);
120
  }
121
 
122
  return $this->tokens[$this->current + $number];
library/twig/twig/lib/Twig/Util/DeprecationCollector.php CHANGED
@@ -11,6 +11,8 @@
11
 
12
  /**
13
  * @author Fabien Potencier <fabien@symfony.com>
 
 
14
  */
15
  class Twig_Util_DeprecationCollector
16
  {
11
 
12
  /**
13
  * @author Fabien Potencier <fabien@symfony.com>
14
+ *
15
+ * @final
16
  */
17
  class Twig_Util_DeprecationCollector
18
  {
library/twig/twig/phpunit.xml.dist ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+
3
+ <phpunit backupGlobals="false"
4
+ backupStaticAttributes="false"
5
+ colors="true"
6
+ convertErrorsToExceptions="true"
7
+ convertNoticesToExceptions="true"
8
+ convertWarningsToExceptions="true"
9
+ processIsolation="false"
10
+ stopOnFailure="false"
11
+ syntaxCheck="false"
12
+ bootstrap="vendor/autoload.php"
13
+ >
14
+ <testsuites>
15
+ <testsuite name="Twig Test Suite">
16
+ <directory>./test/Twig/</directory>
17
+ </testsuite>
18
+ </testsuites>
19
+
20
+ <php>
21
+ <ini name="error_reporting" value="-1" />
22
+ </php>
23
+
24
+ <listeners>
25
+ <listener class="Symfony\Bridge\PhpUnit\SymfonyTestsListener" />
26
+ </listeners>
27
+
28
+ <filter>
29
+ <whitelist>
30
+ <directory suffix=".php">./lib/Twig/</directory>
31
+ </whitelist>
32
+ </filter>
33
+ </phpunit>
library/twig/twig/test/Twig/Tests/AutoloaderTest.php ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 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_Tests_AutoloaderTest extends PHPUnit_Framework_TestCase
13
+ {
14
+ /**
15
+ * @group legacy
16
+ */
17
+ public function testAutoload()
18
+ {
19
+ $this->assertFalse(class_exists('FooBarFoo'), '->autoload() does not try to load classes that does not begin with Twig');
20
+
21
+ $autoloader = new Twig_Autoloader();
22
+ $this->assertNull($autoloader->autoload('Foo'), '->autoload() returns false if it is not able to load a class');
23
+ }
24
+ }
library/twig/twig/test/Twig/Tests/Cache/FilesystemTest.php ADDED
@@ -0,0 +1,193 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 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
+ require_once dirname(dirname(__FILE__)).'/FilesystemHelper.php';
13
+
14
+ class Twig_Tests_Cache_FilesystemTest extends PHPUnit_Framework_TestCase
15
+ {
16
+ private $classname;
17
+ private $directory;
18
+ private $cache;
19
+
20
+ protected function setUp()
21
+ {
22
+ $nonce = hash('sha256', uniqid(mt_rand(), true));
23
+ $this->classname = '__Twig_Tests_Cache_FilesystemTest_Template_'.$nonce;
24
+ $this->directory = sys_get_temp_dir().'/twig-test';
25
+ $this->cache = new Twig_Cache_Filesystem($this->directory);
26
+ }
27
+
28
+ protected function tearDown()
29
+ {
30
+ if (file_exists($this->directory)) {
31
+ Twig_Tests_FilesystemHelper::removeDir($this->directory);
32
+ }
33
+ }
34
+
35
+ public function testLoad()
36
+ {
37
+ $key = $this->directory.'/cache/cachefile.php';
38
+
39
+ $dir = dirname($key);
40
+ @mkdir($dir, 0777, true);
41
+ $this->assertTrue(is_dir($dir));
42
+ $this->assertFalse(class_exists($this->classname, false));
43
+
44
+ $content = $this->generateSource();
45
+ file_put_contents($key, $content);
46
+
47
+ $this->cache->load($key);
48
+
49
+ $this->assertTrue(class_exists($this->classname, false));
50
+ }
51
+
52
+ public function testLoadMissing()
53
+ {
54
+ $key = $this->directory.'/cache/cachefile.php';
55
+
56
+ $this->assertFalse(class_exists($this->classname, false));
57
+
58
+ $this->cache->load($key);
59
+
60
+ $this->assertFalse(class_exists($this->classname, false));
61
+ }
62
+
63
+ public function testWrite()
64
+ {
65
+ $key = $this->directory.'/cache/cachefile.php';
66
+ $content = $this->generateSource();
67
+
68
+ $this->assertFileNotExists($key);
69
+ $this->assertFileNotExists($this->directory);
70
+
71
+ $this->cache->write($key, $content);
72
+
73
+ $this->assertFileExists($this->directory);
74
+ $this->assertFileExists($key);
75
+ $this->assertSame(file_get_contents($key), $content);
76
+ }
77
+
78
+ /**
79
+ * @expectedException RuntimeException
80
+ * @expectedExceptionMessage Unable to create the cache directory
81
+ */
82
+ public function testWriteFailMkdir()
83
+ {
84
+ if (defined('PHP_WINDOWS_VERSION_BUILD')) {
85
+ $this->markTestSkipped('Read-only directories not possible on Windows.');
86
+ }
87
+
88
+ $key = $this->directory.'/cache/cachefile.php';
89
+ $content = $this->generateSource();
90
+
91
+ $this->assertFileNotExists($key);
92
+
93
+ // Create read-only root directory.
94
+ @mkdir($this->directory, 0555, true);
95
+ $this->assertTrue(is_dir($this->directory));
96
+
97
+ $this->cache->write($key, $content);
98
+ }
99
+
100
+ /**
101
+ * @expectedException RuntimeException
102
+ * @expectedExceptionMessage Unable to write in the cache directory
103
+ */
104
+ public function testWriteFailDirWritable()
105
+ {
106
+ if (defined('PHP_WINDOWS_VERSION_BUILD')) {
107
+ $this->markTestSkipped('Read-only directories not possible on Windows.');
108
+ }
109
+
110
+ $key = $this->directory.'/cache/cachefile.php';
111
+ $content = $this->generateSource();
112
+
113
+ $this->assertFileNotExists($key);
114
+
115
+ // Create root directory.
116
+ @mkdir($this->directory, 0777, true);
117
+ // Create read-only subdirectory.
118
+ @mkdir($this->directory.'/cache', 0555);
119
+ $this->assertTrue(is_dir($this->directory.'/cache'));
120
+
121
+ $this->cache->write($key, $content);
122
+ }
123
+
124
+ /**
125
+ * @expectedException RuntimeException
126
+ * @expectedExceptionMessage Failed to write cache file
127
+ */
128
+ public function testWriteFailWriteFile()
129
+ {
130
+ $key = $this->directory.'/cache/cachefile.php';
131
+ $content = $this->generateSource();
132
+
133
+ $this->assertFileNotExists($key);
134
+
135
+ // Create a directory in the place of the cache file.
136
+ @mkdir($key, 0777, true);
137
+ $this->assertTrue(is_dir($key));
138
+
139
+ $this->cache->write($key, $content);
140
+ }
141
+
142
+ public function testGetTimestamp()
143
+ {
144
+ $key = $this->directory.'/cache/cachefile.php';
145
+
146
+ $dir = dirname($key);
147
+ @mkdir($dir, 0777, true);
148
+ $this->assertTrue(is_dir($dir));
149
+
150
+ // Create the file with a specific modification time.
151
+ touch($key, 1234567890);
152
+
153
+ $this->assertSame(1234567890, $this->cache->getTimestamp($key));
154
+ }
155
+
156
+ public function testGetTimestampMissingFile()
157
+ {
158
+ $key = $this->directory.'/cache/cachefile.php';
159
+ $this->assertSame(0, $this->cache->getTimestamp($key));
160
+ }
161
+
162
+ /**
163
+ * Test file cache is tolerant towards trailing (back)slashes on the configured cache directory.
164
+ *
165
+ * @dataProvider provideDirectories
166
+ */
167
+ public function testGenerateKey($expected, $input)
168
+ {
169
+ $cache = new Twig_Cache_Filesystem($input);
170
+ $this->assertRegExp($expected, $cache->generateKey('_test_', get_class($this)));
171
+ }
172
+
173
+ public function provideDirectories()
174
+ {
175
+ $pattern = '#a/b/[a-zA-Z0-9]+/[a-zA-Z0-9]+.php$#';
176
+
177
+ return array(
178
+ array($pattern, 'a/b'),
179
+ array($pattern, 'a/b/'),
180
+ array($pattern, 'a/b\\'),
181
+ array($pattern, 'a/b\\/'),
182
+ array($pattern, 'a/b\\//'),
183
+ array('#/'.substr($pattern, 1), '/a/b'),
184
+ );
185
+ }
186
+
187
+ private function generateSource()
188
+ {
189
+ return strtr('<?php class {{classname}} {}', array(
190
+ '{{classname}}' => $this->classname,
191
+ ));
192
+ }
193
+ }
library/twig/twig/test/Twig/Tests/CompilerTest.php ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 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_Tests_CompilerTest extends PHPUnit_Framework_TestCase
13
+ {
14
+ public function testReprNumericValueWithLocale()
15
+ {
16
+ $compiler = new Twig_Compiler(new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock()));
17
+
18
+ $locale = setlocale(LC_NUMERIC, 0);
19
+ if (false === $locale) {
20
+ $this->markTestSkipped('Your platform does not support locales.');
21
+ }
22
+
23
+ $required_locales = array('fr_FR.UTF-8', 'fr_FR.UTF8', 'fr_FR.utf-8', 'fr_FR.utf8', 'French_France.1252');
24
+ if (false === setlocale(LC_NUMERIC, $required_locales)) {
25
+ $this->markTestSkipped('Could not set any of required locales: '.implode(', ', $required_locales));
26
+ }
27
+
28
+ $this->assertEquals('1.2', $compiler->repr(1.2)->getSource());
29
+ $this->assertContains('fr', strtolower(setlocale(LC_NUMERIC, 0)));
30
+
31
+ setlocale(LC_NUMERIC, $locale);
32
+ }
33
+ }
library/twig/twig/test/Twig/Tests/CustomExtensionTest.php ADDED
@@ -0,0 +1,88 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 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 CustomExtensionTest extends PHPUnit_Framework_TestCase
13
+ {
14
+ /**
15
+ * @requires PHP 5.3
16
+ * @dataProvider provideInvalidExtensions
17
+ */
18
+ public function testGetInvalidOperators(Twig_ExtensionInterface $extension, $expectedExceptionMessage)
19
+ {
20
+ $this->setExpectedException('InvalidArgumentException', $expectedExceptionMessage);
21
+
22
+ $env = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock());
23
+ $env->addExtension($extension);
24
+ $env->getUnaryOperators();
25
+ }
26
+
27
+ public function provideInvalidExtensions()
28
+ {
29
+ return array(
30
+ array(new InvalidOperatorExtension(new stdClass()), '"InvalidOperatorExtension::getOperators()" must return an array with operators, got "stdClass".'),
31
+ array(new InvalidOperatorExtension(array(1, 2, 3)), '"InvalidOperatorExtension::getOperators()" must return an array of 2 elements, got 3.'),
32
+ );
33
+ }
34
+ }
35
+
36
+ class InvalidOperatorExtension implements Twig_ExtensionInterface
37
+ {
38
+ private $operators;
39
+
40
+ public function __construct($operators)
41
+ {
42
+ $this->operators = $operators;
43
+ }
44
+
45
+ public function initRuntime(Twig_Environment $environment)
46
+ {
47
+ }
48
+
49
+ public function getTokenParsers()
50
+ {
51
+ return array();
52
+ }
53
+
54
+ public function getNodeVisitors()
55
+ {
56
+ return array();
57
+ }
58
+
59
+ public function getFilters()
60
+ {
61
+ return array();
62
+ }
63
+
64
+ public function getTests()
65
+ {
66
+ return array();
67
+ }
68
+
69
+ public function getFunctions()
70
+ {
71
+ return array();
72
+ }
73
+
74
+ public function getGlobals()
75
+ {
76
+ return array();
77
+ }
78
+
79
+ public function getOperators()
80
+ {
81
+ return $this->operators;
82
+ }
83
+
84
+ public function getName()
85
+ {
86
+ return __CLASS__;
87
+ }
88
+ }
library/twig/twig/test/Twig/Tests/EnvironmentTest.php ADDED
@@ -0,0 +1,652 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 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
+ require_once dirname(__FILE__).'/FilesystemHelper.php';
13
+
14
+ class Twig_Tests_EnvironmentTest extends PHPUnit_Framework_TestCase
15
+ {
16
+ private $deprecations = array();
17
+
18
+ /**
19
+ * @group legacy
20
+ */
21
+ public function testLegacyTokenizeSignature()
22
+ {
23
+ $env = new Twig_Environment();
24
+ $stream = $env->tokenize('{{ foo }}', 'foo');
25
+ $this->assertEquals('{{ foo }}', $stream->getSource());
26
+ $this->assertEquals('foo', $stream->getFilename());
27
+ }
28
+
29
+ /**
30
+ * @group legacy
31
+ */
32
+ public function testLegacyCompileSourceSignature()
33
+ {
34
+ $loader = new Twig_Loader_Array(array('foo' => '{{ foo }}'));
35
+ $env = new Twig_Environment($loader);
36
+ $this->assertContains('getTemplateName', $env->compileSource('{{ foo }}', 'foo'));
37
+ }
38
+
39
+ /**
40
+ * @expectedException LogicException
41
+ * @expectedExceptionMessage You must set a loader first.
42
+ * @group legacy
43
+ */
44
+ public function testRenderNoLoader()
45
+ {
46
+ $env = new Twig_Environment();
47
+ $env->render('test');
48
+ }
49
+
50
+ public function testAutoescapeOption()
51
+ {
52
+ $loader = new Twig_Loader_Array(array(
53
+ 'html' => '{{ foo }} {{ foo }}',
54
+ 'js' => '{{ bar }} {{ bar }}',
55
+ ));
56
+
57
+ $twig = new Twig_Environment($loader, array(
58
+ 'debug' => true,
59
+ 'cache' => false,
60
+ 'autoescape' => array($this, 'escapingStrategyCallback'),
61
+ ));
62
+
63
+ $this->assertEquals('foo&lt;br/ &gt; foo&lt;br/ &gt;', $twig->render('html', array('foo' => 'foo<br/ >')));
64
+ $this->assertEquals('foo\x3Cbr\x2F\x20\x3E foo\x3Cbr\x2F\x20\x3E', $twig->render('js', array('bar' => 'foo<br/ >')));
65
+ }
66
+
67
+ public function escapingStrategyCallback($name)
68
+ {
69
+ return $name;
70
+ }
71
+
72
+ public function testGlobals()
73
+ {
74
+ // to be removed in 2.0
75
+ $loader = $this->getMockBuilder('Twig_EnvironmentTestLoaderInterface')->getMock();
76
+ //$loader = $this->getMockBuilder(array('Twig_LoaderInterface', 'Twig_SourceContextLoaderInterface'))->getMock();
77
+ $loader->expects($this->any())->method('getSourceContext')->will($this->returnValue(new Twig_Source('', '')));
78
+
79
+ // globals can be added after calling getGlobals
80
+
81
+ $twig = new Twig_Environment($loader);
82
+ $twig->addGlobal('foo', 'foo');
83
+ $twig->getGlobals();
84
+ $twig->addGlobal('foo', 'bar');
85
+ $globals = $twig->getGlobals();
86
+ $this->assertEquals('bar', $globals['foo']);
87
+
88
+ // globals can be modified after a template has been loaded
89
+ $twig = new Twig_Environment($loader);
90
+ $twig->addGlobal('foo', 'foo');
91
+ $twig->getGlobals();
92
+ $twig->loadTemplate('index');
93
+ $twig->addGlobal('foo', 'bar');
94
+ $globals = $twig->getGlobals();
95
+ $this->assertEquals('bar', $globals['foo']);
96
+
97
+ // globals can be modified after extensions init
98
+ $twig = new Twig_Environment($loader);
99
+ $twig->addGlobal('foo', 'foo');
100
+ $twig->getGlobals();
101
+ $twig->getFunctions();
102
+ $twig->addGlobal('foo', 'bar');
103
+ $globals = $twig->getGlobals();
104
+ $this->assertEquals('bar', $globals['foo']);
105
+
106
+ // globals can be modified after extensions and a template has been loaded
107
+ $arrayLoader = new Twig_Loader_Array(array('index' => '{{foo}}'));
108
+ $twig = new Twig_Environment($arrayLoader);
109
+ $twig->addGlobal('foo', 'foo');
110
+ $twig->getGlobals();
111
+ $twig->getFunctions();
112
+ $twig->loadTemplate('index');
113
+ $twig->addGlobal('foo', 'bar');
114
+ $globals = $twig->getGlobals();
115
+ $this->assertEquals('bar', $globals['foo']);
116
+
117
+ $twig = new Twig_Environment($arrayLoader);
118
+ $twig->getGlobals();
119
+ $twig->addGlobal('foo', 'bar');
120
+ $template = $twig->loadTemplate('index');
121
+ $this->assertEquals('bar', $template->render(array()));
122
+
123
+ /* to be uncomment in Twig 2.0
124
+ // globals cannot be added after a template has been loaded
125
+ $twig = new Twig_Environment($loader);
126
+ $twig->addGlobal('foo', 'foo');
127
+ $twig->getGlobals();
128
+ $twig->loadTemplate('index');
129
+ try {
130
+ $twig->addGlobal('bar', 'bar');
131
+ $this->fail();
132
+ } catch (LogicException $e) {
133
+ $this->assertFalse(array_key_exists('bar', $twig->getGlobals()));
134
+ }
135
+
136
+ // globals cannot be added after extensions init
137
+ $twig = new Twig_Environment($loader);
138
+ $twig->addGlobal('foo', 'foo');
139
+ $twig->getGlobals();
140
+ $twig->getFunctions();
141
+ try {
142
+ $twig->addGlobal('bar', 'bar');
143
+ $this->fail();
144
+ } catch (LogicException $e) {
145
+ $this->assertFalse(array_key_exists('bar', $twig->getGlobals()));
146
+ }
147
+
148
+ // globals cannot be added after extensions and a template has been loaded
149
+ $twig = new Twig_Environment($loader);
150
+ $twig->addGlobal('foo', 'foo');
151
+ $twig->getGlobals();
152
+ $twig->getFunctions();
153
+ $twig->loadTemplate('index');
154
+ try {
155
+ $twig->addGlobal('bar', 'bar');
156
+ $this->fail();
157
+ } catch (LogicException $e) {
158
+ $this->assertFalse(array_key_exists('bar', $twig->getGlobals()));
159
+ }
160
+
161
+ // test adding globals after a template has been loaded without call to getGlobals
162
+ $twig = new Twig_Environment($loader);
163
+ $twig->loadTemplate('index');
164
+ try {
165
+ $twig->addGlobal('bar', 'bar');
166
+ $this->fail();
167
+ } catch (LogicException $e) {
168
+ $this->assertFalse(array_key_exists('bar', $twig->getGlobals()));
169
+ }
170
+ */
171
+ }
172
+
173
+ public function testExtensionsAreNotInitializedWhenRenderingACompiledTemplate()
174
+ {
175
+ $cache = new Twig_Cache_Filesystem($dir = sys_get_temp_dir().'/twig');
176
+ $options = array('cache' => $cache, 'auto_reload' => false, 'debug' => false);
177
+
178
+ // force compilation
179
+ $twig = new Twig_Environment($loader = new Twig_Loader_Array(array('index' => '{{ foo }}')), $options);
180
+
181
+ $key = $cache->generateKey('index', $twig->getTemplateClass('index'));
182
+ $cache->write($key, $twig->compileSource(new Twig_Source('{{ foo }}', 'index')));
183
+
184
+ // check that extensions won't be initialized when rendering a template that is already in the cache
185
+ $twig = $this
186
+ ->getMockBuilder('Twig_Environment')
187
+ ->setConstructorArgs(array($loader, $options))
188
+ ->setMethods(array('initExtensions'))
189
+ ->getMock()
190
+ ;
191
+
192
+ $twig->expects($this->never())->method('initExtensions');
193
+
194
+ // render template
195
+ $output = $twig->render('index', array('foo' => 'bar'));
196
+ $this->assertEquals('bar', $output);
197
+
198
+ Twig_Tests_FilesystemHelper::removeDir($dir);
199
+ }
200
+
201
+ public function testAutoReloadCacheMiss()
202
+ {
203
+ $templateName = __FUNCTION__;
204
+ $templateContent = __FUNCTION__;
205
+
206
+ $cache = $this->getMockBuilder('Twig_CacheInterface')->getMock();
207
+ $loader = $this->getMockLoader($templateName, $templateContent);
208
+ $twig = new Twig_Environment($loader, array('cache' => $cache, 'auto_reload' => true, 'debug' => false));
209
+
210
+ // Cache miss: getTimestamp returns 0 and as a result the load() is
211
+ // skipped.
212
+ $cache->expects($this->once())
213
+ ->method('generateKey')
214
+ ->will($this->returnValue('key'));
215
+ $cache->expects($this->once())
216
+ ->method('getTimestamp')
217
+ ->will($this->returnValue(0));
218
+ $loader->expects($this->never())
219
+ ->method('isFresh');
220
+ $cache->expects($this->once())
221
+ ->method('write');
222
+ $cache->expects($this->once())
223
+ ->method('load');
224
+
225
+ $twig->loadTemplate($templateName);
226
+ }
227
+
228
+ public function testAutoReloadCacheHit()
229
+ {
230
+ $templateName = __FUNCTION__;
231
+ $templateContent = __FUNCTION__;
232
+
233
+ $cache = $this->getMockBuilder('Twig_CacheInterface')->getMock();
234
+ $loader = $this->getMockLoader($templateName, $templateContent);
235
+ $twig = new Twig_Environment($loader, array('cache' => $cache, 'auto_reload' => true, 'debug' => false));
236
+
237
+ $now = time();
238
+
239
+ // Cache hit: getTimestamp returns something > extension timestamps and
240
+ // the loader returns true for isFresh().
241
+ $cache->expects($this->once())
242
+ ->method('generateKey')
243
+ ->will($this->returnValue('key'));
244
+ $cache->expects($this->once())
245
+ ->method('getTimestamp')
246
+ ->will($this->returnValue($now));
247
+ $loader->expects($this->once())
248
+ ->method('isFresh')
249
+ ->will($this->returnValue(true));
250
+ $cache->expects($this->atLeastOnce())
251
+ ->method('load');
252
+
253
+ $twig->loadTemplate($templateName);
254
+ }
255
+
256
+ public function testAutoReloadOutdatedCacheHit()
257
+ {
258
+ $templateName = __FUNCTION__;
259
+ $templateContent = __FUNCTION__;
260
+
261
+ $cache = $this->getMockBuilder('Twig_CacheInterface')->getMock();
262
+ $loader = $this->getMockLoader($templateName, $templateContent);
263
+ $twig = new Twig_Environment($loader, array('cache' => $cache, 'auto_reload' => true, 'debug' => false));
264
+
265
+ $now = time();
266
+
267
+ $cache->expects($this->once())
268
+ ->method('generateKey')
269
+ ->will($this->returnValue('key'));
270
+ $cache->expects($this->once())
271
+ ->method('getTimestamp')
272
+ ->will($this->returnValue($now));
273
+ $loader->expects($this->once())
274
+ ->method('isFresh')
275
+ ->will($this->returnValue(false));
276
+ $cache->expects($this->once())
277
+ ->method('write');
278
+ $cache->expects($this->once())
279
+ ->method('load');
280
+
281
+ $twig->loadTemplate($templateName);
282
+ }
283
+
284
+ /**
285
+ * @group legacy
286
+ */
287
+ public function testHasGetExtensionWithDynamicName()
288
+ {
289
+ $twig = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock());
290
+
291
+ $ext1 = new Twig_Tests_EnvironmentTest_Extension_DynamicWithDeprecatedName('ext1');
292
+ $ext2 = new Twig_Tests_EnvironmentTest_Extension_DynamicWithDeprecatedName('ext2');
293
+ $twig->addExtension($ext1);
294
+ $twig->addExtension($ext2);
295
+
296
+ $this->assertTrue($twig->hasExtension('ext1'));
297
+ $this->assertTrue($twig->hasExtension('ext2'));
298
+
299
+ $this->assertTrue($twig->hasExtension('Twig_Tests_EnvironmentTest_Extension_DynamicWithDeprecatedName'));
300
+
301
+ $this->assertSame($ext1, $twig->getExtension('ext1'));
302
+ $this->assertSame($ext2, $twig->getExtension('ext2'));
303
+ }
304
+
305
+ public function testHasGetExtensionByClassName()
306
+ {
307
+ $twig = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock());
308
+ $twig->addExtension($ext = new Twig_Tests_EnvironmentTest_Extension());
309
+ $this->assertTrue($twig->hasExtension('Twig_Tests_EnvironmentTest_Extension'));
310
+ $this->assertTrue($twig->hasExtension('\Twig_Tests_EnvironmentTest_Extension'));
311
+
312
+ $this->assertSame($ext, $twig->getExtension('Twig_Tests_EnvironmentTest_Extension'));
313
+ $this->assertSame($ext, $twig->getExtension('\Twig_Tests_EnvironmentTest_Extension'));
314
+ }
315
+
316
+ public function testAddExtension()
317
+ {
318
+ $twig = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock());
319
+ $twig->addExtension(new Twig_Tests_EnvironmentTest_Extension());
320
+
321
+ $this->assertArrayHasKey('test', $twig->getTags());
322
+ $this->assertArrayHasKey('foo_filter', $twig->getFilters());
323
+ $this->assertArrayHasKey('foo_function', $twig->getFunctions());
324
+ $this->assertArrayHasKey('foo_test', $twig->getTests());
325
+ $this->assertArrayHasKey('foo_unary', $twig->getUnaryOperators());
326
+ $this->assertArrayHasKey('foo_binary', $twig->getBinaryOperators());
327
+ $this->assertArrayHasKey('foo_global', $twig->getGlobals());
328
+ $visitors = $twig->getNodeVisitors();
329
+ $found = false;
330
+ foreach ($visitors as $visitor) {
331
+ if ($visitor instanceof Twig_Tests_EnvironmentTest_NodeVisitor) {
332
+ $found = true;
333
+ }
334
+ }
335
+ $this->assertTrue($found);
336
+ }
337
+
338
+ /**
339
+ * @requires PHP 5.3
340
+ */
341
+ public function testAddExtensionWithDeprecatedGetGlobals()
342
+ {
343
+ $twig = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock());
344
+ $twig->addExtension(new Twig_Tests_EnvironmentTest_Extension_WithGlobals());
345
+
346
+ $this->deprecations = array();
347
+ set_error_handler(array($this, 'handleError'));
348
+
349
+ $this->assertArrayHasKey('foo_global', $twig->getGlobals());
350
+
351
+ $this->assertCount(1, $this->deprecations);
352
+ $this->assertContains('Defining the getGlobals() method in the "Twig_Tests_EnvironmentTest_Extension_WithGlobals" extension ', $this->deprecations[0]);
353
+
354
+ restore_error_handler();
355
+ }
356
+
357
+ /**
358
+ * @group legacy
359
+ */
360
+ public function testRemoveExtension()
361
+ {
362
+ $twig = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock());
363
+ $twig->addExtension(new Twig_Tests_EnvironmentTest_Extension_WithDeprecatedName());
364
+ $twig->removeExtension('environment_test');
365
+
366
+ $this->assertArrayNotHasKey('test', $twig->getTags());
367
+ $this->assertArrayNotHasKey('foo_filter', $twig->getFilters());
368
+ $this->assertArrayNotHasKey('foo_function', $twig->getFunctions());
369
+ $this->assertArrayNotHasKey('foo_test', $twig->getTests());
370
+ $this->assertArrayNotHasKey('foo_unary', $twig->getUnaryOperators());
371
+ $this->assertArrayNotHasKey('foo_binary', $twig->getBinaryOperators());
372
+ $this->assertArrayNotHasKey('foo_global', $twig->getGlobals());
373
+ $this->assertCount(2, $twig->getNodeVisitors());
374
+ }
375
+
376
+ public function testAddMockExtension()
377
+ {
378
+ // should be replaced by the following in 2.0 (this current code is just to avoid a dep notice)
379
+ // $extension = $this->getMockBuilder('Twig_Extension')->getMock();
380
+ $extension = eval(<<<EOF
381
+ class Twig_Tests_EnvironmentTest_ExtensionInEval extends Twig_Extension
382
+ {
383
+ }
384
+ EOF
385
+ );
386
+ $extension = new Twig_Tests_EnvironmentTest_ExtensionInEval();
387
+
388
+ $loader = new Twig_Loader_Array(array('page' => 'hey'));
389
+
390
+ $twig = new Twig_Environment($loader);
391
+ $twig->addExtension($extension);
392
+
393
+ $this->assertInstanceOf('Twig_ExtensionInterface', $twig->getExtension(get_class($extension)));
394
+ $this->assertTrue($twig->isTemplateFresh('page', time()));
395
+ }
396
+
397
+ public function testInitRuntimeWithAnExtensionUsingInitRuntimeNoDeprecation()
398
+ {
399
+ $twig = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock());
400
+ $twig->addExtension(new Twig_Tests_EnvironmentTest_ExtensionWithoutDeprecationInitRuntime());
401
+
402
+ $twig->initRuntime();
403
+ }
404
+
405
+ /**
406
+ * @requires PHP 5.3
407
+ */
408
+ public function testInitRuntimeWithAnExtensionUsingInitRuntimeDeprecation()
409
+ {
410
+ $twig = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock());
411
+ $twig->addExtension(new Twig_Tests_EnvironmentTest_ExtensionWithDeprecationInitRuntime());
412
+
413
+ $this->deprecations = array();
414
+ set_error_handler(array($this, 'handleError'));
415
+
416
+ $twig->initRuntime();
417
+
418
+ $this->assertCount(1, $this->deprecations);
419
+ $this->assertContains('Defining the initRuntime() method in the "Twig_Tests_EnvironmentTest_ExtensionWithDeprecationInitRuntime" extension is deprecated since version 1.23.', $this->deprecations[0]);
420
+
421
+ restore_error_handler();
422
+ }
423
+
424
+ public function handleError($type, $msg)
425
+ {
426
+ if (E_USER_DEPRECATED === $type) {
427
+ $this->deprecations[] = $msg;
428
+ }
429
+ }
430
+
431
+ /**
432
+ * @requires PHP 5.3
433
+ */
434
+ public function testOverrideExtension()
435
+ {
436
+ $twig = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock());
437
+ $twig->addExtension(new Twig_Tests_EnvironmentTest_ExtensionWithDeprecationInitRuntime());
438
+
439
+ $this->deprecations = array();
440
+ set_error_handler(array($this, 'handleError'));
441
+
442
+ $twig->addExtension(new Twig_Tests_EnvironmentTest_Extension_WithDeprecatedName());
443
+ $twig->addExtension(new Twig_Tests_EnvironmentTest_Extension_WithDeprecatedName());
444
+
445
+ $this->assertCount(1, $this->deprecations);
446
+ $this->assertContains('The possibility to register the same extension twice', $this->deprecations[0]);
447
+
448
+ restore_error_handler();
449
+ }
450
+
451
+ public function testAddRuntimeLoader()
452
+ {
453
+ $runtimeLoader = $this->getMockBuilder('Twig_RuntimeLoaderInterface')->getMock();
454
+ $runtimeLoader->expects($this->any())->method('load')->will($this->returnValue(new Twig_Tests_EnvironmentTest_Runtime()));
455
+
456
+ $loader = new Twig_Loader_Array(array(
457
+ 'func_array' => '{{ from_runtime_array("foo") }}',
458
+ 'func_array_default' => '{{ from_runtime_array() }}',
459
+ 'func_array_named_args' => '{{ from_runtime_array(name="foo") }}',
460
+ 'func_string' => '{{ from_runtime_string("foo") }}',
461
+ 'func_string_default' => '{{ from_runtime_string() }}',
462
+ 'func_string_named_args' => '{{ from_runtime_string(name="foo") }}',
463
+ ));
464
+
465
+ $twig = new Twig_Environment($loader);
466
+ $twig->addExtension(new Twig_Tests_EnvironmentTest_ExtensionWithoutRuntime());
467
+ $twig->addRuntimeLoader($runtimeLoader);
468
+
469
+ $this->assertEquals('foo', $twig->render('func_array'));
470
+ $this->assertEquals('bar', $twig->render('func_array_default'));
471
+ $this->assertEquals('foo', $twig->render('func_array_named_args'));
472
+ $this->assertEquals('foo', $twig->render('func_string'));
473
+ $this->assertEquals('bar', $twig->render('func_string_default'));
474
+ $this->assertEquals('foo', $twig->render('func_string_named_args'));
475
+ }
476
+
477
+ protected function getMockLoader($templateName, $templateContent)
478
+ {
479
+ // to be removed in 2.0
480
+ $loader = $this->getMockBuilder('Twig_EnvironmentTestLoaderInterface')->getMock();
481
+ //$loader = $this->getMockBuilder(array('Twig_LoaderInterface', 'Twig_SourceContextLoaderInterface'))->getMock();
482
+ $loader->expects($this->any())
483
+ ->method('getSourceContext')
484
+ ->with($templateName)
485
+ ->will($this->returnValue(new Twig_Source($templateContent, $templateName)));
486
+ $loader->expects($this->any())
487
+ ->method('getCacheKey')
488
+ ->with($templateName)
489
+ ->will($this->returnValue($templateName));
490
+
491
+ return $loader;
492
+ }
493
+ }
494
+
495
+ class Twig_Tests_EnvironmentTest_Extension_WithGlobals extends Twig_Extension
496
+ {
497
+ public function getGlobals()
498
+ {
499
+ return array(
500
+ 'foo_global' => 'foo_global',
501
+ );
502
+ }
503
+ }
504
+
505
+ class Twig_Tests_EnvironmentTest_Extension extends Twig_Extension implements Twig_Extension_GlobalsInterface
506
+ {
507
+ public function getTokenParsers()
508
+ {
509
+ return array(
510
+ new Twig_Tests_EnvironmentTest_TokenParser(),
511
+ );
512
+ }
513
+
514
+ public function getNodeVisitors()
515
+ {
516
+ return array(
517
+ new Twig_Tests_EnvironmentTest_NodeVisitor(),
518
+ );
519
+ }
520
+
521
+ public function getFilters()
522
+ {
523
+ return array(
524
+ new Twig_SimpleFilter('foo_filter', 'foo_filter'),
525
+ );
526
+ }
527
+
528
+ public function getTests()
529
+ {
530
+ return array(
531
+ new Twig_SimpleTest('foo_test', 'foo_test'),
532
+ );
533
+ }
534
+
535
+ public function getFunctions()
536
+ {
537
+ return array(
538
+ new Twig_SimpleFunction('foo_function', 'foo_function'),
539
+ );
540
+ }
541
+
542
+ public function getOperators()
543
+ {
544
+ return array(
545
+ array('foo_unary' => array()),
546
+ array('foo_binary' => array()),
547
+ );
548
+ }
549
+
550
+ public function getGlobals()
551
+ {
552
+ return array(
553
+ 'foo_global' => 'foo_global',
554
+ );
555
+ }
556
+ }
557
+
558
+ class Twig_Tests_EnvironmentTest_Extension_WithDeprecatedName extends Twig_Extension
559
+ {
560
+ public function getName()
561
+ {
562
+ return 'environment_test';
563
+ }
564
+ }
565
+
566
+ class Twig_Tests_EnvironmentTest_Extension_DynamicWithDeprecatedName extends Twig_Extension
567
+ {
568
+ private $name;
569
+
570
+ public function __construct($name)
571
+ {
572
+ $this->name = $name;
573
+ }
574
+
575
+ public function getName()
576
+ {
577
+ return $this->name;
578
+ }
579
+ }
580
+
581
+ class Twig_Tests_EnvironmentTest_TokenParser extends Twig_TokenParser
582
+ {
583
+ public function parse(Twig_Token $token)
584
+ {
585
+ }
586
+
587
+ public function getTag()
588
+ {
589
+ return 'test';
590
+ }
591
+ }
592
+
593
+ class Twig_Tests_EnvironmentTest_NodeVisitor implements Twig_NodeVisitorInterface
594
+ {
595
+ public function enterNode(Twig_NodeInterface $node, Twig_Environment $env)
596
+ {
597
+ return $node;
598
+ }
599
+
600
+ public function leaveNode(Twig_NodeInterface $node, Twig_Environment $env)
601
+ {
602
+ return $node;
603
+ }
604
+
605
+ public function getPriority()
606
+ {
607
+ return 0;
608
+ }
609
+ }
610
+
611
+ class Twig_Tests_EnvironmentTest_ExtensionWithDeprecationInitRuntime extends Twig_Extension
612
+ {
613
+ public function initRuntime(Twig_Environment $env)
614
+ {
615
+ }
616
+ }
617
+
618
+ class Twig_Tests_EnvironmentTest_ExtensionWithoutDeprecationInitRuntime extends Twig_Extension implements Twig_Extension_InitRuntimeInterface
619
+ {
620
+ public function initRuntime(Twig_Environment $env)
621
+ {
622
+ }
623
+ }
624
+
625
+ class Twig_Tests_EnvironmentTest_ExtensionWithoutRuntime extends Twig_Extension
626
+ {
627
+ public function getFunctions()
628
+ {
629
+ return array(
630
+ new Twig_SimpleFunction('from_runtime_array', array('Twig_Tests_EnvironmentTest_Runtime', 'fromRuntime')),
631
+ new Twig_SimpleFunction('from_runtime_string', 'Twig_Tests_EnvironmentTest_Runtime::fromRuntime'),
632
+ );
633
+ }
634
+
635
+ public function getName()
636
+ {
637
+ return 'from_runtime';
638
+ }
639
+ }
640
+
641
+ class Twig_Tests_EnvironmentTest_Runtime
642
+ {
643
+ public function fromRuntime($name = 'bar')
644
+ {
645
+ return $name;
646
+ }
647
+ }
648
+
649
+ // to be removed in 2.0
650
+ interface Twig_EnvironmentTestLoaderInterface extends Twig_LoaderInterface, Twig_SourceContextLoaderInterface
651
+ {
652
+ }
library/twig/twig/test/Twig/Tests/ErrorTest.php ADDED
@@ -0,0 +1,211 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 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_Tests_ErrorTest extends PHPUnit_Framework_TestCase
13
+ {
14
+ public function testErrorWithObjectFilename()
15
+ {
16
+ $error = new Twig_Error('foo');
17
+ $error->setSourceContext(new Twig_Source('', new SplFileInfo(__FILE__)));
18
+
19
+ $this->assertContains('test'.DIRECTORY_SEPARATOR.'Twig'.DIRECTORY_SEPARATOR.'Tests'.DIRECTORY_SEPARATOR.'ErrorTest.php', $error->getMessage());
20
+ }
21
+
22
+ public function testErrorWithArrayFilename()
23
+ {
24
+ $error = new Twig_Error('foo');
25
+ $error->setSourceContext(new Twig_Source('', array('foo' => 'bar')));
26
+
27
+ $this->assertEquals('foo in {"foo":"bar"}', $error->getMessage());
28
+ }
29
+
30
+ public function testTwigExceptionGuessWithMissingVarAndArrayLoader()
31
+ {
32
+ $loader = new Twig_Loader_Array(array(
33
+ 'base.html' => '{% block content %}{% endblock %}',
34
+ 'index.html' => <<<EOHTML
35
+ {% extends 'base.html' %}
36
+ {% block content %}
37
+ {{ foo.bar }}
38
+ {% endblock %}
39
+ {% block foo %}
40
+ {{ foo.bar }}
41
+ {% endblock %}
42
+ EOHTML
43
+ ));
44
+ $twig = new Twig_Environment($loader, array('strict_variables' => true, 'debug' => true, 'cache' => false));
45
+
46
+ $template = $twig->loadTemplate('index.html');
47
+ try {
48
+ $template->render(array());
49
+
50
+ $this->fail();
51
+ } catch (Twig_Error_Runtime $e) {
52
+ $this->assertEquals('Variable "foo" does not exist in "index.html" at line 3.', $e->getMessage());
53
+ $this->assertEquals(3, $e->getTemplateLine());
54
+ $this->assertEquals('index.html', $e->getSourceContext()->getName());
55
+ }
56
+ }
57
+
58
+ public function testTwigExceptionGuessWithExceptionAndArrayLoader()
59
+ {
60
+ $loader = new Twig_Loader_Array(array(
61
+ 'base.html' => '{% block content %}{% endblock %}',
62
+ 'index.html' => <<<EOHTML
63
+ {% extends 'base.html' %}
64
+ {% block content %}
65
+ {{ foo.bar }}
66
+ {% endblock %}
67
+ {% block foo %}
68
+ {{ foo.bar }}
69
+ {% endblock %}
70
+ EOHTML
71
+ ));
72
+ $twig = new Twig_Environment($loader, array('strict_variables' => true, 'debug' => true, 'cache' => false));
73
+
74
+ $template = $twig->loadTemplate('index.html');
75
+ try {
76
+ $template->render(array('foo' => new Twig_Tests_ErrorTest_Foo()));
77
+
78
+ $this->fail();
79
+ } catch (Twig_Error_Runtime $e) {
80
+ $this->assertEquals('An exception has been thrown during the rendering of a template ("Runtime error...") in "index.html" at line 3.', $e->getMessage());
81
+ $this->assertEquals(3, $e->getTemplateLine());
82
+ $this->assertEquals('index.html', $e->getSourceContext()->getName());
83
+ }
84
+ }
85
+
86
+ public function testTwigExceptionGuessWithMissingVarAndFilesystemLoader()
87
+ {
88
+ $loader = new Twig_Loader_Filesystem(dirname(__FILE__).'/Fixtures/errors');
89
+ $twig = new Twig_Environment($loader, array('strict_variables' => true, 'debug' => true, 'cache' => false));
90
+
91
+ $template = $twig->loadTemplate('index.html');
92
+ try {
93
+ $template->render(array());
94
+
95
+ $this->fail();
96
+ } catch (Twig_Error_Runtime $e) {
97
+ $this->assertEquals('Variable "foo" does not exist.', $e->getMessage());
98
+ $this->assertEquals(3, $e->getTemplateLine());
99
+ $this->assertEquals('index.html', $e->getSourceContext()->getName());
100
+ $this->assertEquals(3, $e->getLine());
101
+ $this->assertEquals(strtr(dirname(__FILE__).'/Fixtures/errors/index.html', '/', DIRECTORY_SEPARATOR), $e->getFile());
102
+ }
103
+ }
104
+
105
+ public function testTwigExceptionGuessWithExceptionAndFilesystemLoader()
106
+ {
107
+ $loader = new Twig_Loader_Filesystem(dirname(__FILE__).'/Fixtures/errors');
108
+ $twig = new Twig_Environment($loader, array('strict_variables' => true, 'debug' => true, 'cache' => false));
109
+
110
+ $template = $twig->loadTemplate('index.html');
111
+ try {
112
+ $template->render(array('foo' => new Twig_Tests_ErrorTest_Foo()));
113
+
114
+ $this->fail();
115
+ } catch (Twig_Error_Runtime $e) {
116
+ $this->assertEquals('An exception has been thrown during the rendering of a template ("Runtime error...").', $e->getMessage());
117
+ $this->assertEquals(3, $e->getTemplateLine());
118
+ $this->assertEquals('index.html', $e->getSourceContext()->getName());
119
+ $this->assertEquals(3, $e->getLine());
120
+ $this->assertEquals(strtr(dirname(__FILE__).'/Fixtures/errors/index.html', '/', DIRECTORY_SEPARATOR), $e->getFile());
121
+ }
122
+ }
123
+
124
+ /**
125
+ * @dataProvider getErroredTemplates
126
+ */
127
+ public function testTwigExceptionAddsFileAndLine($templates, $name, $line)
128
+ {
129
+ $loader = new Twig_Loader_Array($templates);
130
+ $twig = new Twig_Environment($loader, array('strict_variables' => true, 'debug' => true, 'cache' => false));
131
+
132
+ $template = $twig->loadTemplate('index');
133
+
134
+ try {
135
+ $template->render(array());
136
+
137
+ $this->fail();
138
+ } catch (Twig_Error_Runtime $e) {
139
+ $this->assertEquals(sprintf('Variable "foo" does not exist in "%s" at line %d.', $name, $line), $e->getMessage());
140
+ $this->assertEquals($line, $e->getTemplateLine());
141
+ $this->assertEquals($name, $e->getSourceContext()->getName());
142
+ }
143
+
144
+ try {
145
+ $template->render(array('foo' => new Twig_Tests_ErrorTest_Foo()));
146
+
147
+ $this->fail();
148
+ } catch (Twig_Error_Runtime $e) {
149
+ $this->assertEquals(sprintf('An exception has been thrown during the rendering of a template ("Runtime error...") in "%s" at line %d.', $name, $line), $e->getMessage());
150
+ $this->assertEquals($line, $e->getTemplateLine());
151
+ $this->assertEquals($name, $e->getSourceContext()->getName());
152
+ }
153
+ }
154
+
155
+ public function getErroredTemplates()
156
+ {
157
+ return array(
158
+ // error occurs in a template
159
+ array(
160
+ array(
161
+ 'index' => "\n\n{{ foo.bar }}\n\n\n{{ 'foo' }}",
162
+ ),
163
+ 'index', 3,
164
+ ),
165
+
166
+ // error occurs in an included template
167
+ array(
168
+ array(
169
+ 'index' => "{% include 'partial' %}",
170
+ 'partial' => '{{ foo.bar }}',
171
+ ),
172
+ 'partial', 1,
173
+ ),
174
+
175
+ // error occurs in a parent block when called via parent()
176
+ array(
177
+ array(
178
+ 'index' => "{% extends 'base' %}
179
+ {% block content %}
180
+ {{ parent() }}
181
+ {% endblock %}",
182
+ 'base' => '{% block content %}{{ foo.bar }}{% endblock %}',
183
+ ),
184
+ 'base', 1,
185
+ ),
186
+
187
+ // error occurs in a block from the child
188
+ array(
189
+ array(
190
+ 'index' => "{% extends 'base' %}
191
+ {% block content %}
192
+ {{ foo.bar }}
193
+ {% endblock %}
194
+ {% block foo %}
195
+ {{ foo.bar }}
196
+ {% endblock %}",
197
+ 'base' => '{% block content %}{% endblock %}',
198
+ ),
199
+ 'index', 3,
200
+ ),
201
+ );
202
+ }
203
+ }
204
+
205
+ class Twig_Tests_ErrorTest_Foo
206
+ {
207
+ public function bar()
208
+ {
209
+ throw new Exception('Runtime error...');
210
+ }
211
+ }
library/twig/twig/test/Twig/Tests/ExpressionParserTest.php ADDED
@@ -0,0 +1,373 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 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_Tests_ExpressionParserTest extends PHPUnit_Framework_TestCase
13
+ {
14
+ /**
15
+ * @expectedException Twig_Error_Syntax
16
+ * @dataProvider getFailingTestsForAssignment
17
+ */
18
+ public function testCanOnlyAssignToNames($template)
19
+ {
20
+ $env = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock(), array('cache' => false, 'autoescape' => false));
21
+ $parser = new Twig_Parser($env);
22
+
23
+ $parser->parse($env->tokenize(new Twig_Source($template, 'index')));
24
+ }
25
+
26
+ public function getFailingTestsForAssignment()
27
+ {
28
+ return array(
29
+ array('{% set false = "foo" %}'),
30
+ array('{% set FALSE = "foo" %}'),
31
+ array('{% set true = "foo" %}'),
32
+ array('{% set TRUE = "foo" %}'),
33
+ array('{% set none = "foo" %}'),
34
+ array('{% set NONE = "foo" %}'),
35
+ array('{% set null = "foo" %}'),
36
+ array('{% set NULL = "foo" %}'),
37
+ array('{% set 3 = "foo" %}'),
38
+ array('{% set 1 + 2 = "foo" %}'),
39
+ array('{% set "bar" = "foo" %}'),
40
+ array('{% set %}{% endset %}'),
41
+ );
42
+ }
43
+
44
+ /**
45
+ * @dataProvider getTestsForArray
46
+ */
47
+ public function testArrayExpression($template, $expected)
48
+ {
49
+ $env = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock(), array('cache' => false, 'autoescape' => false));
50
+ $stream = $env->tokenize(new Twig_Source($template, ''));
51
+ $parser = new Twig_Parser($env);
52
+
53
+ $this->assertEquals($expected, $parser->parse($stream)->getNode('body')->getNode(0)->getNode('expr'));
54
+ }
55
+
56
+ /**
57
+ * @expectedException Twig_Error_Syntax
58
+ * @dataProvider getFailingTestsForArray
59
+ */
60
+ public function testArraySyntaxError($template)
61
+ {
62
+ $env = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock(), array('cache' => false, 'autoescape' => false));
63
+ $parser = new Twig_Parser($env);
64
+
65
+ $parser->parse($env->tokenize(new Twig_Source($template, 'index')));
66
+ }
67
+
68
+ public function getFailingTestsForArray()
69
+ {
70
+ return array(
71
+ array('{{ [1, "a": "b"] }}'),
72
+ array('{{ {"a": "b", 2} }}'),
73
+ );
74
+ }
75
+
76
+ public function getTestsForArray()
77
+ {
78
+ return array(
79
+ // simple array
80
+ array('{{ [1, 2] }}', new Twig_Node_Expression_Array(array(
81
+ new Twig_Node_Expression_Constant(0, 1),
82
+ new Twig_Node_Expression_Constant(1, 1),
83
+
84
+ new Twig_Node_Expression_Constant(1, 1),
85
+ new Twig_Node_Expression_Constant(2, 1),
86
+ ), 1),
87
+ ),
88
+
89
+ // array with trailing ,
90
+ array('{{ [1, 2, ] }}', new Twig_Node_Expression_Array(array(
91
+ new Twig_Node_Expression_Constant(0, 1),
92
+ new Twig_Node_Expression_Constant(1, 1),
93
+
94
+ new Twig_Node_Expression_Constant(1, 1),
95
+ new Twig_Node_Expression_Constant(2, 1),
96
+ ), 1),
97
+ ),
98
+
99
+ // simple hash
100
+ array('{{ {"a": "b", "b": "c"} }}', new Twig_Node_Expression_Array(array(
101
+ new Twig_Node_Expression_Constant('a', 1),
102
+ new Twig_Node_Expression_Constant('b', 1),
103
+
104
+ new Twig_Node_Expression_Constant('b', 1),
105
+ new Twig_Node_Expression_Constant('c', 1),
106
+ ), 1),
107
+ ),
108
+
109
+ // hash with trailing ,
110
+ array('{{ {"a": "b", "b": "c", } }}', new Twig_Node_Expression_Array(array(
111
+ new Twig_Node_Expression_Constant('a', 1),
112
+ new Twig_Node_Expression_Constant('b', 1),
113
+
114
+ new Twig_Node_Expression_Constant('b', 1),
115
+ new Twig_Node_Expression_Constant('c', 1),
116
+ ), 1),
117
+ ),
118
+
119
+ // hash in an array
120
+ array('{{ [1, {"a": "b", "b": "c"}] }}', new Twig_Node_Expression_Array(array(
121
+ new Twig_Node_Expression_Constant(0, 1),
122
+ new Twig_Node_Expression_Constant(1, 1),
123
+
124
+ new Twig_Node_Expression_Constant(1, 1),
125
+ new Twig_Node_Expression_Array(array(
126
+ new Twig_Node_Expression_Constant('a', 1),
127
+ new Twig_Node_Expression_Constant('b', 1),
128
+
129
+ new Twig_Node_Expression_Constant('b', 1),
130
+ new Twig_Node_Expression_Constant('c', 1),
131
+ ), 1),
132
+ ), 1),
133
+ ),
134
+
135
+ // array in a hash
136
+ array('{{ {"a": [1, 2], "b": "c"} }}', new Twig_Node_Expression_Array(array(
137
+ new Twig_Node_Expression_Constant('a', 1),
138
+ new Twig_Node_Expression_Array(array(
139
+ new Twig_Node_Expression_Constant(0, 1),
140
+ new Twig_Node_Expression_Constant(1, 1),
141
+
142
+ new Twig_Node_Expression_Constant(1, 1),
143
+ new Twig_Node_Expression_Constant(2, 1),
144
+ ), 1),
145
+ new Twig_Node_Expression_Constant('b', 1),
146
+ new Twig_Node_Expression_Constant('c', 1),
147
+ ), 1),
148
+ ),
149
+ );
150
+ }
151
+
152
+ /**
153
+ * @expectedException Twig_Error_Syntax
154
+ */
155
+ public function testStringExpressionDoesNotConcatenateTwoConsecutiveStrings()
156
+ {
157
+ $env = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock(), array('cache' => false, 'autoescape' => false, 'optimizations' => 0));
158
+ $stream = $env->tokenize(new Twig_Source('{{ "a" "b" }}', 'index'));
159
+ $parser = new Twig_Parser($env);
160
+
161
+ $parser->parse($stream);
162
+ }
163
+
164
+ /**
165
+ * @dataProvider getTestsForString
166
+ */
167
+ public function testStringExpression($template, $expected)
168
+ {
169
+ $env = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock(), array('cache' => false, 'autoescape' => false, 'optimizations' => 0));
170
+ $stream = $env->tokenize(new Twig_Source($template, ''));
171
+ $parser = new Twig_Parser($env);
172
+
173
+ $this->assertEquals($expected, $parser->parse($stream)->getNode('body')->getNode(0)->getNode('expr'));
174
+ }
175
+
176
+ public function getTestsForString()
177
+ {
178
+ return array(
179
+ array(
180
+ '{{ "foo" }}', new Twig_Node_Expression_Constant('foo', 1),
181
+ ),
182
+ array(
183
+ '{{ "foo #{bar}" }}', new Twig_Node_Expression_Binary_Concat(
184
+ new Twig_Node_Expression_Constant('foo ', 1),
185
+ new Twig_Node_Expression_Name('bar', 1),
186
+ 1
187
+ ),
188
+ ),
189
+ array(
190
+ '{{ "foo #{bar} baz" }}', new Twig_Node_Expression_Binary_Concat(
191
+ new Twig_Node_Expression_Binary_Concat(
192
+ new Twig_Node_Expression_Constant('foo ', 1),
193
+ new Twig_Node_Expression_Name('bar', 1),
194
+ 1
195
+ ),
196
+ new Twig_Node_Expression_Constant(' baz', 1),
197
+ 1
198
+ ),
199
+ ),
200
+
201
+ array(
202
+ '{{ "foo #{"foo #{bar} baz"} baz" }}', new Twig_Node_Expression_Binary_Concat(
203
+ new Twig_Node_Expression_Binary_Concat(
204
+ new Twig_Node_Expression_Constant('foo ', 1),
205
+ new Twig_Node_Expression_Binary_Concat(
206
+ new Twig_Node_Expression_Binary_Concat(
207
+ new Twig_Node_Expression_Constant('foo ', 1),
208
+ new Twig_Node_Expression_Name('bar', 1),
209
+ 1
210
+ ),
211
+ new Twig_Node_Expression_Constant(' baz', 1),
212
+ 1
213
+ ),
214
+ 1
215
+ ),
216
+ new Twig_Node_Expression_Constant(' baz', 1),
217
+ 1
218
+ ),
219
+ ),
220
+ );
221
+ }
222
+
223
+ /**
224
+ * @expectedException Twig_Error_Syntax
225
+ */
226
+ public function testAttributeCallDoesNotSupportNamedArguments()
227
+ {
228
+ $env = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock(), array('cache' => false, 'autoescape' => false));
229
+ $parser = new Twig_Parser($env);
230
+
231
+ $parser->parse($env->tokenize(new Twig_Source('{{ foo.bar(name="Foo") }}', 'index')));
232
+ }
233
+
234
+ /**
235
+ * @expectedException Twig_Error_Syntax
236
+ */
237
+ public function testMacroCallDoesNotSupportNamedArguments()
238
+ {
239
+ $env = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock(), array('cache' => false, 'autoescape' => false));
240
+ $parser = new Twig_Parser($env);
241
+
242
+ $parser->parse($env->tokenize(new Twig_Source('{% from _self import foo %}{% macro foo() %}{% endmacro %}{{ foo(name="Foo") }}', 'index')));
243
+ }
244
+
245
+ /**
246
+ * @expectedException Twig_Error_Syntax
247
+ * @expectedExceptionMessage An argument must be a name. Unexpected token "string" of value "a" ("name" expected) in "index" at line 1.
248
+ */
249
+ public function testMacroDefinitionDoesNotSupportNonNameVariableName()
250
+ {
251
+ $env = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock(), array('cache' => false, 'autoescape' => false));
252
+ $parser = new Twig_Parser($env);
253
+
254
+ $parser->parse($env->tokenize(new Twig_Source('{% macro foo("a") %}{% endmacro %}', 'index')));
255
+ }
256
+
257
+ /**
258
+ * @expectedException Twig_Error_Syntax
259
+ * @expectedExceptionMessage A default value for an argument must be a constant (a boolean, a string, a number, or an array) in "index" at line 1
260
+ * @dataProvider getMacroDefinitionDoesNotSupportNonConstantDefaultValues
261
+ */
262
+ public function testMacroDefinitionDoesNotSupportNonConstantDefaultValues($template)
263
+ {
264
+ $env = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock(), array('cache' => false, 'autoescape' => false));
265
+ $parser = new Twig_Parser($env);
266
+
267
+ $parser->parse($env->tokenize(new Twig_Source($template, 'index')));
268
+ }
269
+
270
+ public function getMacroDefinitionDoesNotSupportNonConstantDefaultValues()
271
+ {
272
+ return array(
273
+ array('{% macro foo(name = "a #{foo} a") %}{% endmacro %}'),
274
+ array('{% macro foo(name = [["b", "a #{foo} a"]]) %}{% endmacro %}'),
275
+ );
276
+ }
277
+
278
+ /**
279
+ * @dataProvider getMacroDefinitionSupportsConstantDefaultValues
280
+ */
281
+ public function testMacroDefinitionSupportsConstantDefaultValues($template)
282
+ {
283
+ $env = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock(), array('cache' => false, 'autoescape' => false));
284
+ $parser = new Twig_Parser($env);
285
+
286
+ $parser->parse($env->tokenize(new Twig_Source($template, 'index')));
287
+ }
288
+
289
+ public function getMacroDefinitionSupportsConstantDefaultValues()
290
+ {
291
+ return array(
292
+ array('{% macro foo(name = "aa") %}{% endmacro %}'),
293
+ array('{% macro foo(name = 12) %}{% endmacro %}'),
294
+ array('{% macro foo(name = true) %}{% endmacro %}'),
295
+ array('{% macro foo(name = ["a"]) %}{% endmacro %}'),
296
+ array('{% macro foo(name = [["a"]]) %}{% endmacro %}'),
297
+ array('{% macro foo(name = {a: "a"}) %}{% endmacro %}'),
298
+ array('{% macro foo(name = {a: {b: "a"}}) %}{% endmacro %}'),
299
+ );
300
+ }
301
+
302
+ /**
303
+ * @expectedException Twig_Error_Syntax
304
+ * @expectedExceptionMessage Unknown "cycl" function. Did you mean "cycle" in "index" at line 1?
305
+ */
306
+ public function testUnknownFunction()
307
+ {
308
+ $env = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock(), array('cache' => false, 'autoescape' => false));
309
+ $parser = new Twig_Parser($env);
310
+
311
+ $parser->parse($env->tokenize(new Twig_Source('{{ cycl() }}', 'index')));
312
+ }
313
+
314
+ /**
315
+ * @expectedException Twig_Error_Syntax
316
+ * @expectedExceptionMessage Unknown "foobar" function in "index" at line 1.
317
+ */
318
+ public function testUnknownFunctionWithoutSuggestions()
319
+ {
320
+ $env = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock(), array('cache' => false, 'autoescape' => false));
321
+ $parser = new Twig_Parser($env);
322
+
323
+ $parser->parse($env->tokenize(new Twig_Source('{{ foobar() }}', 'index')));
324
+ }
325
+
326
+ /**
327
+ * @expectedException Twig_Error_Syntax
328
+ * @expectedExceptionMessage Unknown "lowe" filter. Did you mean "lower" in "index" at line 1?
329
+ */
330
+ public function testUnknownFilter()
331
+ {
332
+ $env = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock(), array('cache' => false, 'autoescape' => false));
333
+ $parser = new Twig_Parser($env);
334
+
335
+ $parser->parse($env->tokenize(new Twig_Source('{{ 1|lowe }}', 'index')));
336
+ }
337
+
338
+ /**
339
+ * @expectedException Twig_Error_Syntax
340
+ * @expectedExceptionMessage Unknown "foobar" filter in "index" at line 1.
341
+ */
342
+ public function testUnknownFilterWithoutSuggestions()
343
+ {
344
+ $env = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock(), array('cache' => false, 'autoescape' => false));
345
+ $parser = new Twig_Parser($env);
346
+
347
+ $parser->parse($env->tokenize(new Twig_Source('{{ 1|foobar }}', 'index')));
348
+ }
349
+
350
+ /**
351
+ * @expectedException Twig_Error_Syntax
352
+ * @expectedExceptionMessage Unknown "nul" test. Did you mean "null" in "index" at line 1
353
+ */
354
+ public function testUnknownTest()
355
+ {
356
+ $env = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock(), array('cache' => false, 'autoescape' => false));
357
+ $parser = new Twig_Parser($env);
358
+ $stream = $env->tokenize(new Twig_Source('{{ 1 is nul }}', 'index'));
359
+ $parser->parse($stream);
360
+ }
361
+
362
+ /**
363
+ * @expectedException Twig_Error_Syntax
364
+ * @expectedExceptionMessage Unknown "foobar" test in "index" at line 1.
365
+ */
366
+ public function testUnknownTestWithoutSuggestions()
367
+ {
368
+ $env = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock(), array('cache' => false, 'autoescape' => false));
369
+ $parser = new Twig_Parser($env);
370
+
371
+ $parser->parse($env->tokenize(new Twig_Source('{{ 1 is foobar }}', 'index')));
372
+ }
373
+ }
library/twig/twig/test/Twig/Tests/Extension/CoreTest.php ADDED
@@ -0,0 +1,355 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 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_Tests_Extension_CoreTest extends PHPUnit_Framework_TestCase
13
+ {
14
+ /**
15
+ * @dataProvider getRandomFunctionTestData
16
+ */
17
+ public function testRandomFunction($value, $expectedInArray)
18
+ {
19
+ $env = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock());
20
+
21
+ for ($i = 0; $i < 100; ++$i) {
22
+ $this->assertTrue(in_array(twig_random($env, $value), $expectedInArray, true)); // assertContains() would not consider the type
23
+ }
24
+ }
25
+
26
+ public function getRandomFunctionTestData()
27
+ {
28
+ return array(
29
+ array(// array
30
+ array('apple', 'orange', 'citrus'),
31
+ array('apple', 'orange', 'citrus'),
32
+ ),
33
+ array(// Traversable
34
+ new ArrayObject(array('apple', 'orange', 'citrus')),
35
+ array('apple', 'orange', 'citrus'),
36
+ ),
37
+ array(// unicode string
38
+ 'Ä€é',
39
+ array('Ä', '€', 'é'),
40
+ ),
41
+ array(// numeric but string
42
+ '123',
43
+ array('1', '2', '3'),
44
+ ),
45
+ array(// integer
46
+ 5,
47
+ range(0, 5, 1),
48
+ ),
49
+ array(// float
50
+ 5.9,
51
+ range(0, 5, 1),
52
+ ),
53
+ array(// negative
54
+ -2,
55
+ array(0, -1, -2),
56
+ ),
57
+ );
58
+ }
59
+
60
+ public function testRandomFunctionWithoutParameter()
61
+ {
62
+ $max = mt_getrandmax();
63
+
64
+ for ($i = 0; $i < 100; ++$i) {
65
+ $val = twig_random(new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock()));
66
+ $this->assertTrue(is_int($val) && $val >= 0 && $val <= $max);
67
+ }
68
+ }
69
+
70
+ public function testRandomFunctionReturnsAsIs()
71
+ {
72
+ $this->assertSame('', twig_random(new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock()), ''));
73
+ $this->assertSame('', twig_random(new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock(), array('charset' => null)), ''));
74
+
75
+ $instance = new stdClass();
76
+ $this->assertSame($instance, twig_random(new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock()), $instance));
77
+ }
78
+
79
+ /**
80
+ * @expectedException Twig_Error_Runtime
81
+ */
82
+ public function testRandomFunctionOfEmptyArrayThrowsException()
83
+ {
84
+ twig_random(new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock()), array());
85
+ }
86
+
87
+ public function testRandomFunctionOnNonUTF8String()
88
+ {
89
+ if (!function_exists('iconv') && !function_exists('mb_convert_encoding')) {
90
+ $this->markTestSkipped('needs iconv or mbstring');
91
+ }
92
+
93
+ $twig = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock());
94
+ $twig->setCharset('ISO-8859-1');
95
+
96
+ $text = twig_convert_encoding('Äé', 'ISO-8859-1', 'UTF-8');
97
+ for ($i = 0; $i < 30; ++$i) {
98
+ $rand = twig_random($twig, $text);
99
+ $this->assertTrue(in_array(twig_convert_encoding($rand, 'UTF-8', 'ISO-8859-1'), array('Ä', 'é'), true));
100
+ }
101
+ }
102
+
103
+ public function testReverseFilterOnNonUTF8String()
104
+ {
105
+ if (!function_exists('iconv') && !function_exists('mb_convert_encoding')) {
106
+ $this->markTestSkipped('needs iconv or mbstring');
107
+ }
108
+
109
+ $twig = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock());
110
+ $twig->setCharset('ISO-8859-1');
111
+
112
+ $input = twig_convert_encoding('Äé', 'ISO-8859-1', 'UTF-8');
113
+ $output = twig_convert_encoding(twig_reverse_filter($twig, $input), 'UTF-8', 'ISO-8859-1');
114
+
115
+ $this->assertEquals($output, 'éÄ');
116
+ }
117
+
118
+ /**
119
+ * @dataProvider provideCustomEscaperCases
120
+ */
121
+ public function testCustomEscaper($expected, $string, $strategy)
122
+ {
123
+ $twig = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock());
124
+ $twig->getExtension('Twig_Extension_Core')->setEscaper('foo', 'foo_escaper_for_test');
125
+
126
+ $this->assertSame($expected, twig_escape_filter($twig, $string, $strategy));
127
+ }
128
+
129
+ public function provideCustomEscaperCases()
130
+ {
131
+ return array(
132
+ array('fooUTF-8', 'foo', 'foo'),
133
+ array('UTF-8', null, 'foo'),
134
+ array('42UTF-8', 42, 'foo'),
135
+ );
136
+ }
137
+
138
+ /**
139
+ * @expectedException Twig_Error_Runtime
140
+ */
141
+ public function testUnknownCustomEscaper()
142
+ {
143
+ twig_escape_filter(new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock()), 'foo', 'bar');
144
+ }
145
+
146
+ /**
147
+ * @dataProvider provideTwigFirstCases
148
+ */
149
+ public function testTwigFirst($expected, $input)
150
+ {
151
+ $twig = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock());
152
+ $this->assertSame($expected, twig_first($twig, $input));
153
+ }
154
+
155
+ public function provideTwigFirstCases()
156
+ {
157
+ $i = array(1 => 'a', 2 => 'b', 3 => 'c');
158
+
159
+ return array(
160
+ array('a', 'abc'),
161
+ array(1, array(1, 2, 3)),
162
+ array('', null),
163
+ array('', ''),
164
+ array('a', new CoreTestIterator($i, array_keys($i), true, 3)),
165
+ );
166
+ }
167
+
168
+ /**
169
+ * @dataProvider provideTwigLastCases
170
+ */
171
+ public function testTwigLast($expected, $input)
172
+ {
173
+ $twig = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock());
174
+ $this->assertSame($expected, twig_last($twig, $input));
175
+ }
176
+
177
+ public function provideTwigLastCases()
178
+ {
179
+ $i = array(1 => 'a', 2 => 'b', 3 => 'c');
180
+
181
+ return array(
182
+ array('c', 'abc'),
183
+ array(3, array(1, 2, 3)),
184
+ array('', null),
185
+ array('', ''),
186
+ array('c', new CoreTestIterator($i, array_keys($i), true)),
187
+ );
188
+ }
189
+
190
+ /**
191
+ * @dataProvider provideArrayKeyCases
192
+ */
193
+ public function testArrayKeysFilter(array $expected, $input)
194
+ {
195
+ $this->assertSame($expected, twig_get_array_keys_filter($input));
196
+ }
197
+
198
+ public function provideArrayKeyCases()
199
+ {
200
+ $array = array('a' => 'a1', 'b' => 'b1', 'c' => 'c1');
201
+ $keys = array_keys($array);
202
+
203
+ return array(
204
+ array($keys, $array),
205
+ array($keys, new CoreTestIterator($array, $keys)),
206
+ array($keys, new CoreTestIteratorAggregate($array, $keys)),
207
+ array($keys, new CoreTestIteratorAggregateAggregate($array, $keys)),
208
+ array(array(), null),
209
+ array(array('a'), new SimpleXMLElement('<xml><a></a></xml>')),
210
+ );
211
+ }
212
+
213
+ /**
214
+ * @dataProvider provideInFilterCases
215
+ */
216
+ public function testInFilter($expected, $value, $compare)
217
+ {
218
+ $this->assertSame($expected, twig_in_filter($value, $compare));
219
+ }
220
+
221
+ public function provideInFilterCases()
222
+ {
223
+ $array = array(1, 2, 'a' => 3, 5, 6, 7);
224
+ $keys = array_keys($array);
225
+
226
+ return array(
227
+ array(true, 1, $array),
228
+ array(true, '3', $array),
229
+ array(true, '3', 'abc3def'),
230
+ array(true, 1, new CoreTestIterator($array, $keys, true, 1)),
231
+ array(true, '3', new CoreTestIterator($array, $keys, true, 3)),
232
+ array(true, '3', new CoreTestIteratorAggregateAggregate($array, $keys, true, 3)),
233
+ array(false, 4, $array),
234
+ array(false, 4, new CoreTestIterator($array, $keys, true)),
235
+ array(false, 4, new CoreTestIteratorAggregateAggregate($array, $keys, true)),
236
+ array(false, 1, 1),
237
+ array(true, 'b', new SimpleXMLElement('<xml><a>b</a></xml>')),
238
+ );
239
+ }
240
+
241
+ /**
242
+ * @dataProvider provideSliceFilterCases
243
+ */
244
+ public function testSliceFilter($expected, $input, $start, $length = null, $preserveKeys = false)
245
+ {
246
+ $twig = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock());
247
+ $this->assertSame($expected, twig_slice($twig, $input, $start, $length, $preserveKeys));
248
+ }
249
+
250
+ public function provideSliceFilterCases()
251
+ {
252
+ $i = array('a' => 1, 'b' => 2, 'c' => 3, 'd' => 4);
253
+ $keys = array_keys($i);
254
+
255
+ return array(
256
+ array(array('a' => 1), $i, 0, 1, true),
257
+ array(array('a' => 1), $i, 0, 1, false),
258
+ array(array('b' => 2, 'c' => 3), $i, 1, 2),
259
+ array(array(1), array(1, 2, 3, 4), 0, 1),
260
+ array(array(2, 3), array(1, 2, 3, 4), 1, 2),
261
+ array(array(2, 3), new CoreTestIterator($i, $keys, true), 1, 2),
262
+ array(array('c' => 3, 'd' => 4), new CoreTestIteratorAggregate($i, $keys, true), 2, null, true),
263
+ array($i, new CoreTestIterator($i, $keys, true), 0, count($keys) + 10, true),
264
+ array(array(), new CoreTestIterator($i, $keys, true), count($keys) + 10),
265
+ array('de', 'abcdef', 3, 2),
266
+ array(array(), new SimpleXMLElement('<items><item>1</item><item>2</item></items>'), 3),
267
+ array(array(), new ArrayIterator(array(1, 2)), 3)
268
+ );
269
+ }
270
+ }
271
+
272
+ function foo_escaper_for_test(Twig_Environment $env, $string, $charset)
273
+ {
274
+ return $string.$charset;
275
+ }
276
+
277
+ final class CoreTestIteratorAggregate implements IteratorAggregate
278
+ {
279
+ private $iterator;
280
+
281
+ public function __construct(array $array, array $keys, $allowAccess = false, $maxPosition = false)
282
+ {
283
+ $this->iterator = new CoreTestIterator($array, $keys, $allowAccess, $maxPosition);
284
+ }
285
+
286
+ public function getIterator()
287
+ {
288
+ return $this->iterator;
289
+ }
290
+ }
291
+
292
+ final class CoreTestIteratorAggregateAggregate implements IteratorAggregate
293
+ {
294
+ private $iterator;
295
+
296
+ public function __construct(array $array, array $keys, $allowValueAccess = false, $maxPosition = false)
297
+ {
298
+ $this->iterator = new CoreTestIteratorAggregate($array, $keys, $allowValueAccess, $maxPosition);
299
+ }
300
+
301
+ public function getIterator()
302
+ {
303
+ return $this->iterator;
304
+ }
305
+ }
306
+
307
+ final class CoreTestIterator implements Iterator
308
+ {
309
+ private $position;
310
+ private $array;
311
+ private $arrayKeys;
312
+ private $allowValueAccess;
313
+ private $maxPosition;
314
+
315
+ public function __construct(array $values, array $keys, $allowValueAccess = false, $maxPosition = false)
316
+ {
317
+ $this->array = $values;
318
+ $this->arrayKeys = $keys;
319
+ $this->position = 0;
320
+ $this->allowValueAccess = $allowValueAccess;
321
+ $this->maxPosition = false === $maxPosition ? count($values) + 1 : $maxPosition;
322
+ }
323
+
324
+ public function rewind()
325
+ {
326
+ $this->position = 0;
327
+ }
328
+
329
+ public function current()
330
+ {
331
+ if ($this->allowValueAccess) {
332
+ return $this->array[$this->key()];
333
+ }
334
+
335
+ throw new LogicException('Code should only use the keys, not the values provided by iterator.');
336
+ }
337
+
338
+ public function key()
339
+ {
340
+ return $this->arrayKeys[$this->position];
341
+ }
342
+
343
+ public function next()
344
+ {
345
+ ++$this->position;
346
+ if ($this->position === $this->maxPosition) {
347
+ throw new LogicException(sprintf('Code should not iterate beyond %d.', $this->maxPosition));
348
+ }
349
+ }
350
+
351
+ public function valid()
352
+ {
353
+ return isset($this->arrayKeys[$this->position]);
354
+ }
355
+ }
library/twig/twig/test/Twig/Tests/Extension/SandboxTest.php ADDED
@@ -0,0 +1,304 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 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_Tests_Extension_SandboxTest extends PHPUnit_Framework_TestCase
13
+ {
14
+ protected static $params;
15
+ protected static $templates;
16
+
17
+ protected function setUp()
18
+ {
19
+ self::$params = array(
20
+ 'name' => 'Fabien',
21
+ 'obj' => new FooObject(),
22
+ 'arr' => array('obj' => new FooObject()),
23
+ );
24
+
25
+ self::$templates = array(
26
+ '1_basic1' => '{{ obj.foo }}',
27
+ '1_basic2' => '{{ name|upper }}',
28
+ '1_basic3' => '{% if name %}foo{% endif %}',
29
+ '1_basic4' => '{{ obj.bar }}',
30
+ '1_basic5' => '{{ obj }}',
31
+ '1_basic6' => '{{ arr.obj }}',
32
+ '1_basic7' => '{{ cycle(["foo","bar"], 1) }}',
33
+ '1_basic8' => '{{ obj.getfoobar }}{{ obj.getFooBar }}',
34
+ '1_basic9' => '{{ obj.foobar }}{{ obj.fooBar }}',
35
+ '1_basic' => '{% if obj.foo %}{{ obj.foo|upper }}{% endif %}',
36
+ '1_layout' => '{% block content %}{% endblock %}',
37
+ '1_child' => "{% extends \"1_layout\" %}\n{% block content %}\n{{ \"a\"|json_encode }}\n{% endblock %}",
38
+ '1_include' => '{{ include("1_basic1", sandboxed=true) }}',
39
+ );
40
+ }
41
+
42
+ /**
43
+ * @expectedException Twig_Sandbox_SecurityError
44
+ * @expectedExceptionMessage Filter "json_encode" is not allowed in "1_child" at line 3.
45
+ */
46
+ public function testSandboxWithInheritance()
47
+ {
48
+ $twig = $this->getEnvironment(true, array(), self::$templates, array('block'));
49
+ $twig->loadTemplate('1_child')->render(array());
50
+ }
51
+
52
+ public function testSandboxGloballySet()
53
+ {
54
+ $twig = $this->getEnvironment(false, array(), self::$templates);
55
+ $this->assertEquals('FOO', $twig->loadTemplate('1_basic')->render(self::$params), 'Sandbox does nothing if it is disabled globally');
56
+ }
57
+
58
+ public function testSandboxUnallowedMethodAccessor()
59
+ {
60
+ $twig = $this->getEnvironment(true, array(), self::$templates);
61
+ try {
62
+ $twig->loadTemplate('1_basic1')->render(self::$params);
63
+ $this->fail('Sandbox throws a SecurityError exception if an unallowed method is called');
64
+ } catch (Twig_Sandbox_SecurityError $e) {
65
+ $this->assertInstanceOf('Twig_Sandbox_SecurityNotAllowedMethodError', $e, 'Exception should be an instance of Twig_Sandbox_SecurityNotAllowedMethodError');
66
+ $this->assertEquals('FooObject', $e->getClassName(), 'Exception should be raised on the "FooObject" class');
67
+ $this->assertEquals('foo', $e->getMethodName(), 'Exception should be raised on the "foo" method');
68
+ }
69
+ }
70
+
71
+ public function testSandboxUnallowedFilter()
72
+ {
73
+ $twig = $this->getEnvironment(true, array(), self::$templates);
74
+ try {
75
+ $twig->loadTemplate('1_basic2')->render(self::$params);
76
+ $this->fail('Sandbox throws a SecurityError exception if an unallowed filter is called');
77
+ } catch (Twig_Sandbox_SecurityError $e) {
78
+ $this->assertInstanceOf('Twig_Sandbox_SecurityNotAllowedFilterError', $e, 'Exception should be an instance of Twig_Sandbox_SecurityNotAllowedFilterError');
79
+ $this->assertEquals('upper', $e->getFilterName(), 'Exception should be raised on the "upper" filter');
80
+ }
81
+ }
82
+
83
+ public function testSandboxUnallowedTag()
84
+ {
85
+ $twig = $this->getEnvironment(true, array(), self::$templates);
86
+ try {
87
+ $twig->loadTemplate('1_basic3')->render(self::$params);
88
+ $this->fail('Sandbox throws a SecurityError exception if an unallowed tag is used in the template');
89
+ } catch (Twig_Sandbox_SecurityError $e) {
90
+ $this->assertInstanceOf('Twig_Sandbox_SecurityNotAllowedTagError', $e, 'Exception should be an instance of Twig_Sandbox_SecurityNotAllowedTagError');
91
+ $this->assertEquals('if', $e->getTagName(), 'Exception should be raised on the "if" tag');
92
+ }
93
+ }
94
+
95
+ public function testSandboxUnallowedProperty()
96
+ {
97
+ $twig = $this->getEnvironment(true, array(), self::$templates);
98
+ try {
99
+ $twig->loadTemplate('1_basic4')->render(self::$params);
100
+ $this->fail('Sandbox throws a SecurityError exception if an unallowed property is called in the template');
101
+ } catch (Twig_Sandbox_SecurityError $e) {
102
+ $this->assertInstanceOf('Twig_Sandbox_SecurityNotAllowedPropertyError', $e, 'Exception should be an instance of Twig_Sandbox_SecurityNotAllowedPropertyError');
103
+ $this->assertEquals('FooObject', $e->getClassName(), 'Exception should be raised on the "FooObject" class');
104
+ $this->assertEquals('bar', $e->getPropertyName(), 'Exception should be raised on the "bar" property');
105
+ }
106
+ }
107
+
108
+ public function testSandboxUnallowedToString()
109
+ {
110
+ $twig = $this->getEnvironment(true, array(), self::$templates);
111
+ try {
112
+ $twig->loadTemplate('1_basic5')->render(self::$params);
113
+ $this->fail('Sandbox throws a SecurityError exception if an unallowed method (__toString()) is called in the template');
114
+ } catch (Twig_Sandbox_SecurityError $e) {
115
+ $this->assertInstanceOf('Twig_Sandbox_SecurityNotAllowedMethodError', $e, 'Exception should be an instance of Twig_Sandbox_SecurityNotAllowedMethodError');
116
+ $this->assertEquals('FooObject', $e->getClassName(), 'Exception should be raised on the "FooObject" class');
117
+ $this->assertEquals('__tostring', $e->getMethodName(), 'Exception should be raised on the "__toString" method');
118
+ }
119
+ }
120
+
121
+ public function testSandboxUnallowedToStringArray()
122
+ {
123
+ $twig = $this->getEnvironment(true, array(), self::$templates);
124
+ try {
125
+ $twig->loadTemplate('1_basic6')->render(self::$params);
126
+ $this->fail('Sandbox throws a SecurityError exception if an unallowed method (__toString()) is called in the template');
127
+ } catch (Twig_Sandbox_SecurityError $e) {
128
+ $this->assertInstanceOf('Twig_Sandbox_SecurityNotAllowedMethodError', $e, 'Exception should be an instance of Twig_Sandbox_SecurityNotAllowedMethodError');
129
+ $this->assertEquals('FooObject', $e->getClassName(), 'Exception should be raised on the "FooObject" class');
130
+ $this->assertEquals('__tostring', $e->getMethodName(), 'Exception should be raised on the "__toString" method');
131
+ }
132
+ }
133
+
134
+ public function testSandboxUnallowedFunction()
135
+ {
136
+ $twig = $this->getEnvironment(true, array(), self::$templates);
137
+ try {
138
+ $twig->loadTemplate('1_basic7')->render(self::$params);
139
+ $this->fail('Sandbox throws a SecurityError exception if an unallowed function is called in the template');
140
+ } catch (Twig_Sandbox_SecurityError $e) {
141
+ $this->assertInstanceOf('Twig_Sandbox_SecurityNotAllowedFunctionError', $e, 'Exception should be an instance of Twig_Sandbox_SecurityNotAllowedFunctionError');
142
+ $this->assertEquals('cycle', $e->getFunctionName(), 'Exception should be raised on the "cycle" function');
143
+ }
144
+ }
145
+
146
+ public function testSandboxAllowMethodFoo()
147
+ {
148
+ $twig = $this->getEnvironment(true, array(), self::$templates, array(), array(), array('FooObject' => 'foo'));
149
+ FooObject::reset();
150
+ $this->assertEquals('foo', $twig->loadTemplate('1_basic1')->render(self::$params), 'Sandbox allow some methods');
151
+ $this->assertEquals(1, FooObject::$called['foo'], 'Sandbox only calls method once');
152
+ }
153
+
154
+ public function testSandboxAllowMethodToString()
155
+ {
156
+ $twig = $this->getEnvironment(true, array(), self::$templates, array(), array(), array('FooObject' => '__toString'));
157
+ FooObject::reset();
158
+ $this->assertEquals('foo', $twig->loadTemplate('1_basic5')->render(self::$params), 'Sandbox allow some methods');
159
+ $this->assertEquals(1, FooObject::$called['__toString'], 'Sandbox only calls method once');
160
+ }
161
+
162
+ public function testSandboxAllowMethodToStringDisabled()
163
+ {
164
+ $twig = $this->getEnvironment(false, array(), self::$templates);
165
+ FooObject::reset();
166
+ $this->assertEquals('foo', $twig->loadTemplate('1_basic5')->render(self::$params), 'Sandbox allows __toString when sandbox disabled');
167
+ $this->assertEquals(1, FooObject::$called['__toString'], 'Sandbox only calls method once');
168
+ }
169
+
170
+ public function testSandboxAllowFilter()
171
+ {
172
+ $twig = $this->getEnvironment(true, array(), self::$templates, array(), array('upper'));
173
+ $this->assertEquals('FABIEN', $twig->loadTemplate('1_basic2')->render(self::$params), 'Sandbox allow some filters');
174
+ }
175
+
176
+ public function testSandboxAllowTag()
177
+ {
178
+ $twig = $this->getEnvironment(true, array(), self::$templates, array('if'));
179
+ $this->assertEquals('foo', $twig->loadTemplate('1_basic3')->render(self::$params), 'Sandbox allow some tags');
180
+ }
181
+
182
+ public function testSandboxAllowProperty()
183
+ {
184
+ $twig = $this->getEnvironment(true, array(), self::$templates, array(), array(), array(), array('FooObject' => 'bar'));
185
+ $this->assertEquals('bar', $twig->loadTemplate('1_basic4')->render(self::$params), 'Sandbox allow some properties');
186
+ }
187
+
188
+ public function testSandboxAllowFunction()
189
+ {
190
+ $twig = $this->getEnvironment(true, array(), self::$templates, array(), array(), array(), array(), array('cycle'));
191
+ $this->assertEquals('bar', $twig->loadTemplate('1_basic7')->render(self::$params), 'Sandbox allow some functions');
192
+ }
193
+
194
+ public function testSandboxAllowFunctionsCaseInsensitive()
195
+ {
196
+ foreach (array('getfoobar', 'getFoobar', 'getFooBar') as $name) {
197
+ $twig = $this->getEnvironment(true, array(), self::$templates, array(), array(), array('FooObject' => $name));
198
+ FooObject::reset();
199
+ $this->assertEquals('foobarfoobar', $twig->loadTemplate('1_basic8')->render(self::$params), 'Sandbox allow methods in a case-insensitive way');
200
+ $this->assertEquals(2, FooObject::$called['getFooBar'], 'Sandbox only calls method once');
201
+
202
+ $this->assertEquals('foobarfoobar', $twig->loadTemplate('1_basic9')->render(self::$params), 'Sandbox allow methods via shortcut names (ie. without get/set)');
203
+ }
204
+ }
205
+
206
+ public function testSandboxLocallySetForAnInclude()
207
+ {
208
+ self::$templates = array(
209
+ '2_basic' => '{{ obj.foo }}{% include "2_included" %}{{ obj.foo }}',
210
+ '2_included' => '{% if obj.foo %}{{ obj.foo|upper }}{% endif %}',
211
+ );
212
+
213
+ $twig = $this->getEnvironment(false, array(), self::$templates);
214
+ $this->assertEquals('fooFOOfoo', $twig->loadTemplate('2_basic')->render(self::$params), 'Sandbox does nothing if disabled globally and sandboxed not used for the include');
215
+
216
+ self::$templates = array(
217
+ '3_basic' => '{{ obj.foo }}{% sandbox %}{% include "3_included" %}{% endsandbox %}{{ obj.foo }}',
218
+ '3_included' => '{% if obj.foo %}{{ obj.foo|upper }}{% endif %}',
219
+ );
220
+
221
+ $twig = $this->getEnvironment(true, array(), self::$templates);
222
+ try {
223
+ $twig->loadTemplate('3_basic')->render(self::$params);
224
+ $this->fail('Sandbox throws a SecurityError exception when the included file is sandboxed');
225
+ } catch (Twig_Sandbox_SecurityError $e) {
226
+ $this->assertInstanceOf('Twig_Sandbox_SecurityNotAllowedTagError', $e, 'Exception should be an instance of Twig_Sandbox_SecurityNotAllowedTagError');
227
+ $this->assertEquals('sandbox', $e->getTagName());
228
+ }
229
+ }
230
+
231
+ public function testMacrosInASandbox()
232
+ {
233
+ $twig = $this->getEnvironment(true, array('autoescape' => 'html'), array('index' => <<<EOF
234
+ {%- import _self as macros %}
235
+
236
+ {%- macro test(text) %}<p>{{ text }}</p>{% endmacro %}
237
+
238
+ {{- macros.test('username') }}
239
+ EOF
240
+ ), array('macro', 'import'), array('escape'));
241
+
242
+ $this->assertEquals('<p>username</p>', $twig->loadTemplate('index')->render(array()));
243
+ }
244
+
245
+ public function testSandboxDisabledAfterIncludeFunctionError()
246
+ {
247
+ $twig = $this->getEnvironment(false, array(), self::$templates);
248
+
249
+ $e = null;
250
+ try {
251
+ $twig->loadTemplate('1_include')->render(self::$params);
252
+ } catch (Throwable $e) {
253
+ } catch (Exception $e) {
254
+ }
255
+ if ($e === null) {
256
+ $this->fail('An exception should be thrown for this test to be valid.');
257
+ }
258
+
259
+ $this->assertFalse($twig->getExtension('Twig_Extension_Sandbox')->isSandboxed(), 'Sandboxed include() function call should not leave Sandbox enabled when an error occurs.');
260
+ }
261
+
262
+ protected function getEnvironment($sandboxed, $options, $templates, $tags = array(), $filters = array(), $methods = array(), $properties = array(), $functions = array())
263
+ {
264
+ $loader = new Twig_Loader_Array($templates);
265
+ $twig = new Twig_Environment($loader, array_merge(array('debug' => true, 'cache' => false, 'autoescape' => false), $options));
266
+ $policy = new Twig_Sandbox_SecurityPolicy($tags, $filters, $methods, $properties, $functions);
267
+ $twig->addExtension(new Twig_Extension_Sandbox($policy, $sandboxed));
268
+
269
+ return $twig;
270
+ }
271
+ }
272
+
273
+ class FooObject
274
+ {
275
+ public static $called = array('__toString' => 0, 'foo' => 0, 'getFooBar' => 0);
276
+
277
+ public $bar = 'bar';
278
+
279
+ public static function reset()
280
+ {
281
+ self::$called = array('__toString' => 0, 'foo' => 0, 'getFooBar' => 0);
282
+ }
283
+
284
+ public function __toString()
285
+ {
286
+ ++self::$called['__toString'];
287
+
288
+ return 'foo';
289
+ }
290
+
291
+ public function foo()
292
+ {
293
+ ++self::$called['foo'];
294
+
295
+ return 'foo';
296
+ }
297
+
298
+ public function getFooBar()
299
+ {
300
+ ++self::$called['getFooBar'];
301
+
302
+ return 'foobar';
303
+ }
304
+ }
library/twig/twig/test/Twig/Tests/FileCachingTest.php ADDED
@@ -0,0 +1,63 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 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
+ require_once dirname(__FILE__).'/FilesystemHelper.php';
13
+
14
+ class Twig_Tests_FileCachingTest extends PHPUnit_Framework_TestCase
15
+ {
16
+ private $env;
17
+ private $tmpDir;
18
+
19
+ protected function setUp()
20
+ {
21
+ $this->tmpDir = sys_get_temp_dir().'/TwigTests';
22
+ if (!file_exists($this->tmpDir)) {
23
+ @mkdir($this->tmpDir, 0777, true);
24
+ }
25
+
26
+ if (!is_writable($this->tmpDir)) {
27
+ $this->markTestSkipped(sprintf('Unable to run the tests as "%s" is not writable.', $this->tmpDir));
28
+ }
29
+
30
+ $this->env = new Twig_Environment(new Twig_Loader_Array(array('index' => 'index', 'index2' => 'index2')), array('cache' => $this->tmpDir));
31
+ }
32
+
33
+ protected function tearDown()
34
+ {
35
+ Twig_Tests_FilesystemHelper::removeDir($this->tmpDir);
36
+ }
37
+
38
+ /**
39
+ * @group legacy
40
+ */
41
+ public function testWritingCacheFiles()
42
+ {
43
+ $name = 'index';
44
+ $this->env->loadTemplate($name);
45
+ $cacheFileName = $this->env->getCacheFilename($name);
46
+
47
+ $this->assertFileExists($cacheFileName, 'Cache file does not exist.');
48
+ }
49
+
50
+ /**
51
+ * @group legacy
52
+ */
53
+ public function testClearingCacheFiles()
54
+ {
55
+ $name = 'index2';
56
+ $this->env->loadTemplate($name);
57
+ $cacheFileName = $this->env->getCacheFilename($name);
58
+
59
+ $this->assertFileExists($cacheFileName, 'Cache file does not exist.');
60
+ $this->env->clearCacheFiles();
61
+ $this->assertFileNotExists($cacheFileName, 'Cache file was not cleared.');
62
+ }
63
+ }
library/twig/twig/test/Twig/Tests/FileExtensionEscapingStrategyTest.php ADDED
@@ -0,0 +1,51 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 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_Tests_FileExtensionEscapingStrategyTest extends PHPUnit_Framework_TestCase
13
+ {
14
+ /**
15
+ * @dataProvider getGuessData
16
+ */
17
+ public function testGuess($strategy, $filename)
18
+ {
19
+ $this->assertSame($strategy, Twig_FileExtensionEscapingStrategy::guess($filename));
20
+ }
21
+
22
+ public function getGuessData()
23
+ {
24
+ return array(
25
+ // default
26
+ array('html', 'foo.html'),
27
+ array('html', 'foo.html.twig'),
28
+ array('html', 'foo'),
29
+ array('html', 'foo.bar.twig'),
30
+ array('html', 'foo.txt/foo'),
31
+ array('html', 'foo.txt/foo.js/'),
32
+
33
+ // css
34
+ array('css', 'foo.css'),
35
+ array('css', 'foo.css.twig'),
36
+ array('css', 'foo.twig.css'),
37
+ array('css', 'foo.js.css'),
38
+ array('css', 'foo.js.css.twig'),
39
+
40
+ // js
41
+ array('js', 'foo.js'),
42
+ array('js', 'foo.js.twig'),
43
+ array('js', 'foo.txt/foo.js'),
44
+ array('js', 'foo.txt.twig/foo.js'),
45
+
46
+ // txt
47
+ array(false, 'foo.txt'),
48
+ array(false, 'foo.txt.twig'),
49
+ );
50
+ }
51
+ }
library/twig/twig/test/Twig/Tests/FilesystemHelper.php ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 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_Tests_FilesystemHelper
13
+ {
14
+ public static function removeDir($dir)
15
+ {
16
+ $iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dir, PHP_VERSION_ID < 50300 ? 0 : FilesystemIterator::SKIP_DOTS), RecursiveIteratorIterator::CHILD_FIRST);
17
+ foreach ($iterator as $filename => $fileInfo) {
18
+ if ($iterator->isDot()) {
19
+ continue;
20
+ }
21
+
22
+ if ($fileInfo->isDir()) {
23
+ rmdir($filename);
24
+ } else {
25
+ unlink($filename);
26
+ }
27
+ }
28
+ rmdir($dir);
29
+ }
30
+ }
library/twig/twig/test/Twig/Tests/Fixtures/autoescape/block.test ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ blocks and autoescape
3
+ --TEMPLATE--
4
+ {{ include('unrelated.txt.twig') -}}
5
+ {{ include('template.html.twig') -}}
6
+ --TEMPLATE(unrelated.txt.twig)--
7
+ {% block content %}{% endblock %}
8
+ --TEMPLATE(template.html.twig)--
9
+ {% extends 'parent.html.twig' %}
10
+ {% block content %}
11
+ {{ br -}}
12
+ {% endblock %}
13
+ --TEMPLATE(parent.html.twig)--
14
+ {% set _content = block('content')|raw %}
15
+ {{ _content|raw }}
16
+ --DATA--
17
+ return array('br' => '<br />')
18
+ --CONFIG--
19
+ return array('autoescape' => 'name')
20
+ --EXPECT--
21
+ &lt;br /&gt;
library/twig/twig/test/Twig/Tests/Fixtures/autoescape/name.test ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "name" autoescape strategy
3
+ --TEMPLATE--
4
+ {{ br -}}
5
+ {{ include('index.html.twig') -}}
6
+ {{ include('index.txt.twig') -}}
7
+ --TEMPLATE(index.html.twig)--
8
+ {{ br -}}
9
+ --TEMPLATE(index.txt.twig)--
10
+ {{ br -}}
11
+ --DATA--
12
+ return array('br' => '<br />')
13
+ --CONFIG--
14
+ return array('autoescape' => 'name')
15
+ --EXPECT--
16
+ &lt;br /&gt;
17
+ &lt;br /&gt;
18
+ <br />
library/twig/twig/test/Twig/Tests/Fixtures/errors/base.html ADDED
@@ -0,0 +1 @@
 
1
+ {% block content %}{% endblock %}
library/twig/twig/test/Twig/Tests/Fixtures/errors/index.html ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
1
+ {% extends 'base.html' %}
2
+ {% block content %}
3
+ {{ foo.bar }}
4
+ {% endblock %}
5
+ {% block foo %}
6
+ {{ foo.bar }}
7
+ {% endblock %}
library/twig/twig/test/Twig/Tests/Fixtures/exceptions/child_contents_outside_blocks.test ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ Exception for child templates defining contents outside blocks defined by parent
3
+ --TEMPLATE--
4
+ {% extends 'base.twig' %}
5
+
6
+ Content outside a block.
7
+
8
+ {% block sidebar %}
9
+ Content inside a block.
10
+ {% endblock %}
11
+ --TEMPLATE(base.twig)--
12
+ {% block sidebar %}
13
+ {% endblock %}
14
+ --EXCEPTION--
15
+ Twig_Error_Syntax: A template that extends another one cannot include contents outside Twig blocks. Did you forget to put the contents inside a {% block %} tag in "index.twig" at line 3?
library/twig/twig/test/Twig/Tests/Fixtures/exceptions/multiline_array_with_undefined_variable.test ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ Exception for multiline array with undefined variable
3
+ --TEMPLATE--
4
+ {% set foo = {
5
+ foo: 'foo',
6
+ bar: 'bar',
7
+
8
+
9
+ foobar: foobar,
10
+
11
+
12
+
13
+ foo2: foo2,
14
+ } %}
15
+ --DATA--
16
+ return array('foobar' => 'foobar')
17
+ --EXCEPTION--
18
+ Twig_Error_Runtime: Variable "foo2" does not exist in "index.twig" at line 11.
library/twig/twig/test/Twig/Tests/Fixtures/exceptions/multiline_array_with_undefined_variable_again.test ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ Exception for multiline array with undefined variable
3
+ --TEMPLATE--
4
+ {% set foo = {
5
+ foo: 'foo',
6
+ bar: 'bar',
7
+
8
+
9
+ foobar: foobar,
10
+
11
+
12
+
13
+ foo2: foo2,
14
+ } %}
15
+ --DATA--
16
+ return array()
17
+ --EXCEPTION--
18
+ Twig_Error_Runtime: Variable "foobar" does not exist in "index.twig" at line 7.
library/twig/twig/test/Twig/Tests/Fixtures/exceptions/multiline_function_with_undefined_variable.test ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ Exception for multile function with undefined variable
3
+ --TEMPLATE--
4
+ {{ include('foo',
5
+ with_context=with_context
6
+ ) }}
7
+ --TEMPLATE(foo)--
8
+ Foo
9
+ --DATA--
10
+ return array()
11
+ --EXCEPTION--
12
+ Twig_Error_Runtime: Variable "with_context" does not exist in "index.twig" at line 3.
library/twig/twig/test/Twig/Tests/Fixtures/exceptions/multiline_function_with_unknown_argument.test ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ Exception for multiline function with unknown argument
3
+ --TEMPLATE--
4
+ {{ include('foo',
5
+ with_context=True,
6
+ invalid=False
7
+ ) }}
8
+ --EXCEPTION--
9
+ Twig_Error_Syntax: Unknown argument "invalid" for function "include(template, variables, with_context, ignore_missing, sandboxed)" in "index.twig" at line 4.
library/twig/twig/test/Twig/Tests/Fixtures/exceptions/multiline_tag_with_undefined_variable.test ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ Exception for multiline tag with undefined variable
3
+ --TEMPLATE--
4
+ {% include 'foo'
5
+ with vars
6
+ %}
7
+ --TEMPLATE(foo)--
8
+ Foo
9
+ --DATA--
10
+ return array()
11
+ --EXCEPTION--
12
+ Twig_Error_Runtime: Variable "vars" does not exist in "index.twig" at line 3.
library/twig/twig/test/Twig/Tests/Fixtures/exceptions/syntax_error_in_reused_template.test ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ Exception for syntax error in reused template
3
+ --TEMPLATE--
4
+ {% use 'foo.twig' %}
5
+ --TEMPLATE(foo.twig)--
6
+ {% block bar %}
7
+ {% do node.data = 5 %}
8
+ {% endblock %}
9
+ --EXCEPTION--
10
+ Twig_Error_Syntax: Unexpected token "operator" of value "=" ("end of statement block" expected) in "foo.twig" at line 3.
library/twig/twig/test/Twig/Tests/Fixtures/exceptions/unclosed_tag.test ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ Exception for an unclosed tag
3
+ --TEMPLATE--
4
+ {% block foo %}
5
+ {% if foo %}
6
+
7
+
8
+
9
+
10
+ {% for i in fo %}
11
+
12
+
13
+
14
+ {% endfor %}
15
+
16
+
17
+
18
+ {% endblock %}
19
+ --EXCEPTION--
20
+ Twig_Error_Syntax: Unexpected "endblock" tag (expecting closing tag for the "if" tag defined near line 4) in "index.twig" at line 16.
library/twig/twig/test/Twig/Tests/Fixtures/exceptions/undefined_parent.test ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ Exception for an undefined parent
3
+ --TEMPLATE--
4
+ {% extends 'foo.html' %}
5
+
6
+ {% set foo = "foo" %}
7
+ --EXCEPTION--
8
+ Twig_Error_Loader: Template "foo.html" is not defined in "index.twig" at line 2.
library/twig/twig/test/Twig/Tests/Fixtures/exceptions/undefined_template_in_child_template.test ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ Exception for an undefined template in a child template
3
+ --TEMPLATE--
4
+ {% extends 'base.twig' %}
5
+
6
+ {% block sidebar %}
7
+ {{ include('include.twig') }}
8
+ {% endblock %}
9
+ --TEMPLATE(base.twig)--
10
+ {% block sidebar %}
11
+ {% endblock %}
12
+ --DATA--
13
+ return array()
14
+ --EXCEPTION--
15
+ Twig_Error_Loader: Template "include.twig" is not defined in "index.twig" at line 5.
library/twig/twig/test/Twig/Tests/Fixtures/exceptions/undefined_trait.test ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ Exception for an undefined trait
3
+ --TEMPLATE--
4
+ {% use 'foo' with foobar as bar %}
5
+ --TEMPLATE(foo)--
6
+ {% block bar %}
7
+ {% endblock %}
8
+ --EXCEPTION--
9
+ Twig_Error_Runtime: Block "foobar" is not defined in trait "foo" in "index.twig" at line 2.
library/twig/twig/test/Twig/Tests/Fixtures/expressions/_self.test ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ _self returns the template name
3
+ --TEMPLATE--
4
+ {{ _self }}
5
+ --DATA--
6
+ return array()
7
+ --EXPECT--
8
+ index.twig
library/twig/twig/test/Twig/Tests/Fixtures/expressions/array.test ADDED
@@ -0,0 +1,61 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ Twig supports array notation
3
+ --TEMPLATE--
4
+ {# empty array #}
5
+ {{ []|join(',') }}
6
+
7
+ {{ [1, 2]|join(',') }}
8
+ {{ ['foo', "bar"]|join(',') }}
9
+ {{ {0: 1, 'foo': 'bar'}|join(',') }}
10
+ {{ {0: 1, 'foo': 'bar'}|keys|join(',') }}
11
+
12
+ {{ {0: 1, foo: 'bar'}|join(',') }}
13
+ {{ {0: 1, foo: 'bar'}|keys|join(',') }}
14
+
15
+ {# nested arrays #}
16
+ {% set a = [1, 2, [1, 2], {'foo': {'foo': 'bar'}}] %}
17
+ {{ a[2]|join(',') }}
18
+ {{ a[3]["foo"]|join(',') }}
19
+
20
+ {# works even if [] is used inside the array #}
21
+ {{ [foo[bar]]|join(',') }}
22
+
23
+ {# elements can be any expression #}
24
+ {{ ['foo'|upper, bar|upper, bar == foo]|join(',') }}
25
+
26
+ {# arrays can have a trailing , like in PHP #}
27
+ {{
28
+ [
29
+ 1,
30
+ 2,
31
+ ]|join(',')
32
+ }}
33
+
34
+ {# keys can be any expression #}
35
+ {% set a = 1 %}
36
+ {% set b = "foo" %}
37
+ {% set ary = { (a): 'a', (b): 'b', 'c': 'c', (a ~ b): 'd' } %}
38
+ {{ ary|keys|join(',') }}
39
+ {{ ary|join(',') }}
40
+ --DATA--
41
+ return array('bar' => 'bar', 'foo' => array('bar' => 'bar'))
42
+ --EXPECT--
43
+ 1,2
44
+ foo,bar
45
+ 1,bar
46
+ 0,foo
47
+
48
+ 1,bar
49
+ 0,foo
50
+
51
+ 1,2
52
+ bar
53
+
54
+ bar
55
+
56
+ FOO,BAR,
57
+
58
+ 1,2
59
+
60
+ 1,foo,c,1foo
61
+ a,b,c,d
library/twig/twig/test/Twig/Tests/Fixtures/expressions/array_call.test ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ Twig supports method calls
3
+ --TEMPLATE--
4
+ {{ items.foo }}
5
+ {{ items['foo'] }}
6
+ {{ items[foo] }}
7
+ {{ items[items[foo]] }}
8
+ --DATA--
9
+ return array('foo' => 'bar', 'items' => array('foo' => 'bar', 'bar' => 'foo'))
10
+ --EXPECT--
11
+ bar
12
+ bar
13
+ foo
14
+ bar
library/twig/twig/test/Twig/Tests/Fixtures/expressions/binary.test ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ Twig supports binary operations (+, -, *, /, ~, %, and, or)
3
+ --TEMPLATE--
4
+ {{ 1 + 1 }}
5
+ {{ 2 - 1 }}
6
+ {{ 2 * 2 }}
7
+ {{ 2 / 2 }}
8
+ {{ 3 % 2 }}
9
+ {{ 1 and 1 }}
10
+ {{ 1 and 0 }}
11
+ {{ 0 and 1 }}
12
+ {{ 0 and 0 }}
13
+ {{ 1 or 1 }}
14
+ {{ 1 or 0 }}
15
+ {{ 0 or 1 }}
16
+ {{ 0 or 0 }}
17
+ {{ 0 or 1 and 0 }}
18
+ {{ 1 or 0 and 1 }}
19
+ {{ "foo" ~ "bar" }}
20
+ {{ foo ~ "bar" }}
21
+ {{ "foo" ~ bar }}
22
+ {{ foo ~ bar }}
23
+ {{ 20 // 7 }}
24
+ --DATA--
25
+ return array('foo' => 'bar', 'bar' => 'foo')
26
+ --EXPECT--
27
+ 2
28
+ 1
29
+ 4
30
+ 1
31
+ 1
32
+ 1
33
+
34
+
35
+
36
+ 1
37
+ 1
38
+ 1
39
+
40
+
41
+ 1
42
+ foobar
43
+ barbar
44
+ foofoo
45
+ barfoo
46
+ 2
library/twig/twig/test/Twig/Tests/Fixtures/expressions/bitwise.test ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ Twig supports bitwise operations
3
+ --TEMPLATE--
4
+ {{ 1 b-and 5 }}
5
+ {{ 1 b-or 5 }}
6
+ {{ 1 b-xor 5 }}
7
+ {{ (1 and 0 b-or 0) is same as(1 and (0 b-or 0)) ? 'ok' : 'ko' }}
8
+ --DATA--
9
+ return array()
10
+ --EXPECT--
11
+ 1
12
+ 5
13
+ 4
14
+ ok
library/twig/twig/test/Twig/Tests/Fixtures/expressions/comparison.test ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ Twig supports comparison operators (==, !=, <, >, >=, <=)
3
+ --TEMPLATE--
4
+ {{ 1 > 2 }}/{{ 1 > 1 }}/{{ 1 >= 2 }}/{{ 1 >= 1 }}
5
+ {{ 1 < 2 }}/{{ 1 < 1 }}/{{ 1 <= 2 }}/{{ 1 <= 1 }}
6
+ {{ 1 == 1 }}/{{ 1 == 2 }}
7
+ {{ 1 != 1 }}/{{ 1 != 2 }}
8
+ --DATA--
9
+ return array()
10
+ --EXPECT--
11
+ ///1
12
+ 1//1/1
13
+ 1/
14
+ /1
library/twig/twig/test/Twig/Tests/Fixtures/expressions/divisibleby.test ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ Twig supports the "divisible by" operator
3
+ --TEMPLATE--
4
+ {{ 8 is divisible by(2) ? 'OK' }}
5
+ {{ 8 is not divisible by(3) ? 'OK' }}
6
+ {{ 8 is divisible by (2) ? 'OK' }}
7
+ {{ 8 is not
8
+ divisible
9
+ by
10
+ (3) ? 'OK' }}
11
+ --DATA--
12
+ return array()
13
+ --EXPECT--
14
+ OK
15
+ OK
16
+ OK
17
+ OK
library/twig/twig/test/Twig/Tests/Fixtures/expressions/dotdot.test ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ Twig supports the .. operator
3
+ --TEMPLATE--
4
+ {% for i in 0..10 %}{{ i }} {% endfor %}
5
+
6
+ {% for letter in 'a'..'z' %}{{ letter }} {% endfor %}
7
+
8
+ {% for letter in 'a'|upper..'z'|upper %}{{ letter }} {% endfor %}
9
+
10
+ {% for i in foo[0]..foo[1] %}{{ i }} {% endfor %}
11
+
12
+ {% for i in 0 + 1 .. 10 - 1 %}{{ i }} {% endfor %}
13
+ --DATA--
14
+ return array('foo' => array(1, 10))
15
+ --EXPECT--
16
+ 0 1 2 3 4 5 6 7 8 9 10
17
+ a b c d e f g h i j k l m n o p q r s t u v w x y z
18
+ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
19
+ 1 2 3 4 5 6 7 8 9 10
20
+ 1 2 3 4 5 6 7 8 9
library/twig/twig/test/Twig/Tests/Fixtures/expressions/ends_with.test ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ Twig supports the "ends with" operator
3
+ --TEMPLATE--
4
+ {{ 'foo' ends with 'o' ? 'OK' : 'KO' }}
5
+ {{ not ('foo' ends with 'f') ? 'OK' : 'KO' }}
6
+ {{ not ('foo' ends with 'foowaytoolong') ? 'OK' : 'KO' }}
7
+ {{ 'foo' ends with '' ? 'OK' : 'KO' }}
8
+ {{ '1' ends with true ? 'OK' : 'KO' }}
9
+ {{ 1 ends with true ? 'OK' : 'KO' }}
10
+ {{ 0 ends with false ? 'OK' : 'KO' }}
11
+ {{ '' ends with false ? 'OK' : 'KO' }}
12
+ {{ false ends with false ? 'OK' : 'KO' }}
13
+ {{ false ends with '' ? 'OK' : 'KO' }}
14
+ --DATA--
15
+ return array()
16
+ --EXPECT--
17
+ OK
18
+ OK
19
+ OK
20
+ OK
21
+ KO
22
+ KO
23
+ KO
24
+ KO
25
+ KO
26
+ KO
library/twig/twig/test/Twig/Tests/Fixtures/expressions/grouping.test ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ Twig supports grouping of expressions
3
+ --TEMPLATE--
4
+ {{ (2 + 2) / 2 }}
5
+ --DATA--
6
+ return array()
7
+ --EXPECT--
8
+ 2
library/twig/twig/test/Twig/Tests/Fixtures/expressions/literals.test ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ Twig supports literals
3
+ --TEMPLATE--
4
+ 1 {{ true }}
5
+ 2 {{ TRUE }}
6
+ 3 {{ false }}
7
+ 4 {{ FALSE }}
8
+ 5 {{ none }}
9
+ 6 {{ NONE }}
10
+ 7 {{ null }}
11
+ 8 {{ NULL }}
12
+ --DATA--
13
+ return array()
14
+ --EXPECT--
15
+ 1 1
16
+ 2 1
17
+ 3
18
+ 4
19
+ 5
20
+ 6
21
+ 7
22
+ 8
library/twig/twig/test/Twig/Tests/Fixtures/expressions/magic_call.test ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ Twig supports __call() for attributes
3
+ --TEMPLATE--
4
+ {{ foo.foo }}
5
+ {{ foo.bar }}
6
+ --DATA--
7
+ class TestClassForMagicCallAttributes
8
+ {
9
+ public function getBar()
10
+ {
11
+ return 'bar_from_getbar';
12
+ }
13
+
14
+ public function __call($method, $arguments)
15
+ {
16
+ if ('foo' === $method) {
17
+ return 'foo_from_call';
18
+ }
19
+
20
+ return false;
21
+ }
22
+ }
23
+
24
+ return array('foo' => new TestClassForMagicCallAttributes())
25
+ --EXPECT--
26
+ foo_from_call
27
+ bar_from_getbar
library/twig/twig/test/Twig/Tests/Fixtures/expressions/matches.test ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ Twig supports the "matches" operator
3
+ --TEMPLATE--
4
+ {{ 'foo' matches '/o/' ? 'OK' : 'KO' }}
5
+ {{ 'foo' matches '/^fo/' ? 'OK' : 'KO' }}
6
+ {{ 'foo' matches '/O/i' ? 'OK' : 'KO' }}
7
+ --DATA--
8
+ return array()
9
+ --EXPECT--
10
+ OK
11
+ OK
12
+ OK
library/twig/twig/test/Twig/Tests/Fixtures/expressions/method_call.test ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ Twig supports method calls
3
+ --TEMPLATE--
4
+ {{ items.foo.foo }}
5
+ {{ items.foo.getFoo() }}
6
+ {{ items.foo.bar }}
7
+ {{ items.foo['bar'] }}
8
+ {{ items.foo.bar('a', 43) }}
9
+ {{ items.foo.bar(foo) }}
10
+ {{ items.foo.self.foo() }}
11
+ {{ items.foo.is }}
12
+ {{ items.foo.in }}
13
+ {{ items.foo.not }}
14
+ --DATA--
15
+ return array('foo' => 'bar', 'items' => array('foo' => new TwigTestFoo(), 'bar' => 'foo'))
16
+ --CONFIG--
17
+ return array('strict_variables' => false)
18
+ --EXPECT--
19
+ foo
20
+ foo
21
+ bar
22
+
23
+ bar_a-43
24
+ bar_bar
25
+ foo
26
+ is
27
+ in
28
+ not
library/twig/twig/test/Twig/Tests/Fixtures/expressions/negative_numbers.test ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ Twig manages negative numbers correctly
3
+ --TEMPLATE--
4
+ {{ -1 }}
5
+ {{ - 1 }}
6
+ {{ 5 - 1 }}
7
+ {{ 5-1 }}
8
+ {{ 5 + -1 }}
9
+ {{ 5 + - 1 }}
10
+ --DATA--
11
+ return array()
12
+ --EXPECT--
13
+ -1
14
+ -1
15
+ 4
16
+ 4
17
+ 4
18
+ 4
library/twig/twig/test/Twig/Tests/Fixtures/expressions/operators_as_variables.test ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ Twig allows to use named operators as variable names
3
+ --TEMPLATE--
4
+ {% for match in matches %}
5
+ {{- match }}
6
+ {% endfor %}
7
+ {{ in }}
8
+ {{ is }}
9
+ --DATA--
10
+ return array('matches' => array(1, 2, 3), 'in' => 'in', 'is' => 'is')
11
+ --EXPECT--
12
+ 1
13
+ 2
14
+ 3
15
+ in
16
+ is
library/twig/twig/test/Twig/Tests/Fixtures/expressions/postfix.test ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ Twig parses postfix expressions
3
+ --TEMPLATE--
4
+ {% import _self as macros %}
5
+
6
+ {% macro foo() %}foo{% endmacro %}
7
+
8
+ {{ 'a' }}
9
+ {{ 'a'|upper }}
10
+ {{ ('a')|upper }}
11
+ {{ -1|upper }}
12
+ {{ macros.foo() }}
13
+ {{ (macros).foo() }}
14
+ --DATA--
15
+ return array();
16
+ --EXPECT--
17
+ a
18
+ A
19
+ A
20
+ -1
21
+ foo
22
+ foo
library/twig/twig/test/Twig/Tests/Fixtures/expressions/power.test ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ Twig parses power expressions
3
+ --TEMPLATE--
4
+ {{ 2**3 }}
5
+ {{ (-2)**3 }}
6
+ {{ (-2)**(-3) }}
7
+ {{ a ** a }}
8
+ {{ a ** b }}
9
+ {{ b ** a }}
10
+ {{ b ** b }}
11
+ --DATA--
12
+ return array('a' => 4, 'b' => -2);
13
+ --EXPECT--
14
+ 8
15
+ -8
16
+ -0.125
17
+ 256
18
+ 0.0625
19
+ 16
20
+ 0.25
library/twig/twig/test/Twig/Tests/Fixtures/expressions/sameas.test ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ Twig supports the "same as" operator
3
+ --TEMPLATE--
4
+ {{ 1 is same as(1) ? 'OK' }}
5
+ {{ 1 is not same as(true) ? 'OK' }}
6
+ {{ 1 is same as(1) ? 'OK' }}
7
+ {{ 1 is not same as(true) ? 'OK' }}
8
+ {{ 1 is same as (1) ? 'OK' }}
9
+ {{ 1 is not
10
+ same
11
+ as
12
+ (true) ? 'OK' }}
13
+ --DATA--
14
+ return array()
15
+ --EXPECT--
16
+ OK
17
+ OK
18
+ OK
19
+ OK
20
+ OK
21
+ OK
library/twig/twig/test/Twig/Tests/Fixtures/expressions/starts_with.test ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ Twig supports the "starts with" operator
3
+ --TEMPLATE--
4
+ {{ 'foo' starts with 'f' ? 'OK' : 'KO' }}
5
+ {{ not ('foo' starts with 'oo') ? 'OK' : 'KO' }}
6
+ {{ not ('foo' starts with 'foowaytoolong') ? 'OK' : 'KO' }}
7
+ {{ 'foo' starts with 'f' ? 'OK' : 'KO' }}
8
+ {{ 'foo' starts
9
+ with 'f' ? 'OK' : 'KO' }}
10
+ {{ 'foo' starts with '' ? 'OK' : 'KO' }}
11
+ {{ '1' starts with true ? 'OK' : 'KO' }}
12
+ {{ '' starts with false ? 'OK' : 'KO' }}
13
+ {{ 'a' starts with false ? 'OK' : 'KO' }}
14
+ {{ false starts with '' ? 'OK' : 'KO' }}
15
+ --DATA--
16
+ return array()
17
+ --EXPECT--
18
+ OK
19
+ OK
20
+ OK
21
+ OK
22
+ OK
23
+ OK
24
+ KO
25
+ KO
26
+ KO
27
+ KO
library/twig/twig/test/Twig/Tests/Fixtures/expressions/strings.test ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ Twig supports string interpolation
3
+ --TEMPLATE--
4
+ {{ "foo #{"foo #{bar} baz"} baz" }}
5
+ {{ "foo #{bar}#{bar} baz" }}
6
+ --DATA--
7
+ return array('bar' => 'BAR');
8
+ --EXPECT--
9
+ foo foo BAR baz baz
10
+ foo BARBAR baz
library/twig/twig/test/Twig/Tests/Fixtures/expressions/ternary_operator.test ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ Twig supports the ternary operator
3
+ --TEMPLATE--
4
+ {{ 1 ? 'YES' : 'NO' }}
5
+ {{ 0 ? 'YES' : 'NO' }}
6
+ {{ 0 ? 'YES' : (1 ? 'YES1' : 'NO1') }}
7
+ {{ 0 ? 'YES' : (0 ? 'YES1' : 'NO1') }}
8
+ {{ 1 == 1 ? 'foo<br />':'' }}
9
+ {{ foo ~ (bar ? ('-' ~ bar) : '') }}
10
+ --DATA--
11
+ return array('foo' => 'foo', 'bar' => 'bar')
12
+ --EXPECT--
13
+ YES
14
+ NO
15
+ YES1
16
+ NO1
17
+ foo<br />
18
+ foo-bar
library/twig/twig/test/Twig/Tests/Fixtures/expressions/ternary_operator_noelse.test ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ Twig supports the ternary operator
3
+ --TEMPLATE--
4
+ {{ 1 ? 'YES' }}
5
+ {{ 0 ? 'YES' }}
6
+ --DATA--
7
+ return array()
8
+ --EXPECT--
9
+ YES
10
+
library/twig/twig/test/Twig/Tests/Fixtures/expressions/ternary_operator_nothen.test ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ Twig supports the ternary operator
3
+ --TEMPLATE--
4
+ {{ 'YES' ?: 'NO' }}
5
+ {{ 0 ?: 'NO' }}
6
+ --DATA--
7
+ return array()
8
+ --EXPECT--
9
+ YES
10
+ NO
library/twig/twig/test/Twig/Tests/Fixtures/expressions/two_word_operators_as_variables.test ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ Twig does not allow to use two-word named operators as variable names
3
+ --TEMPLATE--
4
+ {{ starts with }}
5
+ --DATA--
6
+ return array()
7
+ --EXCEPTION--
8
+ Twig_Error_Syntax: Unexpected token "operator" of value "starts with" in "index.twig" at line 2.
library/twig/twig/test/Twig/Tests/Fixtures/expressions/unary.test ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ Twig supports unary operators (not, -, +)
3
+ --TEMPLATE--
4
+ {{ not 1 }}/{{ not 0 }}
5
+ {{ +1 + 1 }}/{{ -1 - 1 }}
6
+ {{ not (false or true) }}
7
+ --DATA--
8
+ return array()
9
+ --EXPECT--
10
+ /1
11
+ 2/-2
12
+
library/twig/twig/test/Twig/Tests/Fixtures/expressions/unary_macro_arguments.test ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ Twig manages negative numbers as default parameters
3
+ --TEMPLATE--
4
+ {% import _self as macros %}
5
+ {{ macros.negative_number1() }}
6
+ {{ macros.negative_number2() }}
7
+ {{ macros.negative_number3() }}
8
+ {{ macros.positive_number1() }}
9
+ {{ macros.positive_number2() }}
10
+ {% macro negative_number1(nb=-1) %}{{ nb }}{% endmacro %}
11
+ {% macro negative_number2(nb = --1) %}{{ nb }}{% endmacro %}
12
+ {% macro negative_number3(nb = - 1) %}{{ nb }}{% endmacro %}
13
+ {% macro positive_number1(nb = +1) %}{{ nb }}{% endmacro %}
14
+ {% macro positive_number2(nb = ++1) %}{{ nb }}{% endmacro %}
15
+ --DATA--
16
+ return array()
17
+ --EXPECT--
18
+ -1
19
+ 1
20
+ -1
21
+ 1
22
+ 1
library/twig/twig/test/Twig/Tests/Fixtures/expressions/unary_precedence.test ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ Twig unary operators precedence
3
+ --TEMPLATE--
4
+ {{ -1 - 1 }}
5
+ {{ -1 - -1 }}
6
+ {{ -1 * -1 }}
7
+ {{ 4 / -1 * 5 }}
8
+ --DATA--
9
+ return array()
10
+ --EXPECT--
11
+ -2
12
+ 0
13
+ 1
14
+ -20
library/twig/twig/test/Twig/Tests/Fixtures/filters/abs.test ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "abs" filter
3
+ --TEMPLATE--
4
+ {{ (-5.5)|abs }}
5
+ {{ (-5)|abs }}
6
+ {{ (-0)|abs }}
7
+ {{ 0|abs }}
8
+ {{ 5|abs }}
9
+ {{ 5.5|abs }}
10
+ {{ number1|abs }}
11
+ {{ number2|abs }}
12
+ {{ number3|abs }}
13
+ {{ number4|abs }}
14
+ {{ number5|abs }}
15
+ {{ number6|abs }}
16
+ --DATA--
17
+ return array('number1' => -5.5, 'number2' => -5, 'number3' => -0, 'number4' => 0, 'number5' => 5, 'number6' => 5.5)
18
+ --EXPECT--
19
+ 5.5
20
+ 5
21
+ 0
22
+ 0
23
+ 5
24
+ 5.5
25
+ 5.5
26
+ 5
27
+ 0
28
+ 0
29
+ 5
30
+ 5.5
library/twig/twig/test/Twig/Tests/Fixtures/filters/batch.test ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "batch" filter
3
+ --TEMPLATE--
4
+ {% for row in items|batch(3) %}
5
+ <div class=row>
6
+ {% for column in row %}
7
+ <div class=item>{{ column }}</div>
8
+ {% endfor %}
9
+ </div>
10
+ {% endfor %}
11
+ --DATA--
12
+ return array('items' => array('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'))
13
+ --EXPECT--
14
+ <div class=row>
15
+ <div class=item>a</div>
16
+ <div class=item>b</div>
17
+ <div class=item>c</div>
18
+ </div>
19
+ <div class=row>
20
+ <div class=item>d</div>
21
+ <div class=item>e</div>
22
+ <div class=item>f</div>
23
+ </div>
24
+ <div class=row>
25
+ <div class=item>g</div>
26
+ <div class=item>h</div>
27
+ <div class=item>i</div>
28
+ </div>
29
+ <div class=row>
30
+ <div class=item>j</div>
31
+ </div>
library/twig/twig/test/Twig/Tests/Fixtures/filters/batch_float.test ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "batch" filter
3
+ --TEMPLATE--
4
+ {% for row in items|batch(3.1) %}
5
+ <div class=row>
6
+ {% for column in row %}
7
+ <div class=item>{{ column }}</div>
8
+ {% endfor %}
9
+ </div>
10
+ {% endfor %}
11
+ --DATA--
12
+ return array('items' => array('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'))
13
+ --EXPECT--
14
+ <div class=row>
15
+ <div class=item>a</div>
16
+ <div class=item>b</div>
17
+ <div class=item>c</div>
18
+ <div class=item>d</div>
19
+ </div>
20
+ <div class=row>
21
+ <div class=item>e</div>
22
+ <div class=item>f</div>
23
+ <div class=item>g</div>
24
+ <div class=item>h</div>
25
+ </div>
26
+ <div class=row>
27
+ <div class=item>i</div>
28
+ <div class=item>j</div>
29
+ </div>
library/twig/twig/test/Twig/Tests/Fixtures/filters/batch_with_empty_fill.test ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "batch" filter
3
+ --TEMPLATE--
4
+ <table>
5
+ {% for row in items|batch(3, '') %}
6
+ <tr>
7
+ {% for column in row %}
8
+ <td>{{ column }}</td>
9
+ {% endfor %}
10
+ </tr>
11
+ {% endfor %}
12
+ </table>
13
+ --DATA--
14
+ return array('items' => array('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'))
15
+ --EXPECT--
16
+ <table>
17
+ <tr>
18
+ <td>a</td>
19
+ <td>b</td>
20
+ <td>c</td>
21
+ </tr>
22
+ <tr>
23
+ <td>d</td>
24
+ <td>e</td>
25
+ <td>f</td>
26
+ </tr>
27
+ <tr>
28
+ <td>g</td>
29
+ <td>h</td>
30
+ <td>i</td>
31
+ </tr>
32
+ <tr>
33
+ <td>j</td>
34
+ <td></td>
35
+ <td></td>
36
+ </tr>
37
+ </table>
library/twig/twig/test/Twig/Tests/Fixtures/filters/batch_with_exact_elements.test ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "batch" filter
3
+ --TEMPLATE--
4
+ {% for row in items|batch(3, 'fill') %}
5
+ <div class=row>
6
+ {% for column in row %}
7
+ <div class=item>{{ column }}</div>
8
+ {% endfor %}
9
+ </div>
10
+ {% endfor %}
11
+ --DATA--
12
+ return array('items' => array('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l'))
13
+ --EXPECT--
14
+ <div class=row>
15
+ <div class=item>a</div>
16
+ <div class=item>b</div>
17
+ <div class=item>c</div>
18
+ </div>
19
+ <div class=row>
20
+ <div class=item>d</div>
21
+ <div class=item>e</div>
22
+ <div class=item>f</div>
23
+ </div>
24
+ <div class=row>
25
+ <div class=item>g</div>
26
+ <div class=item>h</div>
27
+ <div class=item>i</div>
28
+ </div>
29
+ <div class=row>
30
+ <div class=item>j</div>
31
+ <div class=item>k</div>
32
+ <div class=item>l</div>
33
+ </div>
library/twig/twig/test/Twig/Tests/Fixtures/filters/batch_with_fill.test ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "batch" filter
3
+ --TEMPLATE--
4
+ <table>
5
+ {% for row in items|batch(3, 'fill') %}
6
+ <tr>
7
+ {% for column in row %}
8
+ <td>{{ column }}</td>
9
+ {% endfor %}
10
+ </tr>
11
+ {% endfor %}
12
+ </table>
13
+ --DATA--
14
+ return array('items' => array('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'))
15
+ --EXPECT--
16
+ <table>
17
+ <tr>
18
+ <td>a</td>
19
+ <td>b</td>
20
+ <td>c</td>
21
+ </tr>
22
+ <tr>
23
+ <td>d</td>
24
+ <td>e</td>
25
+ <td>f</td>
26
+ </tr>
27
+ <tr>
28
+ <td>g</td>
29
+ <td>h</td>
30
+ <td>i</td>
31
+ </tr>
32
+ <tr>
33
+ <td>j</td>
34
+ <td>fill</td>
35
+ <td>fill</td>
36
+ </tr>
37
+ </table>
library/twig/twig/test/Twig/Tests/Fixtures/filters/batch_with_keys.test ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "batch" filter preserves array keys
3
+ --TEMPLATE--
4
+ {{ {'foo': 'bar', 'key': 'value'}|batch(4)|first|keys|join(',') }}
5
+ {{ {'foo': 'bar', 'key': 'value'}|batch(4, 'fill')|first|keys|join(',') }}
6
+ --DATA--
7
+ return array()
8
+ --EXPECT--
9
+ foo,key
10
+ foo,key,0,1
library/twig/twig/test/Twig/Tests/Fixtures/filters/batch_with_zero_elements.test ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "batch" filter with zero elements
3
+ --TEMPLATE--
4
+ {{ []|batch(3)|length }}
5
+ {{ []|batch(3, 'fill')|length }}
6
+ --DATA--
7
+ return array()
8
+ --EXPECT--
9
+ 0
10
+ 0
library/twig/twig/test/Twig/Tests/Fixtures/filters/convert_encoding.test ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "convert_encoding" filter
3
+ --CONDITION--
4
+ function_exists('iconv') || function_exists('mb_convert_encoding')
5
+ --TEMPLATE--
6
+ {{ "愛していますか?"|convert_encoding('ISO-2022-JP', 'UTF-8')|convert_encoding('UTF-8', 'ISO-2022-JP') }}
7
+ --DATA--
8
+ return array()
9
+ --EXPECT--
10
+ 愛していますか?
library/twig/twig/test/Twig/Tests/Fixtures/filters/date.test ADDED
@@ -0,0 +1,90 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "date" filter
3
+ --TEMPLATE--
4
+ {{ date1|date }}
5
+ {{ date1|date('d/m/Y') }}
6
+ {{ date1|date('d/m/Y H:i:s', 'Asia/Hong_Kong') }}
7
+ {{ date1|date('d/m/Y H:i:s P', 'Asia/Hong_Kong') }}
8
+ {{ date1|date('d/m/Y H:i:s P', 'America/Chicago') }}
9
+ {{ date1|date('e') }}
10
+ {{ date1|date('d/m/Y H:i:s') }}
11
+
12
+ {{ date2|date }}
13
+ {{ date2|date('d/m/Y') }}
14
+ {{ date2|date('d/m/Y H:i:s', 'Asia/Hong_Kong') }}
15
+ {{ date2|date('d/m/Y H:i:s', timezone1) }}
16
+ {{ date2|date('d/m/Y H:i:s') }}
17
+
18
+ {{ date3|date }}
19
+ {{ date3|date('d/m/Y') }}
20
+
21
+ {{ date4|date }}
22
+ {{ date4|date('d/m/Y') }}
23
+
24
+ {{ date5|date }}
25
+ {{ date5|date('d/m/Y') }}
26
+
27
+ {{ date6|date('d/m/Y H:i:s P', 'Europe/Paris') }}
28
+ {{ date6|date('d/m/Y H:i:s P', 'Asia/Hong_Kong') }}
29
+ {{ date6|date('d/m/Y H:i:s P', false) }}
30
+ {{ date6|date('e', 'Europe/Paris') }}
31
+ {{ date6|date('e', false) }}
32
+
33
+ {{ date7|date }}
34
+ {{ date7|date(timezone='Europe/Paris') }}
35
+ {{ date7|date(timezone='Asia/Hong_Kong') }}
36
+ {{ date7|date(timezone=false) }}
37
+ {{ date7|date(timezone='Indian/Mauritius') }}
38
+
39
+ {{ '2010-01-28 15:00:00'|date(timezone="Europe/Paris") }}
40
+ {{ '2010-01-28 15:00:00'|date(timezone="Asia/Hong_Kong") }}
41
+ --DATA--
42
+ date_default_timezone_set('Europe/Paris');
43
+ return array(
44
+ 'date1' => mktime(13, 45, 0, 10, 4, 2010),
45
+ 'date2' => new DateTime('2010-10-04 13:45'),
46
+ 'date3' => '2010-10-04 13:45',
47
+ 'date4' => 1286199900, // DateTime::createFromFormat('Y-m-d H:i', '2010-10-04 13:45', new DateTimeZone('UTC'))->getTimestamp() -- A unixtimestamp is always GMT
48
+ 'date5' => -189291360, // DateTime::createFromFormat('Y-m-d H:i', '1964-01-02 03:04', new DateTimeZone('UTC'))->getTimestamp(),
49
+ 'date6' => new DateTime('2010-10-04 13:45', new DateTimeZone('America/New_York')),
50
+ 'date7' => '2010-01-28T15:00:00+04:00',
51
+ 'timezone1' => new DateTimeZone('America/New_York'),
52
+ )
53
+ --EXPECT--
54
+ October 4, 2010 13:45
55
+ 04/10/2010
56
+ 04/10/2010 19:45:00
57
+ 04/10/2010 19:45:00 +08:00
58
+ 04/10/2010 06:45:00 -05:00
59
+ Europe/Paris
60
+ 04/10/2010 13:45:00
61
+
62
+ October 4, 2010 13:45
63
+ 04/10/2010
64
+ 04/10/2010 19:45:00
65
+ 04/10/2010 07:45:00
66
+ 04/10/2010 13:45:00
67
+
68
+ October 4, 2010 13:45
69
+ 04/10/2010
70
+
71
+ October 4, 2010 15:45
72
+ 04/10/2010
73
+
74
+ January 2, 1964 04:04
75
+ 02/01/1964
76
+
77
+ 04/10/2010 19:45:00 +02:00
78
+ 05/10/2010 01:45:00 +08:00
79
+ 04/10/2010 13:45:00 -04:00
80
+ Europe/Paris
81
+ America/New_York
82
+
83
+ January 28, 2010 12:00
84
+ January 28, 2010 12:00
85
+ January 28, 2010 19:00
86
+ January 28, 2010 15:00
87
+ January 28, 2010 15:00
88
+
89
+ January 28, 2010 15:00
90
+ January 28, 2010 22:00
library/twig/twig/test/Twig/Tests/Fixtures/filters/date_default_format.test ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "date" filter
3
+ --TEMPLATE--
4
+ {{ date1|date }}
5
+ {{ date1|date('d/m/Y') }}
6
+ --DATA--
7
+ date_default_timezone_set('UTC');
8
+ $twig->getExtension('Twig_Extension_Core')->setDateFormat('Y-m-d', '%d days %h hours');
9
+ return array(
10
+ 'date1' => mktime(13, 45, 0, 10, 4, 2010),
11
+ )
12
+ --EXPECT--
13
+ 2010-10-04
14
+ 04/10/2010
library/twig/twig/test/Twig/Tests/Fixtures/filters/date_default_format_interval.test ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "date" filter (interval support as of PHP 5.3)
3
+ --CONDITION--
4
+ version_compare(phpversion(), '5.3.0', '>=')
5
+ --TEMPLATE--
6
+ {{ date2|date }}
7
+ {{ date2|date('%d days') }}
8
+ --DATA--
9
+ date_default_timezone_set('UTC');
10
+ $twig->getExtension('Twig_Extension_Core')->setDateFormat('Y-m-d', '%d days %h hours');
11
+ return array(
12
+ 'date2' => new DateInterval('P2D'),
13
+ )
14
+ --EXPECT--
15
+ 2 days 0 hours
16
+ 2 days
library/twig/twig/test/Twig/Tests/Fixtures/filters/date_immutable.test ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "date" filter
3
+ --CONDITION--
4
+ version_compare(phpversion(), '5.5.0', '>=')
5
+ --TEMPLATE--
6
+ {{ date1|date }}
7
+ {{ date1|date('d/m/Y') }}
8
+ {{ date1|date('d/m/Y H:i:s', 'Asia/Hong_Kong') }}
9
+ {{ date1|date('d/m/Y H:i:s', timezone1) }}
10
+ {{ date1|date('d/m/Y H:i:s') }}
11
+ {{ date1|date_modify('+1 hour')|date('d/m/Y H:i:s') }}
12
+
13
+ {{ date2|date('d/m/Y H:i:s P', 'Europe/Paris') }}
14
+ {{ date2|date('d/m/Y H:i:s P', 'Asia/Hong_Kong') }}
15
+ {{ date2|date('d/m/Y H:i:s P', false) }}
16
+ {{ date2|date('e', 'Europe/Paris') }}
17
+ {{ date2|date('e', false) }}
18
+ --DATA--
19
+ date_default_timezone_set('Europe/Paris');
20
+ return array(
21
+ 'date1' => new DateTimeImmutable('2010-10-04 13:45'),
22
+ 'date2' => new DateTimeImmutable('2010-10-04 13:45', new DateTimeZone('America/New_York')),
23
+ 'timezone1' => new DateTimeZone('America/New_York'),
24
+ )
25
+ --EXPECT--
26
+ October 4, 2010 13:45
27
+ 04/10/2010
28
+ 04/10/2010 19:45:00
29
+ 04/10/2010 07:45:00
30
+ 04/10/2010 13:45:00
31
+ 04/10/2010 14:45:00
32
+
33
+ 04/10/2010 19:45:00 +02:00
34
+ 05/10/2010 01:45:00 +08:00
35
+ 04/10/2010 13:45:00 -04:00
36
+ Europe/Paris
37
+ America/New_York
library/twig/twig/test/Twig/Tests/Fixtures/filters/date_interval.test ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "date" filter (interval support as of PHP 5.3)
3
+ --CONDITION--
4
+ version_compare(phpversion(), '5.3.0', '>=')
5
+ --TEMPLATE--
6
+ {{ date1|date }}
7
+ {{ date1|date('%d days %h hours') }}
8
+ {{ date1|date('%d days %h hours', timezone1) }}
9
+ --DATA--
10
+ date_default_timezone_set('UTC');
11
+ return array(
12
+ 'date1' => new DateInterval('P2D'),
13
+ // This should have no effect on DateInterval formatting
14
+ 'timezone1' => new DateTimeZone('America/New_York'),
15
+ )
16
+ --EXPECT--
17
+ 2 days
18
+ 2 days 0 hours
19
+ 2 days 0 hours
library/twig/twig/test/Twig/Tests/Fixtures/filters/date_modify.test ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "date_modify" filter
3
+ --TEMPLATE--
4
+ {{ date1|date_modify('-1day')|date('Y-m-d H:i:s') }}
5
+ {{ date2|date_modify('-1day')|date('Y-m-d H:i:s') }}
6
+ --DATA--
7
+ date_default_timezone_set('UTC');
8
+ return array(
9
+ 'date1' => '2010-10-04 13:45',
10
+ 'date2' => new DateTime('2010-10-04 13:45'),
11
+ )
12
+ --EXPECT--
13
+ 2010-10-03 13:45:00
14
+ 2010-10-03 13:45:00
library/twig/twig/test/Twig/Tests/Fixtures/filters/date_namedargs.test ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "date" filter
3
+ --TEMPLATE--
4
+ {{ date|date(format='d/m/Y H:i:s P', timezone='America/Chicago') }}
5
+ {{ date|date(timezone='America/Chicago', format='d/m/Y H:i:s P') }}
6
+ {{ date|date('d/m/Y H:i:s P', timezone='America/Chicago') }}
7
+ --DATA--
8
+ date_default_timezone_set('UTC');
9
+ return array('date' => mktime(13, 45, 0, 10, 4, 2010))
10
+ --EXPECT--
11
+ 04/10/2010 08:45:00 -05:00
12
+ 04/10/2010 08:45:00 -05:00
13
+ 04/10/2010 08:45:00 -05:00
library/twig/twig/test/Twig/Tests/Fixtures/filters/default.test ADDED
@@ -0,0 +1,150 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "default" filter
3
+ --TEMPLATE--
4
+ Variable:
5
+ {{ definedVar |default('default') is same as('default') ? 'ko' : 'ok' }}
6
+ {{ zeroVar |default('default') is same as('default') ? 'ko' : 'ok' }}
7
+ {{ emptyVar |default('default') is same as('default') ? 'ok' : 'ko' }}
8
+ {{ nullVar |default('default') is same as('default') ? 'ok' : 'ko' }}
9
+ {{ undefinedVar |default('default') is same as('default') ? 'ok' : 'ko' }}
10
+ Array access:
11
+ {{ nested.definedVar |default('default') is same as('default') ? 'ko' : 'ok' }}
12
+ {{ nested['definedVar'] |default('default') is same as('default') ? 'ko' : 'ok' }}
13
+ {{ nested.zeroVar |default('default') is same as('default') ? 'ko' : 'ok' }}
14
+ {{ nested.emptyVar |default('default') is same as('default') ? 'ok' : 'ko' }}
15
+ {{ nested.nullVar |default('default') is same as('default') ? 'ok' : 'ko' }}
16
+ {{ nested.undefinedVar |default('default') is same as('default') ? 'ok' : 'ko' }}
17
+ {{ nested['undefinedVar'] |default('default') is same as('default') ? 'ok' : 'ko' }}
18
+ {{ undefinedVar.foo |default('default') is same as('default') ? 'ok' : 'ko' }}
19
+ Plain values:
20
+ {{ 'defined' |default('default') is same as('default') ? 'ko' : 'ok' }}
21
+ {{ 0 |default('default') is same as('default') ? 'ko' : 'ok' }}
22
+ {{ '' |default('default') is same as('default') ? 'ok' : 'ko' }}
23
+ {{ null |default('default') is same as('default') ? 'ok' : 'ko' }}
24
+ Precedence:
25
+ {{ 'o' ~ nullVar |default('k') }}
26
+ {{ 'o' ~ nested.nullVar |default('k') }}
27
+ Object methods:
28
+ {{ object.foo |default('default') is same as('default') ? 'ko' : 'ok' }}
29
+ {{ object.undefinedMethod |default('default') is same as('default') ? 'ok' : 'ko' }}
30
+ {{ object.getFoo() |default('default') is same as('default') ? 'ko' : 'ok' }}
31
+ {{ object.getFoo('a') |default('default') is same as('default') ? 'ko' : 'ok' }}
32
+ {{ object.undefinedMethod() |default('default') is same as('default') ? 'ok' : 'ko' }}
33
+ {{ object.undefinedMethod('a') |default('default') is same as('default') ? 'ok' : 'ko' }}
34
+ Deep nested:
35
+ {{ nested.undefinedVar.foo.bar |default('default') is same as('default') ? 'ok' : 'ko' }}
36
+ {{ nested.definedArray.0 |default('default') is same as('default') ? 'ko' : 'ok' }}
37
+ {{ nested['definedArray'][0] |default('default') is same as('default') ? 'ko' : 'ok' }}
38
+ {{ object.self.foo |default('default') is same as('default') ? 'ko' : 'ok' }}
39
+ {{ object.self.undefinedMethod |default('default') is same as('default') ? 'ok' : 'ko' }}
40
+ {{ object.undefinedMethod.self |default('default') is same as('default') ? 'ok' : 'ko' }}
41
+ --DATA--
42
+ return array(
43
+ 'definedVar' => 'defined',
44
+ 'zeroVar' => 0,
45
+ 'emptyVar' => '',
46
+ 'nullVar' => null,
47
+ 'nested' => array(
48
+ 'definedVar' => 'defined',
49
+ 'zeroVar' => 0,
50
+ 'emptyVar' => '',
51
+ 'nullVar' => null,
52
+ 'definedArray' => array(0),
53
+ ),
54
+ 'object' => new TwigTestFoo(),
55
+ )
56
+ --CONFIG--
57
+ return array('strict_variables' => false)
58
+ --EXPECT--
59
+ Variable:
60
+ ok
61
+ ok
62
+ ok
63
+ ok
64
+ ok
65
+ Array access:
66
+ ok
67
+ ok
68
+ ok
69
+ ok
70
+ ok
71
+ ok
72
+ ok
73
+ ok
74
+ Plain values:
75
+ ok
76
+ ok
77
+ ok
78
+ ok
79
+ Precedence:
80
+ ok
81
+ ok
82
+ Object methods:
83
+ ok
84
+ ok
85
+ ok
86
+ ok
87
+ ok
88
+ ok
89
+ Deep nested:
90
+ ok
91
+ ok
92
+ ok
93
+ ok
94
+ ok
95
+ ok
96
+ --DATA--
97
+ return array(
98
+ 'definedVar' => 'defined',
99
+ 'zeroVar' => 0,
100
+ 'emptyVar' => '',
101
+ 'nullVar' => null,
102
+ 'nested' => array(
103
+ 'definedVar' => 'defined',
104
+ 'zeroVar' => 0,
105
+ 'emptyVar' => '',
106
+ 'nullVar' => null,
107
+ 'definedArray' => array(0),
108
+ ),
109
+ 'object' => new TwigTestFoo(),
110
+ )
111
+ --CONFIG--
112
+ return array('strict_variables' => true)
113
+ --EXPECT--
114
+ Variable:
115
+ ok
116
+ ok
117
+ ok
118
+ ok
119
+ ok
120
+ Array access:
121
+ ok
122
+ ok
123
+ ok
124
+ ok
125
+ ok
126
+ ok
127
+ ok
128
+ ok
129
+ Plain values:
130
+ ok
131
+ ok
132
+ ok
133
+ ok
134
+ Precedence:
135
+ ok
136
+ ok
137
+ Object methods:
138
+ ok
139
+ ok
140
+ ok
141
+ ok
142
+ ok
143
+ ok
144
+ Deep nested:
145
+ ok
146
+ ok
147
+ ok
148
+ ok
149
+ ok
150
+ ok
library/twig/twig/test/Twig/Tests/Fixtures/filters/dynamic_filter.test ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ dynamic filter
3
+ --TEMPLATE--
4
+ {{ 'bar'|foo_path }}
5
+ {{ 'bar'|a_foo_b_bar }}
6
+ --DATA--
7
+ return array()
8
+ --EXPECT--
9
+ foo/bar
10
+ a/b/bar
library/twig/twig/test/Twig/Tests/Fixtures/filters/escape.test ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "escape" filter
3
+ --TEMPLATE--
4
+ {{ "foo <br />"|e }}
5
+ --DATA--
6
+ return array()
7
+ --EXPECT--
8
+ foo &lt;br /&gt;
library/twig/twig/test/Twig/Tests/Fixtures/filters/escape_html_attr.test ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "escape" filter does not escape with the html strategy when using the html_attr strategy
3
+ --TEMPLATE--
4
+ {{ '<br />'|escape('html_attr') }}
5
+ --DATA--
6
+ return array()
7
+ --EXPECT--
8
+ &lt;br&#x20;&#x2F;&gt;
library/twig/twig/test/Twig/Tests/Fixtures/filters/escape_non_supported_charset.test ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "escape" filter
3
+ --TEMPLATE--
4
+ {{ "愛していますか? <br />"|e }}
5
+ --DATA--
6
+ return array()
7
+ --EXPECT--
8
+ 愛していますか? &lt;br /&gt;
library/twig/twig/test/Twig/Tests/Fixtures/filters/first.test ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "first" filter
3
+ --TEMPLATE--
4
+ {{ [1, 2, 3, 4]|first }}
5
+ {{ {a: 1, b: 2, c: 3, d: 4}|first }}
6
+ {{ '1234'|first }}
7
+ {{ arr|first }}
8
+ {{ 'Ä€é'|first }}
9
+ {{ ''|first }}
10
+ --DATA--
11
+ return array('arr' => new ArrayObject(array(1, 2, 3, 4)))
12
+ --EXPECT--
13
+ 1
14
+ 1
15
+ 1
16
+ 1
17
+ Ä
library/twig/twig/test/Twig/Tests/Fixtures/filters/force_escape.test ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "escape" filter
3
+ --TEMPLATE--
4
+ {% set foo %}
5
+ foo<br />
6
+ {% endset %}
7
+
8
+ {{ foo|e('html') -}}
9
+ {{ foo|e('js') }}
10
+ {% autoescape true %}
11
+ {{ foo }}
12
+ {% endautoescape %}
13
+ --DATA--
14
+ return array()
15
+ --EXPECT--
16
+ foo&lt;br /&gt;
17
+ \x20\x20\x20\x20foo\x3Cbr\x20\x2F\x3E\x0A
18
+ foo<br />
library/twig/twig/test/Twig/Tests/Fixtures/filters/format.test ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "format" filter
3
+ --TEMPLATE--
4
+ {{ string|format(foo, 3) }}
5
+ --DATA--
6
+ return array('string' => '%s/%d', 'foo' => 'bar')
7
+ --EXPECT--
8
+ bar/3
library/twig/twig/test/Twig/Tests/Fixtures/filters/join.test ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "join" filter
3
+ --TEMPLATE--
4
+ {{ ["foo", "bar"]|join(', ') }}
5
+ {{ foo|join(', ') }}
6
+ {{ bar|join(', ') }}
7
+ --DATA--
8
+ return array('foo' => new TwigTestFoo(), 'bar' => new ArrayObject(array(3, 4)))
9
+ --EXPECT--
10
+ foo, bar
11
+ 1, 2
12
+ 3, 4
library/twig/twig/test/Twig/Tests/Fixtures/filters/json_encode.test ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "json_encode" filter
3
+ --TEMPLATE--
4
+ {{ "foo"|json_encode|raw }}
5
+ {{ foo|json_encode|raw }}
6
+ {{ [foo, "foo"]|json_encode|raw }}
7
+ --DATA--
8
+ return array('foo' => new Twig_Markup('foo', 'UTF-8'))
9
+ --EXPECT--
10
+ "foo"
11
+ "foo"
12
+ ["foo","foo"]
library/twig/twig/test/Twig/Tests/Fixtures/filters/last.test ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "last" filter
3
+ --TEMPLATE--
4
+ {{ [1, 2, 3, 4]|last }}
5
+ {{ {a: 1, b: 2, c: 3, d: 4}|last }}
6
+ {{ '1234'|last }}
7
+ {{ arr|last }}
8
+ {{ 'Ä€é'|last }}
9
+ {{ ''|last }}
10
+ --DATA--
11
+ return array('arr' => new ArrayObject(array(1, 2, 3, 4)))
12
+ --EXPECT--
13
+ 4
14
+ 4
15
+ 4
16
+ 4
17
+ é
library/twig/twig/test/Twig/Tests/Fixtures/filters/length.test ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "length" filter
3
+ --TEMPLATE--
4
+ {{ array|length }}
5
+ {{ string|length }}
6
+ {{ number|length }}
7
+ {{ markup|length }}
8
+ --DATA--
9
+ return array('array' => array(1, 4), 'string' => 'foo', 'number' => 1000, 'markup' => new Twig_Markup('foo', 'UTF-8'))
10
+ --EXPECT--
11
+ 2
12
+ 3
13
+ 4
14
+ 3
library/twig/twig/test/Twig/Tests/Fixtures/filters/length_utf8.test ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "length" filter
3
+ --CONDITION--
4
+ function_exists('mb_get_info')
5
+ --TEMPLATE--
6
+ {{ string|length }}
7
+ {{ markup|length }}
8
+ --DATA--
9
+ return array('string' => 'été', 'markup' => new Twig_Markup('foo', 'UTF-8'))
10
+ --EXPECT--
11
+ 3
12
+ 3
library/twig/twig/test/Twig/Tests/Fixtures/filters/merge.test ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "merge" filter
3
+ --TEMPLATE--
4
+ {{ items|merge({'bar': 'foo'})|join }}
5
+ {{ items|merge({'bar': 'foo'})|keys|join }}
6
+ {{ {'bar': 'foo'}|merge(items)|join }}
7
+ {{ {'bar': 'foo'}|merge(items)|keys|join }}
8
+ {{ numerics|merge([4, 5, 6])|join }}
9
+ {{ traversable.a|merge(traversable.b)|join }}
10
+ --DATA--
11
+ return array('items' => array('foo' => 'bar'), 'numerics' => array(1, 2, 3), 'traversable' => array('a' => new ArrayObject(array(0 => 1, 1 => 2, 2 => 3)), 'b' => new ArrayObject(array('a' => 'b'))))
12
+ --EXPECT--
13
+ barfoo
14
+ foobar
15
+ foobar
16
+ barfoo
17
+ 123456
18
+ 123b
library/twig/twig/test/Twig/Tests/Fixtures/filters/nl2br.test ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "nl2br" filter
3
+ --TEMPLATE--
4
+ {{ "I like Twig.\nYou will like it too.\n\nEverybody like it!"|nl2br }}
5
+ {{ text|nl2br }}
6
+ --DATA--
7
+ return array('text' => "If you have some <strong>HTML</strong>\nit will be escaped.")
8
+ --EXPECT--
9
+ I like Twig.<br />
10
+ You will like it too.<br />
11
+ <br />
12
+ Everybody like it!
13
+ If you have some &lt;strong&gt;HTML&lt;/strong&gt;<br />
14
+ it will be escaped.
library/twig/twig/test/Twig/Tests/Fixtures/filters/number_format.test ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "number_format" filter
3
+ --TEMPLATE--
4
+ {{ 20|number_format }}
5
+ {{ 20.25|number_format }}
6
+ {{ 20.25|number_format(2) }}
7
+ {{ 20.25|number_format(2, ',') }}
8
+ {{ 1020.25|number_format(2, ',') }}
9
+ {{ 1020.25|number_format(2, ',', '.') }}
10
+ --DATA--
11
+ return array();
12
+ --EXPECT--
13
+ 20
14
+ 20
15
+ 20.25
16
+ 20,25
17
+ 1,020,25
18
+ 1.020,25
library/twig/twig/test/Twig/Tests/Fixtures/filters/number_format_default.test ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "number_format" filter with defaults.
3
+ --TEMPLATE--
4
+ {{ 20|number_format }}
5
+ {{ 20.25|number_format }}
6
+ {{ 20.25|number_format(1) }}
7
+ {{ 20.25|number_format(2, ',') }}
8
+ {{ 1020.25|number_format }}
9
+ {{ 1020.25|number_format(2, ',') }}
10
+ {{ 1020.25|number_format(2, ',', '.') }}
11
+ --DATA--
12
+ $twig->getExtension('Twig_Extension_Core')->setNumberFormat(2, '!', '=');
13
+ return array();
14
+ --EXPECT--
15
+ 20!00
16
+ 20!25
17
+ 20!3
18
+ 20,25
19
+ 1=020!25
20
+ 1=020,25
21
+ 1.020,25
library/twig/twig/test/Twig/Tests/Fixtures/filters/replace.test ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "replace" filter
3
+ --TEMPLATE--
4
+ {{ "I liké %this% and %that%."|replace({'%this%': "foo", '%that%': "bar"}) }}
5
+ {{ 'I like single replace operation only %that%'|replace({'%that%' : '%that%1'}) }}
6
+ {{ 'I like %this% and %that%.'|replace(traversable) }}
7
+ --DATA--
8
+ return array('traversable' => new ArrayObject(array('%this%' => 'foo', '%that%' => 'bar')))
9
+ --EXPECT--
10
+ I liké foo and bar.
11
+ I like single replace operation only %that%1
12
+ I like foo and bar.
library/twig/twig/test/Twig/Tests/Fixtures/filters/replace_invalid_arg.test ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ Exception for invalid argument type in replace call
3
+ --TEMPLATE--
4
+ {{ 'test %foo%'|replace(stdClass) }}
5
+ --DATA--
6
+ return array('stdClass' => new stdClass())
7
+ --EXCEPTION--
8
+ Twig_Error_Runtime: The "replace" filter expects an array or "Traversable" as replace values, got "stdClass" in "index.twig" at line 2.
library/twig/twig/test/Twig/Tests/Fixtures/filters/reverse.test ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "reverse" filter
3
+ --TEMPLATE--
4
+ {{ [1, 2, 3, 4]|reverse|join('') }}
5
+ {{ '1234évènement'|reverse }}
6
+ {{ arr|reverse|join('') }}
7
+ {{ {'a': 'c', 'b': 'a'}|reverse()|join(',') }}
8
+ {{ {'a': 'c', 'b': 'a'}|reverse(preserveKeys=true)|join(glue=',') }}
9
+ {{ {'a': 'c', 'b': 'a'}|reverse(preserve_keys=true)|join(glue=',') }}
10
+ --DATA--
11
+ return array('arr' => new ArrayObject(array(1, 2, 3, 4)))
12
+ --EXPECT--
13
+ 4321
14
+ tnemenèvé4321
15
+ 4321
16
+ a,c
17
+ a,c
18
+ a,c
library/twig/twig/test/Twig/Tests/Fixtures/filters/round.test ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "round" filter
3
+ --TEMPLATE--
4
+ {{ 2.7|round }}
5
+ {{ 2.1|round }}
6
+ {{ 2.1234|round(3, 'floor') }}
7
+ {{ 2.1|round(0, 'ceil') }}
8
+
9
+ {{ 21.3|round(-1)}}
10
+ {{ 21.3|round(-1, 'ceil')}}
11
+ {{ 21.3|round(-1, 'floor')}}
12
+ --DATA--
13
+ return array()
14
+ --EXPECT--
15
+ 3
16
+ 2
17
+ 2.123
18
+ 3
19
+
20
+ 20
21
+ 30
22
+ 20
library/twig/twig/test/Twig/Tests/Fixtures/filters/slice.test ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "slice" filter
3
+ --TEMPLATE--
4
+ {{ [1, 2, 3, 4][1:2]|join('') }}
5
+ {{ {a: 1, b: 2, c: 3, d: 4}[1:2]|join('') }}
6
+ {{ [1, 2, 3, 4][start:length]|join('') }}
7
+ {{ [1, 2, 3, 4]|slice(1, 2)|join('') }}
8
+ {{ [1, 2, 3, 4]|slice(1, 2)|keys|join('') }}
9
+ {{ [1, 2, 3, 4]|slice(1, 2, true)|keys|join('') }}
10
+ {{ {a: 1, b: 2, c: 3, d: 4}|slice(1, 2)|join('') }}
11
+ {{ {a: 1, b: 2, c: 3, d: 4}|slice(1, 2)|keys|join('') }}
12
+ {{ '1234'|slice(1, 2) }}
13
+ {{ '1234'[1:2] }}
14
+ {{ arr|slice(1, 2)|join('') }}
15
+ {{ arr[1:2]|join('') }}
16
+ {{ arr[4:1]|join('') }}
17
+ {{ arr[3:2]|join('') }}
18
+
19
+ {{ [1, 2, 3, 4]|slice(1)|join('') }}
20
+ {{ [1, 2, 3, 4][1:]|join('') }}
21
+ {{ '1234'|slice(1) }}
22
+ {{ '1234'[1:] }}
23
+ {{ '1234'[:1] }}
24
+
25
+ {{ arr|slice(3)|join('') }}
26
+ {{ arr[2:]|join('') }}
27
+ {{ xml|slice(1)|join('')}}
28
+ --DATA--
29
+ return array('start' => 1, 'length' => 2, 'arr' => new ArrayObject(array(1, 2, 3, 4)), 'xml' => new SimpleXMLElement('<items><item>1</item><item>2</item></items>'))
30
+ --EXPECT--
31
+ 23
32
+ 23
33
+ 23
34
+ 23
35
+ 01
36
+ 12
37
+ 23
38
+ bc
39
+ 23
40
+ 23
41
+ 23
42
+ 23
43
+
44
+ 4
45
+
46
+ 234
47
+ 234
48
+ 234
49
+ 234
50
+ 1
51
+
52
+ 4
53
+ 34
54
+ 2
library/twig/twig/test/Twig/Tests/Fixtures/filters/sort.test ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "sort" filter
3
+ --TEMPLATE--
4
+ {{ array1|sort|join }}
5
+ {{ array2|sort|join }}
6
+ {{ traversable|sort|join }}
7
+ --DATA--
8
+ return array('array1' => array(4, 1), 'array2' => array('foo', 'bar'), 'traversable' => new ArrayObject(array(0 => 3, 1 => 2, 2 => 1)))
9
+ --EXPECT--
10
+ 14
11
+ barfoo
12
+ 123
library/twig/twig/test/Twig/Tests/Fixtures/filters/special_chars.test ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "§" custom filter
3
+ --TEMPLATE--
4
+ {{ 'foo'|§ }}
5
+ --DATA--
6
+ return array()
7
+ --EXPECT--
8
+ §foo§
library/twig/twig/test/Twig/Tests/Fixtures/filters/split.test ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "split" filter
3
+ --TEMPLATE--
4
+ {{ "one,two,three,four,five"|split(',')|join('-') }}
5
+ {{ foo|split(',')|join('-') }}
6
+ {{ foo|split(',', 3)|join('-') }}
7
+ {{ baz|split('')|join('-') }}
8
+ {{ baz|split('', 1)|join('-') }}
9
+ {{ baz|split('', 2)|join('-') }}
10
+ {{ foo|split(',', -2)|join('-') }}
11
+ --DATA--
12
+ return array('foo' => "one,two,three,four,five", 'baz' => '12345',)
13
+ --EXPECT--
14
+ one-two-three-four-five
15
+ one-two-three-four-five
16
+ one-two-three,four,five
17
+ 1-2-3-4-5
18
+ 1-2-3-4-5
19
+ 12-34-5
20
+ one-two-three
library/twig/twig/test/Twig/Tests/Fixtures/filters/split_utf8.test ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "split" filter
3
+ --CONDITION--
4
+ function_exists('mb_get_info')
5
+ --TEMPLATE--
6
+ {{ "é"|split('', 10)|join('-') }}
7
+ {{ foo|split(',')|join('-') }}
8
+ {{ foo|split(',', 1)|join('-') }}
9
+ {{ foo|split(',', 2)|join('-') }}
10
+ {{ foo|split(',', 3)|join('-') }}
11
+ {{ baz|split('')|join('-') }}
12
+ {{ baz|split('', 1)|join('-') }}
13
+ {{ baz|split('', 2)|join('-') }}
14
+ --DATA--
15
+ return array('foo' => 'Ä,é,Äほ', 'baz' => 'éÄßごa',)
16
+ --EXPECT--
17
+ é
18
+ Ä-é-Äほ
19
+ Ä,é,Äほ
20
+ Ä-é,Äほ
21
+ Ä-é-Äほ
22
+ é-Ä-ß-ご-a
23
+ é-Ä-ß-ご-a
24
+ éÄ-ßご-a
library/twig/twig/test/Twig/Tests/Fixtures/filters/static_calls.test ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ Filters as static method calls
3
+ --TEMPLATE--
4
+ {{ 'foo'|static_call_string }}
5
+ {{ 'foo'|static_call_array }}
6
+ --DATA--
7
+ return array('foo' => 'foo')
8
+ --EXPECT--
9
+ *foo*
10
+ *foo*
library/twig/twig/test/Twig/Tests/Fixtures/filters/trim.test ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "trim" filter
3
+ --TEMPLATE--
4
+ {{ " I like Twig. "|trim }}
5
+ {{ text|trim }}
6
+ {{ " foo/"|trim("/") }}
7
+ --DATA--
8
+ return array('text' => " If you have some <strong>HTML</strong> it will be escaped. ")
9
+ --EXPECT--
10
+ I like Twig.
11
+ If you have some &lt;strong&gt;HTML&lt;/strong&gt; it will be escaped.
12
+ foo
library/twig/twig/test/Twig/Tests/Fixtures/filters/urlencode.test ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "url_encode" filter
3
+ --CONDITION--
4
+ defined('PHP_QUERY_RFC3986')
5
+ --TEMPLATE--
6
+ {{ {foo: "bar", number: 3, "spéßi%l": "e%c0d@d", "spa ce": ""}|url_encode }}
7
+ {{ {foo: "bar", number: 3, "spéßi%l": "e%c0d@d", "spa ce": ""}|url_encode|raw }}
8
+ {{ {}|url_encode|default("default") }}
9
+ {{ 'spéßi%le%c0d@dspa ce'|url_encode }}
10
+ --DATA--
11
+ return array()
12
+ --EXPECT--
13
+ foo=bar&amp;number=3&amp;sp%C3%A9%C3%9Fi%25l=e%25c0d%40d&amp;spa%20ce=
14
+ foo=bar&number=3&sp%C3%A9%C3%9Fi%25l=e%25c0d%40d&spa%20ce=
15
+ default
16
+ sp%C3%A9%C3%9Fi%25le%25c0d%40dspa%20ce
library/twig/twig/test/Twig/Tests/Fixtures/filters/urlencode_deprecated.test ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "url_encode" filter for PHP < 5.4 and HHVM
3
+ --CONDITION--
4
+ defined('PHP_QUERY_RFC3986')
5
+ --TEMPLATE--
6
+ {{ {foo: "bar", number: 3, "spéßi%l": "e%c0d@d", "spa ce": ""}|url_encode }}
7
+ {{ {foo: "bar", number: 3, "spéßi%l": "e%c0d@d", "spa ce": ""}|url_encode|raw }}
8
+ {{ {}|url_encode|default("default") }}
9
+ {{ 'spéßi%le%c0d@dspa ce'|url_encode }}
10
+ --DATA--
11
+ return array()
12
+ --EXPECT--
13
+ foo=bar&amp;number=3&amp;sp%C3%A9%C3%9Fi%25l=e%25c0d%40d&amp;spa%20ce=
14
+ foo=bar&number=3&sp%C3%A9%C3%9Fi%25l=e%25c0d%40d&spa%20ce=
15
+ default
16
+ sp%C3%A9%C3%9Fi%25le%25c0d%40dspa%20ce
library/twig/twig/test/Twig/Tests/Fixtures/functions/attribute.test ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "attribute" function
3
+ --TEMPLATE--
4
+ {{ attribute(obj, method) }}
5
+ {{ attribute(array, item) }}
6
+ {{ attribute(obj, "bar", ["a", "b"]) }}
7
+ {{ attribute(obj, "bar", arguments) }}
8
+ {{ attribute(obj, method) is defined ? 'ok' : 'ko' }}
9
+ {{ attribute(obj, nonmethod) is defined ? 'ok' : 'ko' }}
10
+ --DATA--
11
+ return array('obj' => new TwigTestFoo(), 'method' => 'foo', 'array' => array('foo' => 'bar'), 'item' => 'foo', 'nonmethod' => 'xxx', 'arguments' => array('a', 'b'))
12
+ --EXPECT--
13
+ foo
14
+ bar
15
+ bar_a-b
16
+ bar_a-b
17
+ ok
18
+ ko
library/twig/twig/test/Twig/Tests/Fixtures/functions/block.test ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "block" function
3
+ --TEMPLATE--
4
+ {% extends 'base.twig' %}
5
+ {% block bar %}BAR{% endblock %}
6
+ --TEMPLATE(base.twig)--
7
+ {% block foo %}{{ block('bar') }}{% endblock %}
8
+ {% block bar %}BAR_BASE{% endblock %}
9
+ --DATA--
10
+ return array()
11
+ --EXPECT--
12
+ BARBAR
library/twig/twig/test/Twig/Tests/Fixtures/functions/block_with_template.test ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "block" function with a template argument
3
+ --TEMPLATE--
4
+ {{ block('foo', 'included.twig') }}
5
+ {{ block('foo', included_loaded) }}
6
+ {{ block('foo', included_loaded_internal) }}
7
+ {% set output = block('foo', 'included.twig') %}
8
+ {{ output }}
9
+ {% block foo %}NOT FOO{% endblock %}
10
+ --TEMPLATE(included.twig)--
11
+ {% block foo %}FOO{% endblock %}
12
+ --DATA--
13
+ return array(
14
+ 'included_loaded' => $twig->load('included.twig'),
15
+ 'included_loaded_internal' => $twig->loadTemplate('included.twig'),
16
+ )
17
+ --EXPECT--
18
+ FOO
19
+ FOO
20
+ FOO
21
+ FOO
22
+ NOT FOO
library/twig/twig/test/Twig/Tests/Fixtures/functions/block_without_name.test ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "block" function without arguments
3
+ --TEMPLATE--
4
+ {% extends 'base.twig' %}
5
+ {% block bar %}BAR{% endblock %}
6
+ --TEMPLATE(base.twig)--
7
+ {% block foo %}{{ block() }}{% endblock %}
8
+ {% block bar %}BAR_BASE{% endblock %}
9
+ --DATA--
10
+ return array()
11
+ --EXCEPTION--
12
+ Twig_Error_Syntax: The "block" function takes one argument (the block name) in "base.twig" at line 2.
library/twig/twig/test/Twig/Tests/Fixtures/functions/constant.test ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "constant" function
3
+ --TEMPLATE--
4
+ {{ constant('DATE_W3C') == expect ? 'true' : 'false' }}
5
+ {{ constant('ARRAY_AS_PROPS', object) }}
6
+ --DATA--
7
+ return array('expect' => DATE_W3C, 'object' => new ArrayObject(array('hi')));
8
+ --EXPECT--
9
+ true
10
+ 2
library/twig/twig/test/Twig/Tests/Fixtures/functions/cycle.test ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "cycle" function
3
+ --TEMPLATE--
4
+ {% for i in 0..6 %}
5
+ {{ cycle(array1, i) }}-{{ cycle(array2, i) }}
6
+ {% endfor %}
7
+ --DATA--
8
+ return array('array1' => array('odd', 'even'), 'array2' => array('apple', 'orange', 'citrus'))
9
+ --EXPECT--
10
+ odd-apple
11
+ even-orange
12
+ odd-citrus
13
+ even-apple
14
+ odd-orange
15
+ even-citrus
16
+ odd-apple
library/twig/twig/test/Twig/Tests/Fixtures/functions/date.test ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "date" function
3
+ --TEMPLATE--
4
+ {{ date().format('r') == date('now').format('r') ? 'OK' : 'KO' }}
5
+ {{ date(date1) == date('2010-10-04 13:45') ? 'OK' : 'KO' }}
6
+ {{ date(date2) == date('2010-10-04 13:45') ? 'OK' : 'KO' }}
7
+ {{ date(date3) == date('2010-10-04 13:45') ? 'OK' : 'KO' }}
8
+ {{ date(date4) == date('2010-10-04 13:45') ? 'OK' : 'KO' }}
9
+ {{ date(date5) == date('1964-01-02 03:04') ? 'OK' : 'KO' }}
10
+ --DATA--
11
+ date_default_timezone_set('UTC');
12
+ return array(
13
+ 'date1' => mktime(13, 45, 0, 10, 4, 2010),
14
+ 'date2' => new DateTime('2010-10-04 13:45'),
15
+ 'date3' => '2010-10-04 13:45',
16
+ 'date4' => 1286199900, // DateTime::createFromFormat('Y-m-d H:i', '2010-10-04 13:45', new DateTimeZone('UTC'))->getTimestamp() -- A unixtimestamp is always GMT
17
+ 'date5' => -189291360, // DateTime::createFromFormat('Y-m-d H:i', '1964-01-02 03:04', new DateTimeZone('UTC'))->getTimestamp(),
18
+ )
19
+ --EXPECT--
20
+ OK
21
+ OK
22
+ OK
23
+ OK
24
+ OK
25
+ OK
library/twig/twig/test/Twig/Tests/Fixtures/functions/date_namedargs.test ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "date" function
3
+ --TEMPLATE--
4
+ {{ date(date, "America/New_York")|date('d/m/Y H:i:s P', false) }}
5
+ {{ date(timezone="America/New_York", date=date)|date('d/m/Y H:i:s P', false) }}
6
+ --DATA--
7
+ date_default_timezone_set('UTC');
8
+ return array('date' => mktime(13, 45, 0, 10, 4, 2010))
9
+ --EXPECT--
10
+ 04/10/2010 09:45:00 -04:00
11
+ 04/10/2010 09:45:00 -04:00
library/twig/twig/test/Twig/Tests/Fixtures/functions/dump.test ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "dump" function
3
+ --CONDITION--
4
+ !extension_loaded('xdebug')
5
+ --TEMPLATE--
6
+ {{ dump('foo') }}
7
+ {{ dump('foo', 'bar') }}
8
+ --DATA--
9
+ return array('foo' => 'foo', 'bar' => 'bar')
10
+ --CONFIG--
11
+ return array('debug' => true, 'autoescape' => false);
12
+ --EXPECT--
13
+ string(3) "foo"
14
+
15
+ string(3) "foo"
16
+ string(3) "bar"
library/twig/twig/test/Twig/Tests/Fixtures/functions/dump_array.test ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "dump" function, xdebug is not loaded or xdebug <2.2-dev is loaded
3
+ --CONDITION--
4
+ !extension_loaded('xdebug') || (($r = new ReflectionExtension('xdebug')) && version_compare($r->getVersion(), '2.2-dev', '<'))
5
+ --TEMPLATE--
6
+ {{ dump() }}
7
+ --DATA--
8
+ return array('foo' => 'foo', 'bar' => 'bar')
9
+ --CONFIG--
10
+ return array('debug' => true, 'autoescape' => false);
11
+ --EXPECT--
12
+ array(3) {
13
+ ["foo"]=>
14
+ string(3) "foo"
15
+ ["bar"]=>
16
+ string(3) "bar"
17
+ ["global"]=>
18
+ string(6) "global"
19
+ }
library/twig/twig/test/Twig/Tests/Fixtures/functions/dynamic_function.test ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ dynamic function
3
+ --TEMPLATE--
4
+ {{ foo_path('bar') }}
5
+ {{ a_foo_b_bar('bar') }}
6
+ --DATA--
7
+ return array()
8
+ --EXPECT--
9
+ foo/bar
10
+ a/b/bar
library/twig/twig/test/Twig/Tests/Fixtures/functions/include/assignment.test ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "include" function
3
+ --TEMPLATE--
4
+ {% set tmp = include("foo.twig") %}
5
+
6
+ FOO{{ tmp }}BAR
7
+ --TEMPLATE(foo.twig)--
8
+ FOOBAR
9
+ --DATA--
10
+ return array()
11
+ --EXPECT--
12
+ FOO
13
+ FOOBARBAR
library/twig/twig/test/Twig/Tests/Fixtures/functions/include/autoescaping.test ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "include" function is safe for auto-escaping
3
+ --TEMPLATE--
4
+ {{ include("foo.twig") }}
5
+ --TEMPLATE(foo.twig)--
6
+ <p>Test</p>
7
+ --DATA--
8
+ return array()
9
+ --EXPECT--
10
+ <p>Test</p>
library/twig/twig/test/Twig/Tests/Fixtures/functions/include/basic.test ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "include" function
3
+ --TEMPLATE--
4
+ FOO
5
+ {{ include("foo.twig") }}
6
+
7
+ BAR
8
+ --TEMPLATE(foo.twig)--
9
+ FOOBAR
10
+ --DATA--
11
+ return array()
12
+ --EXPECT--
13
+ FOO
14
+
15
+ FOOBAR
16
+
17
+ BAR
library/twig/twig/test/Twig/Tests/Fixtures/functions/include/expression.test ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "include" function allows expressions for the template to include
3
+ --TEMPLATE--
4
+ FOO
5
+ {{ include(foo) }}
6
+
7
+ BAR
8
+ --TEMPLATE(foo.twig)--
9
+ FOOBAR
10
+ --DATA--
11
+ return array('foo' => 'foo.twig')
12
+ --EXPECT--
13
+ FOO
14
+
15
+ FOOBAR
16
+
17
+ BAR
library/twig/twig/test/Twig/Tests/Fixtures/functions/include/ignore_missing.test ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "include" function
3
+ --TEMPLATE--
4
+ {{ include(["foo.twig", "bar.twig"], ignore_missing = true) }}
5
+ {{ include("foo.twig", ignore_missing = true) }}
6
+ {{ include("foo.twig", ignore_missing = true, variables = {}) }}
7
+ {{ include("foo.twig", ignore_missing = true, variables = {}, with_context = true) }}
8
+ --DATA--
9
+ return array()
10
+ --EXPECT--
library/twig/twig/test/Twig/Tests/Fixtures/functions/include/missing.test ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "include" function
3
+ --TEMPLATE--
4
+ {{ include("foo.twig") }}
5
+ --DATA--
6
+ return array();
7
+ --EXCEPTION--
8
+ Twig_Error_Loader: Template "foo.twig" is not defined in "index.twig" at line 2.
library/twig/twig/test/Twig/Tests/Fixtures/functions/include/missing_nested.test ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "include" function
3
+ --TEMPLATE--
4
+ {% extends "base.twig" %}
5
+
6
+ {% block content %}
7
+ {{ parent() }}
8
+ {% endblock %}
9
+ --TEMPLATE(base.twig)--
10
+ {% block content %}
11
+ {{ include("foo.twig") }}
12
+ {% endblock %}
13
+ --DATA--
14
+ return array();
15
+ --EXCEPTION--
16
+ Twig_Error_Loader: Template "foo.twig" is not defined in "base.twig" at line 3.
library/twig/twig/test/Twig/Tests/Fixtures/functions/include/sandbox.test ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "include" tag sandboxed
3
+ --TEMPLATE--
4
+ {{ include("foo.twig", sandboxed = true) }}
5
+ --TEMPLATE(foo.twig)--
6
+
7
+
8
+ {{ foo|e }}
9
+ {{ foo|e }}
10
+ --DATA--
11
+ return array()
12
+ --EXCEPTION--
13
+ Twig_Sandbox_SecurityNotAllowedFilterError: Filter "e" is not allowed in "foo.twig" at line 4.
library/twig/twig/test/Twig/Tests/Fixtures/functions/include/sandbox_disabling.test ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "include" tag sandboxed
3
+ --TEMPLATE--
4
+ {{ include("foo.twig", sandboxed = true) }}
5
+ {{ include("bar.twig") }}
6
+ --TEMPLATE(foo.twig)--
7
+ foo
8
+ --TEMPLATE(bar.twig)--
9
+ {{ foo|e }}
10
+ --DATA--
11
+ return array('foo' => 'bar<br />')
12
+ --EXPECT--
13
+ foo
14
+
15
+
16
+ bar&lt;br /&gt;
library/twig/twig/test/Twig/Tests/Fixtures/functions/include/sandbox_disabling_ignore_missing.test ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "include" tag sandboxed
3
+ --TEMPLATE--
4
+ {{ include("unknown.twig", sandboxed = true, ignore_missing = true) }}
5
+ {{ include("bar.twig") }}
6
+ --TEMPLATE(bar.twig)--
7
+ {{ foo|e }}
8
+ --DATA--
9
+ return array('foo' => 'bar<br />')
10
+ --EXPECT--
11
+
12
+
13
+ bar&lt;br /&gt;
library/twig/twig/test/Twig/Tests/Fixtures/functions/include/template_instance.test ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "include" function accepts Twig_Template instance
3
+ --TEMPLATE--
4
+ {{ include(foo) }} FOO
5
+ --TEMPLATE(foo.twig)--
6
+ BAR
7
+ --DATA--
8
+ return array('foo' => $twig->loadTemplate('foo.twig'))
9
+ --EXPECT--
10
+ BAR FOO
library/twig/twig/test/Twig/Tests/Fixtures/functions/include/templates_as_array.test ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "include" function
3
+ --TEMPLATE--
4
+ {{ include(["foo.twig", "bar.twig"]) }}
5
+ {{- include(["bar.twig", "foo.twig"]) }}
6
+ --TEMPLATE(foo.twig)--
7
+ foo
8
+ --DATA--
9
+ return array()
10
+ --EXPECT--
11
+ foo
12
+ foo
library/twig/twig/test/Twig/Tests/Fixtures/functions/include/with_context.test ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "include" function accept variables and with_context
3
+ --TEMPLATE--
4
+ {{ include("foo.twig") }}
5
+ {{- include("foo.twig", with_context = false) }}
6
+ {{- include("foo.twig", {'foo1': 'bar'}) }}
7
+ {{- include("foo.twig", {'foo1': 'bar'}, with_context = false) }}
8
+ --TEMPLATE(foo.twig)--
9
+ {% for k, v in _context %}{{ k }},{% endfor %}
10
+ --DATA--
11
+ return array('foo' => 'bar')
12
+ --EXPECT--
13
+ foo,global,_parent,
14
+ global,_parent,
15
+ foo,global,foo1,_parent,
16
+ foo1,global,_parent,
library/twig/twig/test/Twig/Tests/Fixtures/functions/include/with_variables.test ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "include" function accept variables
3
+ --TEMPLATE--
4
+ {{ include("foo.twig", {'foo': 'bar'}) }}
5
+ {{- include("foo.twig", vars) }}
6
+ --TEMPLATE(foo.twig)--
7
+ {{ foo }}
8
+ --DATA--
9
+ return array('vars' => array('foo' => 'bar'))
10
+ --EXPECT--
11
+ bar
12
+ bar
library/twig/twig/test/Twig/Tests/Fixtures/functions/magic_call.test ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ __call calls
3
+ --TEMPLATE--
4
+ {{ 'foo'|magic_call }}
5
+ --DATA--
6
+ return array()
7
+ --EXPECT--
8
+ magic_foo
library/twig/twig/test/Twig/Tests/Fixtures/functions/magic_call53.test ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ __staticCall calls
3
+ --CONDITION--
4
+ version_compare(phpversion(), '5.3.0', '>=')
5
+ --TEMPLATE--
6
+ {{ 'foo'|magic_call_string }}
7
+ {{ 'foo'|magic_call_array }}
8
+ --DATA--
9
+ return array()
10
+ --EXPECT--
11
+ static_magic_foo
12
+ static_magic_foo
library/twig/twig/test/Twig/Tests/Fixtures/functions/max.test ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "max" function
3
+ --TEMPLATE--
4
+ {{ max([2, 1, 3, 5, 4]) }}
5
+ {{ max(2, 1, 3, 5, 4) }}
6
+ {{ max({2:"two", 1:"one", 3:"three", 5:"five", 4:"for"}) }}
7
+ --DATA--
8
+ return array()
9
+ --EXPECT--
10
+ 5
11
+ 5
12
+ two
library/twig/twig/test/Twig/Tests/Fixtures/functions/min.test ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "min" function
3
+ --TEMPLATE--
4
+ {{ min(2, 1, 3, 5, 4) }}
5
+ {{ min([2, 1, 3, 5, 4]) }}
6
+ {{ min({2:"two", 1:"one", 3:"three", 5:"five", 4:"for"}) }}
7
+ --DATA--
8
+ return array()
9
+ --EXPECT--
10
+ 1
11
+ 1
12
+ five
library/twig/twig/test/Twig/Tests/Fixtures/functions/range.test ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "range" function
3
+ --TEMPLATE--
4
+ {{ range(low=0+1, high=10+0, step=2)|join(',') }}
5
+ --DATA--
6
+ return array()
7
+ --EXPECT--
8
+ 1,3,5,7,9
library/twig/twig/test/Twig/Tests/Fixtures/functions/recursive_block_with_inheritance.test ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "block" function recursively called in a parent template
3
+ --TEMPLATE--
4
+ {% extends "ordered_menu.twig" %}
5
+ {% block label %}"{{ parent() }}"{% endblock %}
6
+ {% block list %}{% set class = 'b' %}{{ parent() }}{% endblock %}
7
+ --TEMPLATE(ordered_menu.twig)--
8
+ {% extends "menu.twig" %}
9
+ {% block list %}{% set class = class|default('a') %}<ol class="{{ class }}">{{ block('children') }}</ol>{% endblock %}
10
+ --TEMPLATE(menu.twig)--
11
+ {% extends "base.twig" %}
12
+ {% block list %}<ul>{{ block('children') }}</ul>{% endblock %}
13
+ {% block children %}{% set currentItem = item %}{% for item in currentItem %}{{ block('item') }}{% endfor %}{% set item = currentItem %}{% endblock %}
14
+ {% block item %}<li>{% if item is not iterable %}{{ block('label') }}{% else %}{{ block('list') }}{% endif %}</li>{% endblock %}
15
+ {% block label %}{{ item }}{% endblock %}
16
+ --TEMPLATE(base.twig)--
17
+ {{ block('list') }}
18
+ --DATA--
19
+ return array('item' => array('1', '2', array('3.1', array('3.2.1', '3.2.2'), '3.4')))
20
+ --EXPECT--
21
+ <ol class="b"><li>"1"</li><li>"2"</li><li><ol class="b"><li>"3.1"</li><li><ol class="b"><li>"3.2.1"</li><li>"3.2.2"</li></ol></li><li>"3.4"</li></ol></li></ol>
library/twig/twig/test/Twig/Tests/Fixtures/functions/source.test ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "source" function
3
+ --TEMPLATE--
4
+ FOO
5
+ {{ source("foo.twig") }}
6
+
7
+ BAR
8
+ --TEMPLATE(foo.twig)--
9
+ {{ foo }}<br />
10
+ --DATA--
11
+ return array()
12
+ --EXPECT--
13
+ FOO
14
+
15
+ {{ foo }}<br />
16
+
17
+ BAR
library/twig/twig/test/Twig/Tests/Fixtures/functions/special_chars.test ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "§" custom function
3
+ --TEMPLATE--
4
+ {{ §('foo') }}
5
+ --DATA--
6
+ return array()
7
+ --EXPECT--
8
+ §foo§
library/twig/twig/test/Twig/Tests/Fixtures/functions/static_calls.test ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ Functions as static method calls
3
+ --TEMPLATE--
4
+ {{ static_call_string('foo') }}
5
+ {{ static_call_array('foo') }}
6
+ --DATA--
7
+ return array('foo' => 'foo')
8
+ --EXPECT--
9
+ *foo*
10
+ *foo*
library/twig/twig/test/Twig/Tests/Fixtures/functions/template_from_string.test ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "template_from_string" function
3
+ --TEMPLATE--
4
+ {% include template_from_string(template) %}
5
+
6
+ {% include template_from_string("Hello {{ name }}") %}
7
+ {% include template_from_string('{% extends "parent.twig" %}{% block content %}Hello {{ name }}{% endblock %}') %}
8
+ --TEMPLATE(parent.twig)--
9
+ {% block content %}{% endblock %}
10
+ --DATA--
11
+ return array('name' => 'Fabien', 'template' => "Hello {{ name }}")
12
+ --EXPECT--
13
+ Hello Fabien
14
+ Hello Fabien
15
+ Hello Fabien
library/twig/twig/test/Twig/Tests/Fixtures/macros/default_values.test ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ macro
3
+ --TEMPLATE--
4
+ {% from _self import test %}
5
+
6
+ {% macro test(a, b = 'bar') -%}
7
+ {{ a }}{{ b }}
8
+ {%- endmacro %}
9
+
10
+ {{ test('foo') }}
11
+ {{ test('bar', 'foo') }}
12
+ --DATA--
13
+ return array();
14
+ --EXPECT--
15
+ foobar
16
+ barfoo
library/twig/twig/test/Twig/Tests/Fixtures/macros/nested_calls.test ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ macro
3
+ --TEMPLATE--
4
+ {% import _self as macros %}
5
+
6
+ {% macro foo(data) %}
7
+ {{ data }}
8
+ {% endmacro %}
9
+
10
+ {% macro bar() %}
11
+ <br />
12
+ {% endmacro %}
13
+
14
+ {{ macros.foo(macros.bar()) }}
15
+ --DATA--
16
+ return array();
17
+ --EXPECT--
18
+ <br />
library/twig/twig/test/Twig/Tests/Fixtures/macros/reserved_variables.test ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ macro
3
+ --TEMPLATE--
4
+ {% from _self import test %}
5
+
6
+ {% macro test(this) -%}
7
+ {{ this }}
8
+ {%- endmacro %}
9
+
10
+ {{ test(this) }}
11
+ --DATA--
12
+ return array('this' => 'foo');
13
+ --EXPECT--
14
+ foo
library/twig/twig/test/Twig/Tests/Fixtures/macros/simple.test ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ macro
3
+ --TEMPLATE--
4
+ {% import _self as test %}
5
+ {% from _self import test %}
6
+
7
+ {% macro test(a, b) -%}
8
+ {{ a|default('a') }}<br />
9
+ {{- b|default('b') }}<br />
10
+ {%- endmacro %}
11
+
12
+ {{ test.test() }}
13
+ {{ test() }}
14
+ {{ test.test(1, "c") }}
15
+ {{ test(1, "c") }}
16
+ --DATA--
17
+ return array();
18
+ --EXPECT--
19
+ a<br />b<br />
20
+ a<br />b<br />
21
+ 1<br />c<br />
22
+ 1<br />c<br />
library/twig/twig/test/Twig/Tests/Fixtures/macros/varargs.test ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ macro with arbitrary arguments
3
+ --TEMPLATE--
4
+ {% from _self import test1, test2 %}
5
+
6
+ {% macro test1(var) %}
7
+ {{- var }}: {{ varargs|join(", ") }}
8
+ {% endmacro %}
9
+
10
+ {% macro test2() %}
11
+ {{- varargs|join(", ") }}
12
+ {% endmacro %}
13
+
14
+ {{ test1("foo", "bar", "foobar") }}
15
+ {{ test2("foo", "bar", "foobar") }}
16
+ --DATA--
17
+ return array();
18
+ --EXPECT--
19
+ foo: bar, foobar
20
+
21
+ foo, bar, foobar
library/twig/twig/test/Twig/Tests/Fixtures/macros/varargs_argument.test ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
1
+ --TEST--
2
+ macro with varargs argument
3
+ --TEMPLATE--
4
+ {% macro test(varargs) %}
5
+ {% endmacro %}
6
+ --EXCEPTION--
7
+ Twig_Error_Syntax: The argument "varargs" in macro "test" cannot be defined because the variable "varargs" is reserved for arbitrary arguments in "index.twig" at line 2.
library/twig/twig/test/Twig/Tests/Fixtures/macros/with_filters.test ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ macro with a filter
3
+ --TEMPLATE--
4
+ {% import _self as test %}
5
+
6
+ {% macro test() %}
7
+ {% filter escape %}foo<br />{% endfilter %}
8
+ {% endmacro %}
9
+
10
+ {{ test.test() }}
11
+ --DATA--
12
+ return array();
13
+ --EXPECT--
14
+ foo&lt;br /&gt;
library/twig/twig/test/Twig/Tests/Fixtures/regression/combined_debug_info.test ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ Exception with bad line number
3
+ --TEMPLATE--
4
+ {% block content %}
5
+ {{ foo }}
6
+ {{ include("foo") }}
7
+ {% endblock %}
8
+ index
9
+ --TEMPLATE(foo)--
10
+ foo
11
+ {{ foo.bar }}
12
+ --DATA--
13
+ return array('foo' => 'foo');
14
+ --EXCEPTION--
15
+ Twig_Error_Runtime: Impossible to access an attribute ("bar") on a string variable ("foo") in "foo" at line 3.
library/twig/twig/test/Twig/Tests/Fixtures/regression/empty_token.test ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ Twig outputs 0 nodes correctly
3
+ --TEMPLATE--
4
+ {{ foo }}0{{ foo }}
5
+ --DATA--
6
+ return array('foo' => 'foo')
7
+ --EXPECT--
8
+ foo0foo
library/twig/twig/test/Twig/Tests/Fixtures/regression/issue_1143.test ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ error in twig extension
3
+ --TEMPLATE--
4
+ {{ object.region is not null ? object.regionChoices[object.region] }}
5
+ --DATA--
6
+ class House
7
+ {
8
+ const REGION_S = 1;
9
+ const REGION_P = 2;
10
+
11
+ public static $regionChoices = array(self::REGION_S => 'house.region.s', self::REGION_P => 'house.region.p');
12
+
13
+ public function getRegionChoices()
14
+ {
15
+ return self::$regionChoices;
16
+ }
17
+ }
18
+
19
+ $object = new House();
20
+ $object->region = 1;
21
+ return array('object' => $object)
22
+ --EXPECT--
23
+ house.region.s
library/twig/twig/test/Twig/Tests/Fixtures/regression/multi_word_tests.test ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ Twig allows multi-word tests without a custom node class
3
+ --TEMPLATE--
4
+ {{ 'foo' is multi word ? 'yes' : 'no' }}
5
+ {{ 'foo bar' is multi word ? 'yes' : 'no' }}
6
+ --DATA--
7
+ return array()
8
+ --EXPECT--
9
+ no
10
+ yes
library/twig/twig/test/Twig/Tests/Fixtures/regression/simple_xml_element.test ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ Twig is able to deal with SimpleXMLElement instances as variables
3
+ --CONDITION--
4
+ version_compare(phpversion(), '5.3.0', '>=')
5
+ --TEMPLATE--
6
+ Hello '{{ images.image.0.group }}'!
7
+ {{ images.image.0.group.attributes.myattr }}
8
+ {{ images.children().image.count() }}
9
+ {% for image in images %}
10
+ - {{ image.group }}
11
+ {% endfor %}
12
+ --DATA--
13
+ return array('images' => new SimpleXMLElement('<images><image><group myattr="example">foo</group></image><image><group>bar</group></image></images>'))
14
+ --EXPECT--
15
+ Hello 'foo'!
16
+ example
17
+ 2
18
+ - foo
19
+ - bar
library/twig/twig/test/Twig/Tests/Fixtures/regression/strings_like_numbers.test ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ Twig does not confuse strings with integers in getAttribute()
3
+ --TEMPLATE--
4
+ {{ hash['2e2'] }}
5
+ --DATA--
6
+ return array('hash' => array('2e2' => 'works'))
7
+ --EXPECT--
8
+ works
library/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/basic.test ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "autoescape" tag applies escaping on its children
3
+ --TEMPLATE--
4
+ {% autoescape %}
5
+ {{ var }}<br />
6
+ {% endautoescape %}
7
+ {% autoescape 'html' %}
8
+ {{ var }}<br />
9
+ {% endautoescape %}
10
+ {% autoescape false %}
11
+ {{ var }}<br />
12
+ {% endautoescape %}
13
+ {% autoescape true %}
14
+ {{ var }}<br />
15
+ {% endautoescape %}
16
+ {% autoescape false %}
17
+ {{ var }}<br />
18
+ {% endautoescape %}
19
+ --DATA--
20
+ return array('var' => '<br />')
21
+ --EXPECT--
22
+ &lt;br /&gt;<br />
23
+ &lt;br /&gt;<br />
24
+ <br /><br />
25
+ &lt;br /&gt;<br />
26
+ <br /><br />
library/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/blocks.test ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "autoescape" tag applies escaping on embedded blocks
3
+ --TEMPLATE--
4
+ {% autoescape 'html' %}
5
+ {% block foo %}
6
+ {{ var }}
7
+ {% endblock %}
8
+ {% endautoescape %}
9
+ --DATA--
10
+ return array('var' => '<br />')
11
+ --EXPECT--
12
+ &lt;br /&gt;
library/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/double_escaping.test ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "autoescape" tag does not double-escape
3
+ --TEMPLATE--
4
+ {% autoescape 'html' %}
5
+ {{ var|escape }}
6
+ {% endautoescape %}
7
+ --DATA--
8
+ return array('var' => '<br />')
9
+ --EXPECT--
10
+ &lt;br /&gt;
library/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/functions.test ADDED
@@ -0,0 +1,83 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "autoescape" tag applies escaping after calling functions
3
+ --TEMPLATE--
4
+
5
+ autoescape false
6
+ {% autoescape false %}
7
+
8
+ safe_br
9
+ {{ safe_br() }}
10
+
11
+ unsafe_br
12
+ {{ unsafe_br() }}
13
+
14
+ {% endautoescape %}
15
+
16
+ autoescape 'html'
17
+ {% autoescape 'html' %}
18
+
19
+ safe_br
20
+ {{ safe_br() }}
21
+
22
+ unsafe_br
23
+ {{ unsafe_br() }}
24
+
25
+ unsafe_br()|raw
26
+ {{ (unsafe_br())|raw }}
27
+
28
+ safe_br()|escape
29
+ {{ (safe_br())|escape }}
30
+
31
+ safe_br()|raw
32
+ {{ (safe_br())|raw }}
33
+
34
+ unsafe_br()|escape
35
+ {{ (unsafe_br())|escape }}
36
+
37
+ {% endautoescape %}
38
+
39
+ autoescape js
40
+ {% autoescape 'js' %}
41
+
42
+ safe_br
43
+ {{ safe_br() }}
44
+
45
+ {% endautoescape %}
46
+ --DATA--
47
+ return array()
48
+ --EXPECT--
49
+
50
+ autoescape false
51
+
52
+ safe_br
53
+ <br />
54
+
55
+ unsafe_br
56
+ <br />
57
+
58
+
59
+ autoescape 'html'
60
+
61
+ safe_br
62
+ <br />
63
+
64
+ unsafe_br
65
+ &lt;br /&gt;
66
+
67
+ unsafe_br()|raw
68
+ <br />
69
+
70
+ safe_br()|escape
71
+ &lt;br /&gt;
72
+
73
+ safe_br()|raw
74
+ <br />
75
+
76
+ unsafe_br()|escape
77
+ &lt;br /&gt;
78
+
79
+
80
+ autoescape js
81
+
82
+ safe_br
83
+ \x3Cbr\x20\x2F\x3E
library/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/literal.test ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "autoescape" tag does not apply escaping on literals
3
+ --TEMPLATE--
4
+ {% autoescape 'html' %}
5
+
6
+ 1. Simple literal
7
+ {{ "<br />" }}
8
+
9
+ 2. Conditional expression with only literals
10
+ {{ true ? "<br />" : "<br>" }}
11
+
12
+ 3. Conditional expression with a variable
13
+ {{ true ? "<br />" : someVar }}
14
+
15
+ 4. Nested conditionals with only literals
16
+ {{ true ? (true ? "<br />" : "<br>") : "\n" }}
17
+
18
+ 5. Nested conditionals with a variable
19
+ {{ true ? (true ? "<br />" : someVar) : "\n" }}
20
+
21
+ 6. Nested conditionals with a variable marked safe
22
+ {{ true ? (true ? "<br />" : someVar|raw) : "\n" }}
23
+
24
+ {% endautoescape %}
25
+ --DATA--
26
+ return array()
27
+ --EXPECT--
28
+
29
+ 1. Simple literal
30
+ <br />
31
+
32
+ 2. Conditional expression with only literals
33
+ <br />
34
+
35
+ 3. Conditional expression with a variable
36
+ &lt;br /&gt;
37
+
38
+ 4. Nested conditionals with only literals
39
+ <br />
40
+
41
+ 5. Nested conditionals with a variable
42
+ &lt;br /&gt;
43
+
44
+ 6. Nested conditionals with a variable marked safe
45
+ <br />
library/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/nested.test ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "autoescape" tags can be nested at will
3
+ --TEMPLATE--
4
+ {{ var }}
5
+ {% autoescape 'html' %}
6
+ {{ var }}
7
+ {% autoescape false %}
8
+ {{ var }}
9
+ {% autoescape 'html' %}
10
+ {{ var }}
11
+ {% endautoescape %}
12
+ {{ var }}
13
+ {% endautoescape %}
14
+ {{ var }}
15
+ {% endautoescape %}
16
+ {{ var }}
17
+ --DATA--
18
+ return array('var' => '<br />')
19
+ --EXPECT--
20
+ &lt;br /&gt;
21
+ &lt;br /&gt;
22
+ <br />
23
+ &lt;br /&gt;
24
+ <br />
25
+ &lt;br /&gt;
26
+ &lt;br /&gt;
library/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/objects.test ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "autoescape" tag applies escaping to object method calls
3
+ --TEMPLATE--
4
+ {% autoescape 'html' %}
5
+ {{ user.name }}
6
+ {{ user.name|lower }}
7
+ {{ user }}
8
+ {% endautoescape %}
9
+ --DATA--
10
+ class UserForAutoEscapeTest
11
+ {
12
+ public function getName()
13
+ {
14
+ return 'Fabien<br />';
15
+ }
16
+
17
+ public function __toString()
18
+ {
19
+ return 'Fabien<br />';
20
+ }
21
+ }
22
+ return array('user' => new UserForAutoEscapeTest())
23
+ --EXPECT--
24
+ Fabien&lt;br /&gt;
25
+ fabien&lt;br /&gt;
26
+ Fabien&lt;br /&gt;
library/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/raw.test ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "autoescape" tag does not escape when raw is used as a filter
3
+ --TEMPLATE--
4
+ {% autoescape 'html' %}
5
+ {{ var|raw }}
6
+ {% endautoescape %}
7
+ --DATA--
8
+ return array('var' => '<br />')
9
+ --EXPECT--
10
+ <br />
library/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/strategy.legacy.test ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "autoescape" tag accepts an escaping strategy
3
+ --TEMPLATE--
4
+ {% autoescape true js %}{{ var }}{% endautoescape %}
5
+
6
+ {% autoescape true html %}{{ var }}{% endautoescape %}
7
+ --DATA--
8
+ return array('var' => '<br />"')
9
+ --EXPECT--
10
+ \x3Cbr\x20\x2F\x3E\x22
11
+ &lt;br /&gt;&quot;
library/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/strategy.test ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "autoescape" tag accepts an escaping strategy
3
+ --TEMPLATE--
4
+ {% autoescape 'js' %}{{ var }}{% endautoescape %}
5
+
6
+ {% autoescape 'html' %}{{ var }}{% endautoescape %}
7
+ --DATA--
8
+ return array('var' => '<br />"')
9
+ --EXPECT--
10
+ \x3Cbr\x20\x2F\x3E\x22
11
+ &lt;br /&gt;&quot;
library/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/type.test ADDED
@@ -0,0 +1,69 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ escape types
3
+ --TEMPLATE--
4
+
5
+ 1. autoescape 'html' |escape('js')
6
+
7
+ {% autoescape 'html' %}
8
+ <a onclick="alert(&quot;{{ msg|escape('js') }}&quot;)"></a>
9
+ {% endautoescape %}
10
+
11
+ 2. autoescape 'html' |escape('js')
12
+
13
+ {% autoescape 'html' %}
14
+ <a onclick="alert(&quot;{{ msg|escape('js') }}&quot;)"></a>
15
+ {% endautoescape %}
16
+
17
+ 3. autoescape 'js' |escape('js')
18
+
19
+ {% autoescape 'js' %}
20
+ <a onclick="alert(&quot;{{ msg|escape('js') }}&quot;)"></a>
21
+ {% endautoescape %}
22
+
23
+ 4. no escape
24
+
25
+ {% autoescape false %}
26
+ <a onclick="alert(&quot;{{ msg }}&quot;)"></a>
27
+ {% endautoescape %}
28
+
29
+ 5. |escape('js')|escape('html')
30
+
31
+ {% autoescape false %}
32
+ <a onclick="alert(&quot;{{ msg|escape('js')|escape('html') }}&quot;)"></a>
33
+ {% endautoescape %}
34
+
35
+ 6. autoescape 'html' |escape('js')|escape('html')
36
+
37
+ {% autoescape 'html' %}
38
+ <a onclick="alert(&quot;{{ msg|escape('js')|escape('html') }}&quot;)"></a>
39
+ {% endautoescape %}
40
+
41
+ --DATA--
42
+ return array('msg' => "<>\n'\"")
43
+ --EXPECT--
44
+
45
+ 1. autoescape 'html' |escape('js')
46
+
47
+ <a onclick="alert(&quot;\x3C\x3E\x0A\x27\x22&quot;)"></a>
48
+
49
+ 2. autoescape 'html' |escape('js')
50
+
51
+ <a onclick="alert(&quot;\x3C\x3E\x0A\x27\x22&quot;)"></a>
52
+
53
+ 3. autoescape 'js' |escape('js')
54
+
55
+ <a onclick="alert(&quot;\x3C\x3E\x0A\x27\x22&quot;)"></a>
56
+
57
+ 4. no escape
58
+
59
+ <a onclick="alert(&quot;<>
60
+ '"&quot;)"></a>
61
+
62
+ 5. |escape('js')|escape('html')
63
+
64
+ <a onclick="alert(&quot;\x3C\x3E\x0A\x27\x22&quot;)"></a>
65
+
66
+ 6. autoescape 'html' |escape('js')|escape('html')
67
+
68
+ <a onclick="alert(&quot;\x3C\x3E\x0A\x27\x22&quot;)"></a>
69
+
library/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/with_filters.test ADDED
@@ -0,0 +1,131 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "autoescape" tag applies escaping after calling filters
3
+ --TEMPLATE--
4
+ {% autoescape 'html' %}
5
+
6
+ (escape_and_nl2br is an escaper filter)
7
+
8
+ 1. Don't escape escaper filter output
9
+ ( var is escaped by |escape_and_nl2br, line-breaks are added,
10
+ the output is not escaped )
11
+ {{ var|escape_and_nl2br }}
12
+
13
+ 2. Don't escape escaper filter output
14
+ ( var is escaped by |escape_and_nl2br, line-breaks are added,
15
+ the output is not escaped, |raw is redundant )
16
+ {{ var|escape_and_nl2br|raw }}
17
+
18
+ 3. Explicit escape
19
+ ( var is escaped by |escape_and_nl2br, line-breaks are added,
20
+ the output is explicitly escaped by |escape )
21
+ {{ var|escape_and_nl2br|escape }}
22
+
23
+ 4. Escape non-escaper filter output
24
+ ( var is upper-cased by |upper,
25
+ the output is auto-escaped )
26
+ {{ var|upper }}
27
+
28
+ 5. Escape if last filter is not an escaper
29
+ ( var is escaped by |escape_and_nl2br, line-breaks are added,
30
+ the output is upper-cased by |upper,
31
+ the output is auto-escaped as |upper is not an escaper )
32
+ {{ var|escape_and_nl2br|upper }}
33
+
34
+ 6. Don't escape escaper filter output
35
+ ( var is upper cased by upper,
36
+ the output is escaped by |escape_and_nl2br, line-breaks are added,
37
+ the output is not escaped as |escape_and_nl2br is an escaper )
38
+ {{ var|upper|escape_and_nl2br }}
39
+
40
+ 7. Escape if last filter is not an escaper
41
+ ( the output of |format is "<b>" ~ var ~ "</b>",
42
+ the output is auto-escaped )
43
+ {{ "<b>%s</b>"|format(var) }}
44
+
45
+ 8. Escape if last filter is not an escaper
46
+ ( the output of |format is "<b>" ~ var ~ "</b>",
47
+ |raw is redundant,
48
+ the output is auto-escaped )
49
+ {{ "<b>%s</b>"|raw|format(var) }}
50
+
51
+ 9. Don't escape escaper filter output
52
+ ( the output of |format is "<b>" ~ var ~ "</b>",
53
+ the output is not escaped due to |raw filter at the end )
54
+ {{ "<b>%s</b>"|format(var)|raw }}
55
+
56
+ 10. Don't escape escaper filter output
57
+ ( the output of |format is "<b>" ~ var ~ "</b>",
58
+ the output is not escaped due to |raw filter at the end,
59
+ the |raw filter on var is redundant )
60
+ {{ "<b>%s</b>"|format(var|raw)|raw }}
61
+
62
+ {% endautoescape %}
63
+ --DATA--
64
+ return array('var' => "<Fabien>\nTwig")
65
+ --EXPECT--
66
+
67
+ (escape_and_nl2br is an escaper filter)
68
+
69
+ 1. Don't escape escaper filter output
70
+ ( var is escaped by |escape_and_nl2br, line-breaks are added,
71
+ the output is not escaped )
72
+ &lt;Fabien&gt;<br />
73
+ Twig
74
+
75
+ 2. Don't escape escaper filter output
76
+ ( var is escaped by |escape_and_nl2br, line-breaks are added,
77
+ the output is not escaped, |raw is redundant )
78
+ &lt;Fabien&gt;<br />
79
+ Twig
80
+
81
+ 3. Explicit escape
82
+ ( var is escaped by |escape_and_nl2br, line-breaks are added,
83
+ the output is explicitly escaped by |escape )
84
+ &amp;lt;Fabien&amp;gt;&lt;br /&gt;
85
+ Twig
86
+
87
+ 4. Escape non-escaper filter output
88
+ ( var is upper-cased by |upper,
89
+ the output is auto-escaped )
90
+ &lt;FABIEN&gt;
91
+ TWIG
92
+
93
+ 5. Escape if last filter is not an escaper
94
+ ( var is escaped by |escape_and_nl2br, line-breaks are added,
95
+ the output is upper-cased by |upper,
96
+ the output is auto-escaped as |upper is not an escaper )
97
+ &amp;LT;FABIEN&amp;GT;&lt;BR /&gt;
98
+ TWIG
99
+
100
+ 6. Don't escape escaper filter output
101
+ ( var is upper cased by upper,
102
+ the output is escaped by |escape_and_nl2br, line-breaks are added,
103
+ the output is not escaped as |escape_and_nl2br is an escaper )
104
+ &lt;FABIEN&gt;<br />
105
+ TWIG
106
+
107
+ 7. Escape if last filter is not an escaper
108
+ ( the output of |format is "<b>" ~ var ~ "</b>",
109
+ the output is auto-escaped )
110
+ &lt;b&gt;&lt;Fabien&gt;
111
+ Twig&lt;/b&gt;
112
+
113
+ 8. Escape if last filter is not an escaper
114
+ ( the output of |format is "<b>" ~ var ~ "</b>",
115
+ |raw is redundant,
116
+ the output is auto-escaped )
117
+ &lt;b&gt;&lt;Fabien&gt;
118
+ Twig&lt;/b&gt;
119
+
120
+ 9. Don't escape escaper filter output
121
+ ( the output of |format is "<b>" ~ var ~ "</b>",
122
+ the output is not escaped due to |raw filter at the end )
123
+ <b><Fabien>
124
+ Twig</b>
125
+
126
+ 10. Don't escape escaper filter output
127
+ ( the output of |format is "<b>" ~ var ~ "</b>",
128
+ the output is not escaped due to |raw filter at the end,
129
+ the |raw filter on var is redundant )
130
+ <b><Fabien>
131
+ Twig</b>
library/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/with_filters_arguments.test ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "autoescape" tag do not applies escaping on filter arguments
3
+ --TEMPLATE--
4
+ {% autoescape 'html' %}
5
+ {{ var|nl2br("<br />") }}
6
+ {{ var|nl2br("<br />"|escape) }}
7
+ {{ var|nl2br(sep) }}
8
+ {{ var|nl2br(sep|raw) }}
9
+ {{ var|nl2br(sep|escape) }}
10
+ {% endautoescape %}
11
+ --DATA--
12
+ return array('var' => "<Fabien>\nTwig", 'sep' => '<br />')
13
+ --EXPECT--
14
+ &lt;Fabien&gt;<br />
15
+ Twig
16
+ &lt;Fabien&gt;&lt;br /&gt;
17
+ Twig
18
+ &lt;Fabien&gt;<br />
19
+ Twig
20
+ &lt;Fabien&gt;<br />
21
+ Twig
22
+ &lt;Fabien&gt;&lt;br /&gt;
23
+ Twig
library/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/with_pre_escape_filters.test ADDED
@@ -0,0 +1,68 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "autoescape" tag applies escaping after calling filters, and before calling pre_escape filters
3
+ --TEMPLATE--
4
+ {% autoescape 'html' %}
5
+
6
+ (nl2br is pre_escaped for "html" and declared safe for "html")
7
+
8
+ 1. Pre-escape and don't post-escape
9
+ ( var|escape|nl2br )
10
+ {{ var|nl2br }}
11
+
12
+ 2. Don't double-pre-escape
13
+ ( var|escape|nl2br )
14
+ {{ var|escape|nl2br }}
15
+
16
+ 3. Don't escape safe values
17
+ ( var|raw|nl2br )
18
+ {{ var|raw|nl2br }}
19
+
20
+ 4. Don't escape safe values
21
+ ( var|escape|nl2br|nl2br )
22
+ {{ var|nl2br|nl2br }}
23
+
24
+ 5. Re-escape values that are escaped for an other contexts
25
+ ( var|escape_something|escape|nl2br )
26
+ {{ var|escape_something|nl2br }}
27
+
28
+ 6. Still escape when using filters not declared safe
29
+ ( var|escape|nl2br|upper|escape )
30
+ {{ var|nl2br|upper }}
31
+
32
+ {% endautoescape %}
33
+ --DATA--
34
+ return array('var' => "<Fabien>\nTwig")
35
+ --EXPECT--
36
+
37
+ (nl2br is pre_escaped for "html" and declared safe for "html")
38
+
39
+ 1. Pre-escape and don't post-escape
40
+ ( var|escape|nl2br )
41
+ &lt;Fabien&gt;<br />
42
+ Twig
43
+
44
+ 2. Don't double-pre-escape
45
+ ( var|escape|nl2br )
46
+ &lt;Fabien&gt;<br />
47
+ Twig
48
+
49
+ 3. Don't escape safe values
50
+ ( var|raw|nl2br )
51
+ <Fabien><br />
52
+ Twig
53
+
54
+ 4. Don't escape safe values
55
+ ( var|escape|nl2br|nl2br )
56
+ &lt;Fabien&gt;<br /><br />
57
+ Twig
58
+
59
+ 5. Re-escape values that are escaped for an other contexts
60
+ ( var|escape_something|escape|nl2br )
61
+ &lt;FABIEN&gt;<br />
62
+ TWIG
63
+
64
+ 6. Still escape when using filters not declared safe
65
+ ( var|escape|nl2br|upper|escape )
66
+ &amp;LT;FABIEN&amp;GT;&lt;BR /&gt;
67
+ TWIG
68
+
library/twig/twig/test/Twig/Tests/Fixtures/tags/autoescape/with_preserves_safety_filters.test ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "autoescape" tag handles filters preserving the safety
3
+ --TEMPLATE--
4
+ {% autoescape 'html' %}
5
+
6
+ (preserves_safety is preserving safety for "html")
7
+
8
+ 1. Unsafe values are still unsafe
9
+ ( var|preserves_safety|escape )
10
+ {{ var|preserves_safety }}
11
+
12
+ 2. Safe values are still safe
13
+ ( var|escape|preserves_safety )
14
+ {{ var|escape|preserves_safety }}
15
+
16
+ 3. Re-escape values that are escaped for an other contexts
17
+ ( var|escape_something|preserves_safety|escape )
18
+ {{ var|escape_something|preserves_safety }}
19
+
20
+ 4. Still escape when using filters not declared safe
21
+ ( var|escape|preserves_safety|replace({'FABIEN': 'FABPOT'})|escape )
22
+ {{ var|escape|preserves_safety|replace({'FABIEN': 'FABPOT'}) }}
23
+
24
+ {% endautoescape %}
25
+ --DATA--
26
+ return array('var' => "<Fabien>\nTwig")
27
+ --EXPECT--
28
+
29
+ (preserves_safety is preserving safety for "html")
30
+
31
+ 1. Unsafe values are still unsafe
32
+ ( var|preserves_safety|escape )
33
+ &lt;FABIEN&gt;
34
+ TWIG
35
+
36
+ 2. Safe values are still safe
37
+ ( var|escape|preserves_safety )
38
+ &LT;FABIEN&GT;
39
+ TWIG
40
+
41
+ 3. Re-escape values that are escaped for an other contexts
42
+ ( var|escape_something|preserves_safety|escape )
43
+ &lt;FABIEN&gt;
44
+ TWIG
45
+
46
+ 4. Still escape when using filters not declared safe
47
+ ( var|escape|preserves_safety|replace({'FABIEN': 'FABPOT'})|escape )
48
+ &amp;LT;FABPOT&amp;GT;
49
+ TWIG
50
+
library/twig/twig/test/Twig/Tests/Fixtures/tags/block/basic.test ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "block" tag
3
+ --TEMPLATE--
4
+ {% block title1 %}FOO{% endblock %}
5
+ {% block title2 foo|lower %}
6
+ --TEMPLATE(foo.twig)--
7
+ {% block content %}{% endblock %}
8
+ --DATA--
9
+ return array('foo' => 'bar')
10
+ --EXPECT--
11
+ FOObar
library/twig/twig/test/Twig/Tests/Fixtures/tags/block/block_unique_name.test ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "block" tag
3
+ --TEMPLATE--
4
+ {% block content %}
5
+ {% block content %}
6
+ {% endblock %}
7
+ {% endblock %}
8
+ --DATA--
9
+ return array()
10
+ --EXCEPTION--
11
+ Twig_Error_Syntax: The block 'content' has already been defined line 2 in "index.twig" at line 3.
library/twig/twig/test/Twig/Tests/Fixtures/tags/block/special_chars.test ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "§" special chars in a block name
3
+ --TEMPLATE--
4
+ {% block § %}
5
+ §
6
+ {% endblock § %}
7
+ --DATA--
8
+ return array()
9
+ --EXPECT--
10
+ §
library/twig/twig/test/Twig/Tests/Fixtures/tags/embed/basic.test ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "embed" tag
3
+ --TEMPLATE--
4
+ FOO
5
+ {% embed "foo.twig" %}
6
+ {% block c1 %}
7
+ {{ parent() }}
8
+ block1extended
9
+ {% endblock %}
10
+ {% endembed %}
11
+
12
+ BAR
13
+ --TEMPLATE(foo.twig)--
14
+ A
15
+ {% block c1 %}
16
+ block1
17
+ {% endblock %}
18
+ B
19
+ {% block c2 %}
20
+ block2
21
+ {% endblock %}
22
+ C
23
+ --DATA--
24
+ return array()
25
+ --EXPECT--
26
+ FOO
27
+
28
+ A
29
+ block1
30
+
31
+ block1extended
32
+ B
33
+ block2
34
+ C
35
+ BAR
library/twig/twig/test/Twig/Tests/Fixtures/tags/embed/complex_dynamic_parent.test ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "embed" tag
3
+ --TEMPLATE--
4
+ FOO
5
+ {% embed foo ~ ".twig" %}
6
+ {% block c1 %}
7
+ {{ parent() }}
8
+ block1extended
9
+ {% endblock %}
10
+ {% endembed %}
11
+
12
+ BAR
13
+ --TEMPLATE(foo.twig)--
14
+ A
15
+ {% block c1 %}
16
+ block1
17
+ {% endblock %}
18
+ B
19
+ {% block c2 %}
20
+ block2
21
+ {% endblock %}
22
+ C
23
+ --DATA--
24
+ return array('foo' => 'foo')
25
+ --EXPECT--
26
+ FOO
27
+
28
+ A
29
+ block1
30
+
31
+ block1extended
32
+ B
33
+ block2
34
+ C
35
+ BAR
library/twig/twig/test/Twig/Tests/Fixtures/tags/embed/dynamic_parent.test ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "embed" tag
3
+ --TEMPLATE--
4
+ FOO
5
+ {% embed foo %}
6
+ {% block c1 %}
7
+ {{ parent() }}
8
+ block1extended
9
+ {% endblock %}
10
+ {% endembed %}
11
+
12
+ BAR
13
+ --TEMPLATE(foo.twig)--
14
+ A
15
+ {% block c1 %}
16
+ block1
17
+ {% endblock %}
18
+ B
19
+ {% block c2 %}
20
+ block2
21
+ {% endblock %}
22
+ C
23
+ --DATA--
24
+ return array('foo' => 'foo.twig')
25
+ --EXPECT--
26
+ FOO
27
+
28
+ A
29
+ block1
30
+
31
+ block1extended
32
+ B
33
+ block2
34
+ C
35
+ BAR
library/twig/twig/test/Twig/Tests/Fixtures/tags/embed/error_line.test ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "embed" tag
3
+ --TEMPLATE(index.twig)--
4
+ FOO
5
+ {% embed "foo.twig" %}
6
+ {% block c1 %}
7
+ {{ nothing }}
8
+ {% endblock %}
9
+ {% endembed %}
10
+ BAR
11
+ --TEMPLATE(foo.twig)--
12
+ {% block c1 %}{% endblock %}
13
+ --DATA--
14
+ return array()
15
+ --EXCEPTION--
16
+ Twig_Error_Runtime: Variable "nothing" does not exist in "index.twig" at line 5.
library/twig/twig/test/Twig/Tests/Fixtures/tags/embed/multiple.test ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "embed" tag
3
+ --TEMPLATE--
4
+ FOO
5
+ {% embed "foo.twig" %}
6
+ {% block c1 %}
7
+ {{ parent() }}
8
+ block1extended
9
+ {% endblock %}
10
+ {% endembed %}
11
+
12
+ {% embed "foo.twig" %}
13
+ {% block c1 %}
14
+ {{ parent() }}
15
+ block1extended
16
+ {% endblock %}
17
+ {% endembed %}
18
+
19
+ BAR
20
+ --TEMPLATE(foo.twig)--
21
+ A
22
+ {% block c1 %}
23
+ block1
24
+ {% endblock %}
25
+ B
26
+ {% block c2 %}
27
+ block2
28
+ {% endblock %}
29
+ C
30
+ --DATA--
31
+ return array()
32
+ --EXPECT--
33
+ FOO
34
+
35
+ A
36
+ block1
37
+
38
+ block1extended
39
+ B
40
+ block2
41
+ C
42
+
43
+ A
44
+ block1
45
+
46
+ block1extended
47
+ B
48
+ block2
49
+ C
50
+ BAR
library/twig/twig/test/Twig/Tests/Fixtures/tags/embed/nested.test ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "embed" tag
3
+ --TEMPLATE--
4
+ {% embed "foo.twig" %}
5
+ {% block c1 %}
6
+ {{ parent() }}
7
+ {% embed "foo.twig" %}
8
+ {% block c1 %}
9
+ {{ parent() }}
10
+ block1extended
11
+ {% endblock %}
12
+ {% endembed %}
13
+
14
+ {% endblock %}
15
+ {% endembed %}
16
+ --TEMPLATE(foo.twig)--
17
+ A
18
+ {% block c1 %}
19
+ block1
20
+ {% endblock %}
21
+ B
22
+ {% block c2 %}
23
+ block2
24
+ {% endblock %}
25
+ C
26
+ --DATA--
27
+ return array()
28
+ --EXPECT--
29
+ A
30
+ block1
31
+
32
+
33
+ A
34
+ block1
35
+
36
+ block1extended
37
+ B
38
+ block2
39
+ C
40
+ B
41
+ block2
42
+ C
library/twig/twig/test/Twig/Tests/Fixtures/tags/embed/with_extends.test ADDED
@@ -0,0 +1,60 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "embed" tag
3
+ --TEMPLATE--
4
+ {% extends "base.twig" %}
5
+
6
+ {% block c1 %}
7
+ {{ parent() }}
8
+ blockc1baseextended
9
+ {% endblock %}
10
+
11
+ {% block c2 %}
12
+ {{ parent() }}
13
+
14
+ {% embed "foo.twig" %}
15
+ {% block c1 %}
16
+ {{ parent() }}
17
+ block1extended
18
+ {% endblock %}
19
+ {% endembed %}
20
+ {{ parent() }}
21
+ {% endblock %}
22
+ --TEMPLATE(base.twig)--
23
+ A
24
+ {% block c1 %}
25
+ blockc1base
26
+ {% endblock %}
27
+ {% block c2 %}
28
+ blockc2base
29
+ {% endblock %}
30
+ B
31
+ --TEMPLATE(foo.twig)--
32
+ A
33
+ {% block c1 %}
34
+ block1
35
+ {% endblock %}
36
+ B
37
+ {% block c2 %}
38
+ block2
39
+ {% endblock %}
40
+ C
41
+ --DATA--
42
+ return array()
43
+ --EXPECT--
44
+ A
45
+ blockc1base
46
+
47
+ blockc1baseextended
48
+ blockc2base
49
+
50
+
51
+
52
+ A
53
+ block1
54
+
55
+ block1extended
56
+ B
57
+ block2
58
+ C blockc2base
59
+
60
+ B
library/twig/twig/test/Twig/Tests/Fixtures/tags/filter/basic.test ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "filter" tag applies a filter on its children
3
+ --TEMPLATE--
4
+ {% filter upper %}
5
+ Some text with a {{ var }}
6
+ {% endfilter %}
7
+ --DATA--
8
+ return array('var' => 'var')
9
+ --EXPECT--
10
+ SOME TEXT WITH A VAR
library/twig/twig/test/Twig/Tests/Fixtures/tags/filter/json_encode.test ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "filter" tag applies a filter on its children
3
+ --TEMPLATE--
4
+ {% filter json_encode|raw %}test{% endfilter %}
5
+ --DATA--
6
+ return array()
7
+ --EXPECT--
8
+ "test"
library/twig/twig/test/Twig/Tests/Fixtures/tags/filter/multiple.test ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "filter" tags accept multiple chained filters
3
+ --TEMPLATE--
4
+ {% filter lower|title %}
5
+ {{ var }}
6
+ {% endfilter %}
7
+ --DATA--
8
+ return array('var' => 'VAR')
9
+ --EXPECT--
10
+ Var
library/twig/twig/test/Twig/Tests/Fixtures/tags/filter/nested.test ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "filter" tags can be nested at will
3
+ --TEMPLATE--
4
+ {% filter lower|title %}
5
+ {{ var }}
6
+ {% filter upper %}
7
+ {{ var }}
8
+ {% endfilter %}
9
+ {{ var }}
10
+ {% endfilter %}
11
+ --DATA--
12
+ return array('var' => 'var')
13
+ --EXPECT--
14
+ Var
15
+ Var
16
+ Var
library/twig/twig/test/Twig/Tests/Fixtures/tags/filter/with_for_tag.test ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "filter" tag applies the filter on "for" tags
3
+ --TEMPLATE--
4
+ {% filter upper %}
5
+ {% for item in items %}
6
+ {{ item }}
7
+ {% endfor %}
8
+ {% endfilter %}
9
+ --DATA--
10
+ return array('items' => array('a', 'b'))
11
+ --EXPECT--
12
+ A
13
+ B
library/twig/twig/test/Twig/Tests/Fixtures/tags/filter/with_if_tag.test ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "filter" tag applies the filter on "if" tags
3
+ --TEMPLATE--
4
+ {% filter upper %}
5
+ {% if items %}
6
+ {{ items|join(', ') }}
7
+ {% endif %}
8
+
9
+ {% if items.3 is defined %}
10
+ FOO
11
+ {% else %}
12
+ {{ items.1 }}
13
+ {% endif %}
14
+
15
+ {% if items.3 is defined %}
16
+ FOO
17
+ {% elseif items.1 %}
18
+ {{ items.0 }}
19
+ {% endif %}
20
+
21
+ {% endfilter %}
22
+ --DATA--
23
+ return array('items' => array('a', 'b'))
24
+ --EXPECT--
25
+ A, B
26
+
27
+ B
28
+
29
+ A
library/twig/twig/test/Twig/Tests/Fixtures/tags/for/condition.test ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "for" tag takes a condition
3
+ --TEMPLATE--
4
+ {% for i in 1..5 if i is odd -%}
5
+ {{ loop.index }}.{{ i }}{{ foo.bar }}
6
+ {% endfor %}
7
+ --DATA--
8
+ return array('foo' => array('bar' => 'X'))
9
+ --CONFIG--
10
+ return array('strict_variables' => false)
11
+ --EXPECT--
12
+ 1.1X
13
+ 2.3X
14
+ 3.5X
library/twig/twig/test/Twig/Tests/Fixtures/tags/for/context.test ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "for" tag keeps the context safe
3
+ --TEMPLATE--
4
+ {% for item in items %}
5
+ {% for item in items %}
6
+ * {{ item }}
7
+ {% endfor %}
8
+ * {{ item }}
9
+ {% endfor %}
10
+ --DATA--
11
+ return array('items' => array('a', 'b'))
12
+ --EXPECT--
13
+ * a
14
+ * b
15
+ * a
16
+ * a
17
+ * b
18
+ * b
library/twig/twig/test/Twig/Tests/Fixtures/tags/for/else.test ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "for" tag can use an "else" clause
3
+ --TEMPLATE--
4
+ {% for item in items %}
5
+ * {{ item }}
6
+ {% else %}
7
+ no item
8
+ {% endfor %}
9
+ --DATA--
10
+ return array('items' => array('a', 'b'))
11
+ --EXPECT--
12
+ * a
13
+ * b
14
+ --DATA--
15
+ return array('items' => array())
16
+ --EXPECT--
17
+ no item
18
+ --DATA--
19
+ return array()
20
+ --CONFIG--
21
+ return array('strict_variables' => false)
22
+ --EXPECT--
23
+ no item
library/twig/twig/test/Twig/Tests/Fixtures/tags/for/inner_variables.test ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "for" tag does not reset inner variables
3
+ --TEMPLATE--
4
+ {% for i in 1..2 %}
5
+ {% for j in 0..2 %}
6
+ {{k}}{% set k = k+1 %} {{ loop.parent.loop.index }}
7
+ {% endfor %}
8
+ {% endfor %}
9
+ --DATA--
10
+ return array('k' => 0)
11
+ --EXPECT--
12
+ 0 1
13
+ 1 1
14
+ 2 1
15
+ 3 2
16
+ 4 2
17
+ 5 2
library/twig/twig/test/Twig/Tests/Fixtures/tags/for/keys.test ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "for" tag can iterate over keys
3
+ --TEMPLATE--
4
+ {% for key in items|keys %}
5
+ * {{ key }}
6
+ {% endfor %}
7
+ --DATA--
8
+ return array('items' => array('a', 'b'))
9
+ --EXPECT--
10
+ * 0
11
+ * 1
library/twig/twig/test/Twig/Tests/Fixtures/tags/for/keys_and_values.test ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "for" tag can iterate over keys and values
3
+ --TEMPLATE--
4
+ {% for key, item in items %}
5
+ * {{ key }}/{{ item }}
6
+ {% endfor %}
7
+ --DATA--
8
+ return array('items' => array('a', 'b'))
9
+ --EXPECT--
10
+ * 0/a
11
+ * 1/b
library/twig/twig/test/Twig/Tests/Fixtures/tags/for/loop_context.test ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "for" tag adds a loop variable to the context
3
+ --TEMPLATE--
4
+ {% for item in items %}
5
+ * {{ loop.index }}/{{ loop.index0 }}
6
+ * {{ loop.revindex }}/{{ loop.revindex0 }}
7
+ * {{ loop.first }}/{{ loop.last }}/{{ loop.length }}
8
+
9
+ {% endfor %}
10
+ --DATA--
11
+ return array('items' => array('a', 'b'))
12
+ --EXPECT--
13
+ * 1/0
14
+ * 2/1
15
+ * 1//2
16
+
17
+ * 2/1
18
+ * 1/0
19
+ * /1/2
library/twig/twig/test/Twig/Tests/Fixtures/tags/for/loop_context_local.test ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "for" tag adds a loop variable to the context locally
3
+ --TEMPLATE--
4
+ {% for item in items %}
5
+ {% endfor %}
6
+ {% if loop is not defined %}WORKS{% endif %}
7
+ --DATA--
8
+ return array('items' => array())
9
+ --EXPECT--
10
+ WORKS
library/twig/twig/test/Twig/Tests/Fixtures/tags/for/loop_not_defined.test ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "for" tag
3
+ --TEMPLATE--
4
+ {% for i, item in items if i > 0 %}
5
+ {{ loop.last }}
6
+ {% endfor %}
7
+ --DATA--
8
+ return array('items' => array('a', 'b'))
9
+ --EXCEPTION--
10
+ Twig_Error_Syntax: The "loop.last" variable is not defined when looping with a condition in "index.twig" at line 3.
library/twig/twig/test/Twig/Tests/Fixtures/tags/for/loop_not_defined_cond.test ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "for" tag
3
+ --TEMPLATE--
4
+ {% for i, item in items if loop.last > 0 %}
5
+ {% endfor %}
6
+ --DATA--
7
+ return array('items' => array('a', 'b'))
8
+ --EXCEPTION--
9
+ Twig_Error_Syntax: The "loop" variable cannot be used in a looping condition in "index.twig" at line 2.
library/twig/twig/test/Twig/Tests/Fixtures/tags/for/nested_else.test ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "for" tag can use an "else" clause
3
+ --TEMPLATE--
4
+ {% for item in items %}
5
+ {% for item in items1 %}
6
+ * {{ item }}
7
+ {% else %}
8
+ no {{ item }}
9
+ {% endfor %}
10
+ {% else %}
11
+ no item1
12
+ {% endfor %}
13
+ --DATA--
14
+ return array('items' => array('a', 'b'), 'items1' => array())
15
+ --EXPECT--
16
+ no a
17
+ no b
library/twig/twig/test/Twig/Tests/Fixtures/tags/for/objects.test ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "for" tag iterates over iterable objects
3
+ --TEMPLATE--
4
+ {% for item in items %}
5
+ * {{ item }}
6
+ * {{ loop.index }}/{{ loop.index0 }}
7
+ * {{ loop.first }}
8
+
9
+ {% endfor %}
10
+
11
+ {% for key, value in items %}
12
+ * {{ key }}/{{ value }}
13
+ {% endfor %}
14
+
15
+ {% for key in items|keys %}
16
+ * {{ key }}
17
+ {% endfor %}
18
+ --DATA--
19
+ class ItemsIterator implements Iterator
20
+ {
21
+ protected $values = array('foo' => 'bar', 'bar' => 'foo');
22
+ public function current() { return current($this->values); }
23
+ public function key() { return key($this->values); }
24
+ public function next() { return next($this->values); }
25
+ public function rewind() { return reset($this->values); }
26
+ public function valid() { return false !== current($this->values); }
27
+ }
28
+ return array('items' => new ItemsIterator())
29
+ --EXPECT--
30
+ * bar
31
+ * 1/0
32
+ * 1
33
+
34
+ * foo
35
+ * 2/1
36
+ *
37
+
38
+
39
+ * foo/bar
40
+ * bar/foo
41
+
42
+ * foo
43
+ * bar
library/twig/twig/test/Twig/Tests/Fixtures/tags/for/objects_countable.test ADDED
@@ -0,0 +1,47 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "for" tag iterates over iterable and countable objects
3
+ --TEMPLATE--
4
+ {% for item in items %}
5
+ * {{ item }}
6
+ * {{ loop.index }}/{{ loop.index0 }}
7
+ * {{ loop.revindex }}/{{ loop.revindex0 }}
8
+ * {{ loop.first }}/{{ loop.last }}/{{ loop.length }}
9
+
10
+ {% endfor %}
11
+
12
+ {% for key, value in items %}
13
+ * {{ key }}/{{ value }}
14
+ {% endfor %}
15
+
16
+ {% for key in items|keys %}
17
+ * {{ key }}
18
+ {% endfor %}
19
+ --DATA--
20
+ class ItemsIteratorCountable implements Iterator, Countable
21
+ {
22
+ protected $values = array('foo' => 'bar', 'bar' => 'foo');
23
+ public function current() { return current($this->values); }
24
+ public function key() { return key($this->values); }
25
+ public function next() { return next($this->values); }
26
+ public function rewind() { return reset($this->values); }
27
+ public function valid() { return false !== current($this->values); }
28
+ public function count() { return count($this->values); }
29
+ }
30
+ return array('items' => new ItemsIteratorCountable())
31
+ --EXPECT--
32
+ * bar
33
+ * 1/0
34
+ * 2/1
35
+ * 1//2
36
+
37
+ * foo
38
+ * 2/1
39
+ * 1/0
40
+ * /1/2
41
+
42
+
43
+ * foo/bar
44
+ * bar/foo
45
+
46
+ * foo
47
+ * bar
library/twig/twig/test/Twig/Tests/Fixtures/tags/for/recursive.test ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "for" tags can be nested
3
+ --TEMPLATE--
4
+ {% for key, item in items %}
5
+ * {{ key }} ({{ loop.length }}):
6
+ {% for value in item %}
7
+ * {{ value }} ({{ loop.length }})
8
+ {% endfor %}
9
+ {% endfor %}
10
+ --DATA--
11
+ return array('items' => array('a' => array('a1', 'a2', 'a3'), 'b' => array('b1')))
12
+ --EXPECT--
13
+ * a (2):
14
+ * a1 (3)
15
+ * a2 (3)
16
+ * a3 (3)
17
+ * b (2):
18
+ * b1 (1)
library/twig/twig/test/Twig/Tests/Fixtures/tags/for/values.test ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "for" tag iterates over item values
3
+ --TEMPLATE--
4
+ {% for item in items %}
5
+ * {{ item }}
6
+ {% endfor %}
7
+ --DATA--
8
+ return array('items' => array('a', 'b'))
9
+ --EXPECT--
10
+ * a
11
+ * b
library/twig/twig/test/Twig/Tests/Fixtures/tags/from.test ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ global variables
3
+ --TEMPLATE--
4
+ {% include "included.twig" %}
5
+ {% from "included.twig" import foobar %}
6
+ {{ foobar() }}
7
+ --TEMPLATE(included.twig)--
8
+ {% macro foobar() %}
9
+ called foobar
10
+ {% endmacro %}
11
+ --DATA--
12
+ return array();
13
+ --EXPECT--
14
+ called foobar
library/twig/twig/test/Twig/Tests/Fixtures/tags/if/basic.test ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "if" creates a condition
3
+ --TEMPLATE--
4
+ {% if a is defined %}
5
+ {{ a }}
6
+ {% elseif b is defined %}
7
+ {{ b }}
8
+ {% else %}
9
+ NOTHING
10
+ {% endif %}
11
+ --DATA--
12
+ return array('a' => 'a')
13
+ --EXPECT--
14
+ a
15
+ --DATA--
16
+ return array('b' => 'b')
17
+ --EXPECT--
18
+ b
19
+ --DATA--
20
+ return array()
21
+ --EXPECT--
22
+ NOTHING
library/twig/twig/test/Twig/Tests/Fixtures/tags/if/expression.test ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "if" takes an expression as a test
3
+ --TEMPLATE--
4
+ {% if a < 2 %}
5
+ A1
6
+ {% elseif a > 10 %}
7
+ A2
8
+ {% else %}
9
+ A3
10
+ {% endif %}
11
+ --DATA--
12
+ return array('a' => 1)
13
+ --EXPECT--
14
+ A1
15
+ --DATA--
16
+ return array('a' => 12)
17
+ --EXPECT--
18
+ A2
19
+ --DATA--
20
+ return array('a' => 7)
21
+ --EXPECT--
22
+ A3
library/twig/twig/test/Twig/Tests/Fixtures/tags/include/basic.test ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "include" tag
3
+ --TEMPLATE--
4
+ FOO
5
+ {% include "foo.twig" %}
6
+
7
+ BAR
8
+ --TEMPLATE(foo.twig)--
9
+ FOOBAR
10
+ --DATA--
11
+ return array()
12
+ --EXPECT--
13
+ FOO
14
+
15
+ FOOBAR
16
+ BAR
library/twig/twig/test/Twig/Tests/Fixtures/tags/include/expression.test ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "include" tag allows expressions for the template to include
3
+ --TEMPLATE--
4
+ FOO
5
+ {% include foo %}
6
+
7
+ BAR
8
+ --TEMPLATE(foo.twig)--
9
+ FOOBAR
10
+ --DATA--
11
+ return array('foo' => 'foo.twig')
12
+ --EXPECT--
13
+ FOO
14
+
15
+ FOOBAR
16
+ BAR
library/twig/twig/test/Twig/Tests/Fixtures/tags/include/ignore_missing.test ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "include" tag
3
+ --TEMPLATE--
4
+ {% include ["foo.twig", "bar.twig"] ignore missing %}
5
+ {% include "foo.twig" ignore missing %}
6
+ {% include "foo.twig" ignore missing with {} %}
7
+ {% include "foo.twig" ignore missing with {} only %}
8
+ --DATA--
9
+ return array()
10
+ --EXPECT--
library/twig/twig/test/Twig/Tests/Fixtures/tags/include/missing.test ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "include" tag
3
+ --TEMPLATE--
4
+ {% include "foo.twig" %}
5
+ --DATA--
6
+ return array();
7
+ --EXCEPTION--
8
+ Twig_Error_Loader: Template "foo.twig" is not defined in "index.twig" at line 2.
library/twig/twig/test/Twig/Tests/Fixtures/tags/include/missing_nested.test ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "include" tag
3
+ --TEMPLATE--
4
+ {% extends "base.twig" %}
5
+
6
+ {% block content %}
7
+ {{ parent() }}
8
+ {% endblock %}
9
+ --TEMPLATE(base.twig)--
10
+ {% block content %}
11
+ {% include "foo.twig" %}
12
+ {% endblock %}
13
+ --DATA--
14
+ return array();
15
+ --EXCEPTION--
16
+ Twig_Error_Loader: Template "foo.twig" is not defined in "base.twig" at line 3.
library/twig/twig/test/Twig/Tests/Fixtures/tags/include/only.test ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "include" tag accept variables and only
3
+ --TEMPLATE--
4
+ {% include "foo.twig" %}
5
+ {% include "foo.twig" only %}
6
+ {% include "foo.twig" with {'foo1': 'bar'} %}
7
+ {% include "foo.twig" with {'foo1': 'bar'} only %}
8
+ --TEMPLATE(foo.twig)--
9
+ {% for k, v in _context %}{{ k }},{% endfor %}
10
+ --DATA--
11
+ return array('foo' => 'bar')
12
+ --EXPECT--
13
+ foo,global,_parent,
14
+ global,_parent,
15
+ foo,global,foo1,_parent,
16
+ foo1,global,_parent,
library/twig/twig/test/Twig/Tests/Fixtures/tags/include/template_instance.test ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "include" tag accepts Twig_Template instance
3
+ --TEMPLATE--
4
+ {% include foo %} FOO
5
+ --TEMPLATE(foo.twig)--
6
+ BAR
7
+ --DATA--
8
+ return array('foo' => $twig->loadTemplate('foo.twig'))
9
+ --EXPECT--
10
+ BAR FOO
library/twig/twig/test/Twig/Tests/Fixtures/tags/include/templates_as_array.test ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "include" tag
3
+ --TEMPLATE--
4
+ {% include ["foo.twig", "bar.twig"] %}
5
+ {% include ["bar.twig", "foo.twig"] %}
6
+ --TEMPLATE(foo.twig)--
7
+ foo
8
+ --DATA--
9
+ return array()
10
+ --EXPECT--
11
+ foo
12
+ foo
library/twig/twig/test/Twig/Tests/Fixtures/tags/include/with_variables.test ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "include" tag accept variables
3
+ --TEMPLATE--
4
+ {% include "foo.twig" with {'foo': 'bar'} %}
5
+ {% include "foo.twig" with vars %}
6
+ --TEMPLATE(foo.twig)--
7
+ {{ foo }}
8
+ --DATA--
9
+ return array('vars' => array('foo' => 'bar'))
10
+ --EXPECT--
11
+ bar
12
+ bar
library/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/basic.test ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "extends" tag
3
+ --TEMPLATE--
4
+ {% extends "foo.twig" %}
5
+
6
+ {% block content %}
7
+ FOO
8
+ {% endblock %}
9
+ --TEMPLATE(foo.twig)--
10
+ {% block content %}{% endblock %}
11
+ --DATA--
12
+ return array()
13
+ --EXPECT--
14
+ FOO
library/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/block_expr.test ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ block_expr
3
+ --TEMPLATE--
4
+ {% extends "base.twig" %}
5
+
6
+ {% block element -%}
7
+ Element:
8
+ {{- parent() -}}
9
+ {% endblock %}
10
+ --TEMPLATE(base.twig)--
11
+ {% spaceless %}
12
+ {% block element -%}
13
+ <div>
14
+ {%- if item.children is defined %}
15
+ {%- for item in item.children %}
16
+ {{- block('element') -}}
17
+ {% endfor %}
18
+ {%- endif -%}
19
+ </div>
20
+ {%- endblock %}
21
+ {% endspaceless %}
22
+ --DATA--
23
+ return array(
24
+ 'item' => array(
25
+ 'children' => array(
26
+ null,
27
+ null,
28
+ )
29
+ )
30
+ )
31
+ --EXPECT--
32
+ Element:<div>Element:<div></div>Element:<div></div></div>
library/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/block_expr2.test ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ block_expr2
3
+ --TEMPLATE--
4
+ {% extends "base2.twig" %}
5
+
6
+ {% block element -%}
7
+ Element:
8
+ {{- parent() -}}
9
+ {% endblock %}
10
+ --TEMPLATE(base2.twig)--
11
+ {% extends "base.twig" %}
12
+ --TEMPLATE(base.twig)--
13
+ {% spaceless %}
14
+ {% block element -%}
15
+ <div>
16
+ {%- if item.children is defined %}
17
+ {%- for item in item.children %}
18
+ {{- block('element') -}}
19
+ {% endfor %}
20
+ {%- endif -%}
21
+ </div>
22
+ {%- endblock %}
23
+ {% endspaceless %}
24
+ --DATA--
25
+ return array(
26
+ 'item' => array(
27
+ 'children' => array(
28
+ null,
29
+ null,
30
+ )
31
+ )
32
+ )
33
+ --EXPECT--
34
+ Element:<div>Element:<div></div>Element:<div></div></div>
library/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/conditional.test ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "extends" tag
3
+ --TEMPLATE--
4
+ {% extends standalone ? foo : 'bar.twig' %}
5
+
6
+ {% block content %}{{ parent() }}FOO{% endblock %}
7
+ --TEMPLATE(foo.twig)--
8
+ {% block content %}FOO{% endblock %}
9
+ --TEMPLATE(bar.twig)--
10
+ {% block content %}BAR{% endblock %}
11
+ --DATA--
12
+ return array('foo' => 'foo.twig', 'standalone' => true)
13
+ --EXPECT--
14
+ FOOFOO
library/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/dynamic.test ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "extends" tag
3
+ --TEMPLATE--
4
+ {% extends foo %}
5
+
6
+ {% block content %}
7
+ FOO
8
+ {% endblock %}
9
+ --TEMPLATE(foo.twig)--
10
+ {% block content %}{% endblock %}
11
+ --DATA--
12
+ return array('foo' => 'foo.twig')
13
+ --EXPECT--
14
+ FOO
library/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/empty.test ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "extends" tag
3
+ --TEMPLATE--
4
+ {% extends "foo.twig" %}
5
+ --TEMPLATE(foo.twig)--
6
+ {% block content %}FOO{% endblock %}
7
+ --DATA--
8
+ return array()
9
+ --EXPECT--
10
+ FOO
library/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/extends_as_array.test ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "extends" tag
3
+ --TEMPLATE--
4
+ {% extends ["foo.twig", "bar.twig"] %}
5
+ --TEMPLATE(bar.twig)--
6
+ {% block content %}
7
+ foo
8
+ {% endblock %}
9
+ --DATA--
10
+ return array()
11
+ --EXPECT--
12
+ foo
library/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/extends_as_array_with_empty_name.test ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "extends" tag
3
+ --TEMPLATE--
4
+ {% extends ["", "bar.twig"] %}
5
+ --TEMPLATE(bar.twig)--
6
+ {% block content %}
7
+ foo
8
+ {% endblock %}
9
+ --DATA--
10
+ return array()
11
+ --EXPECT--
12
+ foo
library/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/extends_as_array_with_null_name.test ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "extends" tag
3
+ --TEMPLATE--
4
+ {% extends [null, "bar.twig"] %}
5
+ --TEMPLATE(bar.twig)--
6
+ {% block content %}
7
+ foo
8
+ {% endblock %}
9
+ --DATA--
10
+ return array()
11
+ --EXPECT--
12
+ foo
library/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/multiple.test ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "extends" tag
3
+ --TEMPLATE--
4
+ {% extends "layout.twig" %}{% block content %}{{ parent() }}index {% endblock %}
5
+ --TEMPLATE(layout.twig)--
6
+ {% extends "base.twig" %}{% block content %}{{ parent() }}layout {% endblock %}
7
+ --TEMPLATE(base.twig)--
8
+ {% block content %}base {% endblock %}
9
+ --DATA--
10
+ return array()
11
+ --EXPECT--
12
+ base layout index
library/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/multiple_dynamic.test ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "extends" tag
3
+ --TEMPLATE--
4
+ {% set foo = 1 %}
5
+ {{ include('parent.twig') }}
6
+ {{ include('parent.twig') }}
7
+ {% set foo = 2 %}
8
+ {{ include('parent.twig') }}
9
+ --TEMPLATE(parent.twig)--
10
+ {% extends foo~'_parent.twig' %}{% block content %}{{ parent() }} parent{% endblock %}
11
+ --TEMPLATE(1_parent.twig)--
12
+ {% block content %}1{% endblock %}
13
+ --TEMPLATE(2_parent.twig)--
14
+ {% block content %}2{% endblock %}
15
+ --DATA--
16
+ return array()
17
+ --EXPECT--
18
+ 1 parent
19
+
20
+ 1 parent
21
+
22
+ 2 parent
library/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/nested_blocks.test ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "block" tag
3
+ --TEMPLATE--
4
+ {% extends "foo.twig" %}
5
+
6
+ {% block content %}
7
+ {% block subcontent %}
8
+ {% block subsubcontent %}
9
+ SUBSUBCONTENT
10
+ {% endblock %}
11
+ {% endblock %}
12
+ {% endblock %}
13
+ --TEMPLATE(foo.twig)--
14
+ {% block content %}
15
+ {% block subcontent %}
16
+ SUBCONTENT
17
+ {% endblock %}
18
+ {% endblock %}
19
+ --DATA--
20
+ return array()
21
+ --EXPECT--
22
+ SUBSUBCONTENT
library/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/nested_blocks_parent_only.test ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "block" tag
3
+ --TEMPLATE--
4
+ {% block content %}
5
+ CONTENT
6
+ {%- block subcontent -%}
7
+ SUBCONTENT
8
+ {%- endblock -%}
9
+ ENDCONTENT
10
+ {% endblock %}
11
+ --TEMPLATE(foo.twig)--
12
+ --DATA--
13
+ return array()
14
+ --EXPECT--
15
+ CONTENTSUBCONTENTENDCONTENT
library/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/nested_inheritance.test ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "extends" tag
3
+ --TEMPLATE--
4
+ {% extends "layout.twig" %}
5
+ {% block inside %}INSIDE{% endblock inside %}
6
+ --TEMPLATE(layout.twig)--
7
+ {% extends "base.twig" %}
8
+ {% block body %}
9
+ {% block inside '' %}
10
+ {% endblock body %}
11
+ --TEMPLATE(base.twig)--
12
+ {% block body '' %}
13
+ --DATA--
14
+ return array()
15
+ --EXPECT--
16
+ INSIDE
library/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/parent.test ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "extends" tag
3
+ --TEMPLATE--
4
+ {% extends "foo.twig" %}
5
+
6
+ {% block content %}{{ parent() }}FOO{{ parent() }}{% endblock %}
7
+ --TEMPLATE(foo.twig)--
8
+ {% block content %}BAR{% endblock %}
9
+ --DATA--
10
+ return array()
11
+ --EXPECT--
12
+ BARFOOBAR
library/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/parent_change.test ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "extends" tag
3
+ --TEMPLATE--
4
+ {% extends foo ? 'foo.twig' : 'bar.twig' %}
5
+ --TEMPLATE(foo.twig)--
6
+ FOO
7
+ --TEMPLATE(bar.twig)--
8
+ BAR
9
+ --DATA--
10
+ return array('foo' => true)
11
+ --EXPECT--
12
+ FOO
13
+ --DATA--
14
+ return array('foo' => false)
15
+ --EXPECT--
16
+ BAR
library/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/parent_in_a_block.test ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "extends" tag
3
+ --TEMPLATE--
4
+ {% block content %}
5
+ {% extends "foo.twig" %}
6
+ {% endblock %}
7
+ --EXCEPTION--
8
+ Twig_Error_Syntax: Cannot extend from a block in "index.twig" at line 3.
library/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/parent_isolation.test ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "extends" tag
3
+ --TEMPLATE--
4
+ {% extends "base.twig" %}
5
+ {% block content %}{% include "included.twig" %}{% endblock %}
6
+
7
+ {% block footer %}Footer{% endblock %}
8
+ --TEMPLATE(included.twig)--
9
+ {% extends "base.twig" %}
10
+ {% block content %}Included Content{% endblock %}
11
+ --TEMPLATE(base.twig)--
12
+ {% block content %}Default Content{% endblock %}
13
+
14
+ {% block footer %}Default Footer{% endblock %}
15
+ --DATA--
16
+ return array()
17
+ --EXPECT--
18
+ Included Content
19
+ Default Footer
20
+ Footer
library/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/parent_nested.test ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "extends" tag
3
+ --TEMPLATE--
4
+ {% extends "foo.twig" %}
5
+
6
+ {% block content %}
7
+ {% block inside %}
8
+ INSIDE OVERRIDDEN
9
+ {% endblock %}
10
+
11
+ BEFORE
12
+ {{ parent() }}
13
+ AFTER
14
+ {% endblock %}
15
+ --TEMPLATE(foo.twig)--
16
+ {% block content %}
17
+ BAR
18
+ {% endblock %}
19
+ --DATA--
20
+ return array()
21
+ --EXPECT--
22
+
23
+ INSIDE OVERRIDDEN
24
+
25
+ BEFORE
26
+ BAR
27
+
28
+ AFTER
library/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/parent_without_extends.test ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "parent" tag
3
+ --TEMPLATE--
4
+ {% block content %}
5
+ {{ parent() }}
6
+ {% endblock %}
7
+ --EXCEPTION--
8
+ Twig_Error_Syntax: Calling "parent" on a template that does not extend nor "use" another template is forbidden in "index.twig" at line 3.
library/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/parent_without_extends_but_traits.test ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "parent" tag
3
+ --TEMPLATE--
4
+ {% use 'foo.twig' %}
5
+
6
+ {% block content %}
7
+ {{ parent() }}
8
+ {% endblock %}
9
+ --TEMPLATE(foo.twig)--
10
+ {% block content %}BAR{% endblock %}
11
+ --DATA--
12
+ return array()
13
+ --EXPECT--
14
+ BAR
library/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/template_instance.test ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "extends" tag accepts Twig_Template instance
3
+ --TEMPLATE--
4
+ {% extends foo %}
5
+
6
+ {% block content %}
7
+ {{ parent() }}FOO
8
+ {% endblock %}
9
+ --TEMPLATE(foo.twig)--
10
+ {% block content %}BAR{% endblock %}
11
+ --DATA--
12
+ return array('foo' => $twig->loadTemplate('foo.twig'))
13
+ --EXPECT--
14
+ BARFOO
library/twig/twig/test/Twig/Tests/Fixtures/tags/inheritance/use.test ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "parent" function
3
+ --TEMPLATE--
4
+ {% extends "parent.twig" %}
5
+
6
+ {% use "use1.twig" %}
7
+ {% use "use2.twig" %}
8
+
9
+ {% block content_parent %}
10
+ {{ parent() }}
11
+ {% endblock %}
12
+
13
+ {% block content_use1 %}
14
+ {{ parent() }}
15
+ {% endblock %}
16
+
17
+ {% block content_use2 %}
18
+ {{ parent() }}
19
+ {% endblock %}
20
+
21
+ {% block content %}
22
+ {{ block('content_use1_only') }}
23
+ {{ block('content_use2_only') }}
24
+ {% endblock %}
25
+ --TEMPLATE(parent.twig)--
26
+ {% block content_parent 'content_parent' %}
27
+ {% block content_use1 'content_parent' %}
28
+ {% block content_use2 'content_parent' %}
29
+ {% block content '' %}
30
+ --TEMPLATE(use1.twig)--
31
+ {% block content_use1 'content_use1' %}
32
+ {% block content_use2 'content_use1' %}
33
+ {% block content_use1_only 'content_use1_only' %}
34
+ --TEMPLATE(use2.twig)--
35
+ {% block content_use2 'content_use2' %}
36
+ {% block content_use2_only 'content_use2_only' %}
37
+ --DATA--
38
+ return array()
39
+ --EXPECT--
40
+ content_parent
41
+ content_use1
42
+ content_use2
43
+ content_use1_only
44
+ content_use2_only
library/twig/twig/test/Twig/Tests/Fixtures/tags/macro/basic.test ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "macro" tag
3
+ --TEMPLATE--
4
+ {% import _self as macros %}
5
+
6
+ {{ macros.input('username') }}
7
+ {{ macros.input('password', null, 'password', 1) }}
8
+
9
+ {% macro input(name, value, type, size) %}
10
+ <input type="{{ type|default("text") }}" name="{{ name }}" value="{{ value|e|default('') }}" size="{{ size|default(20) }}">
11
+ {% endmacro %}
12
+ --DATA--
13
+ return array()
14
+ --EXPECT--
15
+ <input type="text" name="username" value="" size="20">
16
+
17
+ <input type="password" name="password" value="" size="1">
library/twig/twig/test/Twig/Tests/Fixtures/tags/macro/endmacro_name.test ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "macro" tag supports name for endmacro
3
+ --TEMPLATE--
4
+ {% import _self as macros %}
5
+
6
+ {{ macros.foo() }}
7
+ {{ macros.bar() }}
8
+
9
+ {% macro foo() %}foo{% endmacro %}
10
+ {% macro bar() %}bar{% endmacro bar %}
11
+ --DATA--
12
+ return array()
13
+ --EXPECT--
14
+ foo
15
+ bar
16
+
library/twig/twig/test/Twig/Tests/Fixtures/tags/macro/external.test ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "macro" tag
3
+ --TEMPLATE--
4
+ {% import 'forms.twig' as forms %}
5
+
6
+ {{ forms.input('username') }}
7
+ {{ forms.input('password', null, 'password', 1) }}
8
+ --TEMPLATE(forms.twig)--
9
+ {% macro input(name, value, type, size) %}
10
+ <input type="{{ type|default("text") }}" name="{{ name }}" value="{{ value|e|default('') }}" size="{{ size|default(20) }}">
11
+ {% endmacro %}
12
+ --DATA--
13
+ return array()
14
+ --EXPECT--
15
+ <input type="text" name="username" value="" size="20">
16
+
17
+ <input type="password" name="password" value="" size="1">
library/twig/twig/test/Twig/Tests/Fixtures/tags/macro/from.test ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "macro" tag
3
+ --TEMPLATE--
4
+ {% from 'forms.twig' import foo %}
5
+ {% from 'forms.twig' import foo as foobar, bar %}
6
+
7
+ {{ foo('foo') }}
8
+ {{ foobar('foo') }}
9
+ {{ bar('foo') }}
10
+ --TEMPLATE(forms.twig)--
11
+ {% macro foo(name) %}foo{{ name }}{% endmacro %}
12
+ {% macro bar(name) %}bar{{ name }}{% endmacro %}
13
+ --DATA--
14
+ return array()
15
+ --EXPECT--
16
+ foofoo
17
+ foofoo
18
+ barfoo
library/twig/twig/test/Twig/Tests/Fixtures/tags/macro/from_with_reserved_name.test ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "from" tag with reserved name
3
+ --TEMPLATE--
4
+ {% from 'forms.twig' import templateName %}
5
+ --TEMPLATE(forms.twig)--
6
+ --DATA--
7
+ return array()
8
+ --EXCEPTION--
9
+ Twig_Error_Syntax: "templateName" cannot be an imported macro as it is a reserved keyword in "index.twig" at line 2.
library/twig/twig/test/Twig/Tests/Fixtures/tags/macro/global.test ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "macro" tag
3
+ --TEMPLATE--
4
+ {% from 'forms.twig' import foo %}
5
+
6
+ {{ foo('foo') }}
7
+ {{ foo() }}
8
+ --TEMPLATE(forms.twig)--
9
+ {% macro foo(name) %}{{ name|default('foo') }}{{ global }}{% endmacro %}
10
+ --DATA--
11
+ return array()
12
+ --EXPECT--
13
+ fooglobal
14
+ fooglobal
library/twig/twig/test/Twig/Tests/Fixtures/tags/macro/import_with_reserved_nam.test ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "from" tag with reserved name
3
+ --TEMPLATE--
4
+ {% import 'forms.twig' as macros %}
5
+
6
+ {{ macros.parent() }}
7
+ --TEMPLATE(forms.twig)--
8
+ --DATA--
9
+ return array()
10
+ --EXCEPTION--
11
+ Twig_Error_Syntax: "parent" cannot be called as macro as it is a reserved keyword in "index.twig" at line 4.
library/twig/twig/test/Twig/Tests/Fixtures/tags/macro/reserved_name.test ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "macro" tag with reserved name
3
+ --TEMPLATE--
4
+ {% macro parent(arg1, arg2) %}
5
+ parent
6
+ {% endmacro %}
7
+ --DATA--
8
+ return array()
9
+ --EXCEPTION--
10
+ Twig_Error_Syntax: "parent" cannot be used as a macro name as it is a reserved keyword in "index.twig" at line 2.
library/twig/twig/test/Twig/Tests/Fixtures/tags/macro/self_import.test ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "macro" tag
3
+ --TEMPLATE--
4
+ {% import _self as forms %}
5
+
6
+ {{ forms.input('username') }}
7
+ {{ forms.input('password', null, 'password', 1) }}
8
+
9
+ {% macro input(name, value, type, size) %}
10
+ <input type="{{ type|default("text") }}" name="{{ name }}" value="{{ value|e|default('') }}" size="{{ size|default(20) }}">
11
+ {% endmacro %}
12
+ --DATA--
13
+ return array()
14
+ --EXPECT--
15
+ <input type="text" name="username" value="" size="20">
16
+
17
+ <input type="password" name="password" value="" size="1">
library/twig/twig/test/Twig/Tests/Fixtures/tags/macro/special_chars.test ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "§" as a macro name
3
+ --TEMPLATE--
4
+ {% import _self as macros %}
5
+
6
+ {{ macros.§('foo') }}
7
+
8
+ {% macro §(foo) %}
9
+ §{{ foo }}§
10
+ {% endmacro %}
11
+ --DATA--
12
+ return array()
13
+ --EXPECT--
14
+ §foo§
library/twig/twig/test/Twig/Tests/Fixtures/tags/macro/super_globals.test ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ Super globals as macro arguments
3
+ --TEMPLATE--
4
+ {% import _self as macros %}
5
+
6
+ {{ macros.foo('foo') }}
7
+
8
+ {% macro foo(GET) %}
9
+ {{ GET }}
10
+ {% endmacro %}
11
+ --DATA--
12
+ return array()
13
+ --EXPECT--
14
+ foo
library/twig/twig/test/Twig/Tests/Fixtures/tags/raw/basic.legacy.test ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "raw" tag
3
+ --TEMPLATE--
4
+ {% raw %}
5
+ {{ foo }}
6
+ {% endraw %}
7
+ --DATA--
8
+ return array()
9
+ --EXPECT--
10
+ {{ foo }}
library/twig/twig/test/Twig/Tests/Fixtures/tags/raw/mixed_usage_with_raw.legacy.test ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "raw" tag
3
+ --TEMPLATE--
4
+ {% raw %}
5
+ {{ foo }}
6
+ {% endverbatim %}
7
+ --DATA--
8
+ return array()
9
+ --EXCEPTION--
10
+ Twig_Error_Syntax: Unexpected end of file: Unclosed "raw" block in "index.twig" at line 2.
library/twig/twig/test/Twig/Tests/Fixtures/tags/raw/whitespace_control.legacy.test ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "raw" tag
3
+ --TEMPLATE--
4
+ 1***
5
+
6
+ {%- raw %}
7
+ {{ 'bla' }}
8
+ {% endraw %}
9
+
10
+ 1***
11
+ 2***
12
+
13
+ {%- raw -%}
14
+ {{ 'bla' }}
15
+ {% endraw %}
16
+
17
+ 2***
18
+ 3***
19
+
20
+ {%- raw -%}
21
+ {{ 'bla' }}
22
+ {% endraw -%}
23
+
24
+ 3***
25
+ 4***
26
+
27
+ {%- raw -%}
28
+ {{ 'bla' }}
29
+ {%- endraw %}
30
+
31
+ 4***
32
+ 5***
33
+
34
+ {%- raw -%}
35
+ {{ 'bla' }}
36
+ {%- endraw -%}
37
+
38
+ 5***
39
+ --DATA--
40
+ return array()
41
+ --EXPECT--
42
+ 1***
43
+ {{ 'bla' }}
44
+
45
+
46
+ 1***
47
+ 2***{{ 'bla' }}
48
+
49
+
50
+ 2***
51
+ 3***{{ 'bla' }}
52
+ 3***
53
+ 4***{{ 'bla' }}
54
+
55
+ 4***
56
+ 5***{{ 'bla' }}5***
library/twig/twig/test/Twig/Tests/Fixtures/tags/sandbox/not_valid1.test ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ sandbox tag
3
+ --TEMPLATE--
4
+ {%- sandbox %}
5
+ {%- include "foo.twig" %}
6
+ a
7
+ {%- endsandbox %}
8
+ --TEMPLATE(foo.twig)--
9
+ foo
10
+ --EXCEPTION--
11
+ Twig_Error_Syntax: Only "include" tags are allowed within a "sandbox" section in "index.twig" at line 4.
library/twig/twig/test/Twig/Tests/Fixtures/tags/sandbox/not_valid2.test ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ sandbox tag
3
+ --TEMPLATE--
4
+ {%- sandbox %}
5
+ {%- include "foo.twig" %}
6
+
7
+ {% if 1 %}
8
+ {%- include "foo.twig" %}
9
+ {% endif %}
10
+ {%- endsandbox %}
11
+ --TEMPLATE(foo.twig)--
12
+ foo
13
+ --EXCEPTION--
14
+ Twig_Error_Syntax: Only "include" tags are allowed within a "sandbox" section in "index.twig" at line 5.
library/twig/twig/test/Twig/Tests/Fixtures/tags/sandbox/simple.test ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ sandbox tag
3
+ --TEMPLATE--
4
+ {%- sandbox %}
5
+ {%- include "foo.twig" %}
6
+ {%- endsandbox %}
7
+
8
+ {%- sandbox %}
9
+ {%- include "foo.twig" %}
10
+ {%- include "foo.twig" %}
11
+ {%- endsandbox %}
12
+
13
+ {%- sandbox %}{% include "foo.twig" %}{% endsandbox %}
14
+ --TEMPLATE(foo.twig)--
15
+ foo
16
+ --DATA--
17
+ return array()
18
+ --EXPECT--
19
+ foo
20
+ foo
21
+ foo
22
+ foo
library/twig/twig/test/Twig/Tests/Fixtures/tags/set/basic.test ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "set" tag
3
+ --TEMPLATE--
4
+ {% set foo = 'foo' %}
5
+ {% set bar = 'foo<br />' %}
6
+
7
+ {{ foo }}
8
+ {{ bar }}
9
+
10
+ {% set foo, bar = 'foo', 'bar' %}
11
+
12
+ {{ foo }}{{ bar }}
13
+ --DATA--
14
+ return array()
15
+ --EXPECT--
16
+ foo
17
+ foo&lt;br /&gt;
18
+
19
+
20
+ foobar
library/twig/twig/test/Twig/Tests/Fixtures/tags/set/capture-empty.test ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "set" tag block empty capture
3
+ --TEMPLATE--
4
+ {% set foo %}{% endset %}
5
+
6
+ {% if foo %}FAIL{% endif %}
7
+ --DATA--
8
+ return array()
9
+ --EXPECT--
library/twig/twig/test/Twig/Tests/Fixtures/tags/set/capture.test ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "set" tag block capture
3
+ --TEMPLATE--
4
+ {% set foo %}f<br />o<br />o{% endset %}
5
+
6
+ {{ foo }}
7
+ --DATA--
8
+ return array()
9
+ --EXPECT--
10
+ f<br />o<br />o
library/twig/twig/test/Twig/Tests/Fixtures/tags/set/expression.test ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "set" tag
3
+ --TEMPLATE--
4
+ {% set foo, bar = 'foo' ~ 'bar', 'bar' ~ 'foo' %}
5
+
6
+ {{ foo }}
7
+ {{ bar }}
8
+ --DATA--
9
+ return array()
10
+ --EXPECT--
11
+ foobar
12
+ barfoo
library/twig/twig/test/Twig/Tests/Fixtures/tags/spaceless/simple.test ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "spaceless" tag removes whites between HTML tags
3
+ --TEMPLATE--
4
+ {% spaceless %}
5
+
6
+ <div> <div> foo </div> </div>
7
+
8
+ {% endspaceless %}
9
+ --DATA--
10
+ return array()
11
+ --EXPECT--
12
+ <div><div> foo </div></div>
library/twig/twig/test/Twig/Tests/Fixtures/tags/special_chars.test ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "§" custom tag
3
+ --TEMPLATE--
4
+ {% § %}
5
+ --DATA--
6
+ return array()
7
+ --EXPECT--
8
+ §
library/twig/twig/test/Twig/Tests/Fixtures/tags/trim_block.test ADDED
@@ -0,0 +1,74 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ Whitespace trimming on tags.
3
+ --TEMPLATE--
4
+ {{ 5 * '{#-'|length }}
5
+ {{ '{{-'|length * 5 + '{%-'|length }}
6
+
7
+ Trim on control tag:
8
+ {% for i in range(1, 9) -%}
9
+ {{ i }}
10
+ {%- endfor %}
11
+
12
+
13
+ Trim on output tag:
14
+ {% for i in range(1, 9) %}
15
+ {{- i -}}
16
+ {% endfor %}
17
+
18
+
19
+ Trim comments:
20
+
21
+ {#- Invisible -#}
22
+
23
+ After the comment.
24
+
25
+ Trim leading space:
26
+ {% if leading %}
27
+
28
+ {{- leading }}
29
+ {% endif %}
30
+
31
+ {%- if leading %}
32
+ {{- leading }}
33
+
34
+ {%- endif %}
35
+
36
+
37
+ Trim trailing space:
38
+ {% if trailing -%}
39
+ {{ trailing -}}
40
+
41
+ {% endif -%}
42
+
43
+ Combined:
44
+
45
+ {%- if both -%}
46
+ <ul>
47
+ <li> {{- both -}} </li>
48
+ </ul>
49
+
50
+ {%- endif -%}
51
+
52
+ end
53
+ --DATA--
54
+ return array('leading' => 'leading space', 'trailing' => 'trailing space', 'both' => 'both')
55
+ --EXPECT--
56
+ 15
57
+ 18
58
+
59
+ Trim on control tag:
60
+ 123456789
61
+
62
+ Trim on output tag:
63
+ 123456789
64
+
65
+ Trim comments:After the comment.
66
+
67
+ Trim leading space:
68
+ leading space
69
+ leading space
70
+
71
+ Trim trailing space:
72
+ trailing spaceCombined:<ul>
73
+ <li>both</li>
74
+ </ul>end
library/twig/twig/test/Twig/Tests/Fixtures/tags/use/aliases.test ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "use" tag
3
+ --TEMPLATE--
4
+ {% use "blocks.twig" with content as foo %}
5
+
6
+ {{ block('foo') }}
7
+ --TEMPLATE(blocks.twig)--
8
+ {% block content 'foo' %}
9
+ --DATA--
10
+ return array()
11
+ --EXPECT--
12
+ foo
library/twig/twig/test/Twig/Tests/Fixtures/tags/use/basic.test ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "use" tag
3
+ --TEMPLATE--
4
+ {% use "blocks.twig" %}
5
+
6
+ {{ block('content') }}
7
+ --TEMPLATE(blocks.twig)--
8
+ {% block content 'foo' %}
9
+ --DATA--
10
+ return array()
11
+ --EXPECT--
12
+ foo
library/twig/twig/test/Twig/Tests/Fixtures/tags/use/deep.test ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "use" tag
3
+ --TEMPLATE--
4
+ {% use "foo.twig" %}
5
+
6
+ {{ block('content') }}
7
+ {{ block('foo') }}
8
+ {{ block('bar') }}
9
+ --TEMPLATE(foo.twig)--
10
+ {% use "bar.twig" %}
11
+
12
+ {% block content 'foo' %}
13
+ {% block foo 'foo' %}
14
+ --TEMPLATE(bar.twig)--
15
+ {% block content 'bar' %}
16
+ {% block bar 'bar' %}
17
+ --DATA--
18
+ return array()
19
+ --EXPECT--
20
+ foo
21
+ foo
22
+ bar
library/twig/twig/test/Twig/Tests/Fixtures/tags/use/deep_empty.test ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "use" tag
3
+ --TEMPLATE--
4
+ {% use "foo.twig" %}
5
+ --TEMPLATE(foo.twig)--
6
+ {% use "bar.twig" %}
7
+ --TEMPLATE(bar.twig)--
8
+ --DATA--
9
+ return array()
10
+ --EXPECT--
library/twig/twig/test/Twig/Tests/Fixtures/tags/use/inheritance.test ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "use" tag
3
+ --TEMPLATE--
4
+ {% use "parent.twig" %}
5
+
6
+ {{ block('container') }}
7
+ --TEMPLATE(parent.twig)--
8
+ {% use "ancestor.twig" %}
9
+
10
+ {% block sub_container %}
11
+ <div class="overridden_sub_container">overridden sub_container</div>
12
+ {% endblock %}
13
+ --TEMPLATE(ancestor.twig)--
14
+ {% block container %}
15
+ <div class="container">{{ block('sub_container') }}</div>
16
+ {% endblock %}
17
+
18
+ {% block sub_container %}
19
+ <div class="sub_container">sub_container</div>
20
+ {% endblock %}
21
+ --DATA--
22
+ return array()
23
+ --EXPECT--
24
+ <div class="container"> <div class="overridden_sub_container">overridden sub_container</div>
25
+ </div>
library/twig/twig/test/Twig/Tests/Fixtures/tags/use/inheritance2.test ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "use" tag
3
+ --TEMPLATE--
4
+ {% use "ancestor.twig" %}
5
+ {% use "parent.twig" %}
6
+
7
+ {{ block('container') }}
8
+ --TEMPLATE(parent.twig)--
9
+ {% block sub_container %}
10
+ <div class="overridden_sub_container">overridden sub_container</div>
11
+ {% endblock %}
12
+ --TEMPLATE(ancestor.twig)--
13
+ {% block container %}
14
+ <div class="container">{{ block('sub_container') }}</div>
15
+ {% endblock %}
16
+
17
+ {% block sub_container %}
18
+ <div class="sub_container">sub_container</div>
19
+ {% endblock %}
20
+ --DATA--
21
+ return array()
22
+ --EXPECT--
23
+ <div class="container"> <div class="overridden_sub_container">overridden sub_container</div>
24
+ </div>
library/twig/twig/test/Twig/Tests/Fixtures/tags/use/multiple.test ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "use" tag
3
+ --TEMPLATE--
4
+ {% use "foo.twig" %}
5
+ {% use "bar.twig" %}
6
+
7
+ {{ block('content') }}
8
+ {{ block('foo') }}
9
+ {{ block('bar') }}
10
+ --TEMPLATE(foo.twig)--
11
+ {% block content 'foo' %}
12
+ {% block foo 'foo' %}
13
+ --TEMPLATE(bar.twig)--
14
+ {% block content 'bar' %}
15
+ {% block bar 'bar' %}
16
+ --DATA--
17
+ return array()
18
+ --EXPECT--
19
+ bar
20
+ foo
21
+ bar
library/twig/twig/test/Twig/Tests/Fixtures/tags/use/multiple_aliases.test ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "use" tag
3
+ --TEMPLATE--
4
+ {% use "foo.twig" with content as foo_content %}
5
+ {% use "bar.twig" %}
6
+
7
+ {{ block('content') }}
8
+ {{ block('foo') }}
9
+ {{ block('bar') }}
10
+ {{ block('foo_content') }}
11
+ --TEMPLATE(foo.twig)--
12
+ {% block content 'foo' %}
13
+ {% block foo 'foo' %}
14
+ --TEMPLATE(bar.twig)--
15
+ {% block content 'bar' %}
16
+ {% block bar 'bar' %}
17
+ --DATA--
18
+ return array()
19
+ --EXPECT--
20
+ bar
21
+ foo
22
+ bar
23
+ foo
library/twig/twig/test/Twig/Tests/Fixtures/tags/use/parent_block.test ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "use" tag
3
+ --TEMPLATE--
4
+ {% use 'file2.html.twig' with foobar as base_base_foobar %}
5
+ {% block foobar %}
6
+ {{- block('base_base_foobar') -}}
7
+ Content of block (second override)
8
+ {% endblock foobar %}
9
+ --TEMPLATE(file2.html.twig)--
10
+ {% use 'file1.html.twig' with foobar as base_foobar %}
11
+ {% block foobar %}
12
+ {{- block('base_foobar') -}}
13
+ Content of block (first override)
14
+ {% endblock foobar %}
15
+ --TEMPLATE(file1.html.twig)--
16
+ {% block foobar -%}
17
+ Content of block
18
+ {% endblock foobar %}
19
+ --DATA--
20
+ return array()
21
+ --EXPECT--
22
+ Content of block
23
+ Content of block (first override)
24
+ Content of block (second override)
library/twig/twig/test/Twig/Tests/Fixtures/tags/use/parent_block2.test ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "use" tag
3
+ --TEMPLATE--
4
+ {% use 'file2.html.twig'%}
5
+ {% block foobar %}
6
+ {{- parent() -}}
7
+ Content of block (second override)
8
+ {% endblock foobar %}
9
+ --TEMPLATE(file2.html.twig)--
10
+ {% use 'file1.html.twig' %}
11
+ {% block foobar %}
12
+ {{- parent() -}}
13
+ Content of block (first override)
14
+ {% endblock foobar %}
15
+ --TEMPLATE(file1.html.twig)--
16
+ {% block foobar -%}
17
+ Content of block
18
+ {% endblock foobar %}
19
+ --DATA--
20
+ return array()
21
+ --EXPECT--
22
+ Content of block
23
+ Content of block (first override)
24
+ Content of block (second override)
library/twig/twig/test/Twig/Tests/Fixtures/tags/use/parent_block3.test ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "use" tag
3
+ --TEMPLATE--
4
+ {% use 'file2.html.twig' %}
5
+ {% use 'file1.html.twig' with foo %}
6
+ {% block foo %}
7
+ {{- parent() -}}
8
+ Content of foo (second override)
9
+ {% endblock foo %}
10
+ {% block bar %}
11
+ {{- parent() -}}
12
+ Content of bar (second override)
13
+ {% endblock bar %}
14
+ --TEMPLATE(file2.html.twig)--
15
+ {% use 'file1.html.twig' %}
16
+ {% block foo %}
17
+ {{- parent() -}}
18
+ Content of foo (first override)
19
+ {% endblock foo %}
20
+ {% block bar %}
21
+ {{- parent() -}}
22
+ Content of bar (first override)
23
+ {% endblock bar %}
24
+ --TEMPLATE(file1.html.twig)--
25
+ {% block foo -%}
26
+ Content of foo
27
+ {% endblock foo %}
28
+ {% block bar -%}
29
+ Content of bar
30
+ {% endblock bar %}
31
+ --DATA--
32
+ return array()
33
+ --EXPECT--
34
+ Content of foo
35
+ Content of foo (first override)
36
+ Content of foo (second override)
37
+ Content of bar
38
+ Content of bar (second override)
library/twig/twig/test/Twig/Tests/Fixtures/tags/verbatim/basic.test ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "verbatim" tag
3
+ --TEMPLATE--
4
+ {% verbatim %}
5
+ {{ foo }}
6
+ {% endverbatim %}
7
+ --DATA--
8
+ return array()
9
+ --EXPECT--
10
+ {{ foo }}
library/twig/twig/test/Twig/Tests/Fixtures/tags/verbatim/mixed_usage_with_raw.test ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "verbatim" tag
3
+ --TEMPLATE--
4
+ {% verbatim %}
5
+ {{ foo }}
6
+ {% endraw %}
7
+ --DATA--
8
+ return array()
9
+ --EXCEPTION--
10
+ Twig_Error_Syntax: Unexpected end of file: Unclosed "verbatim" block in "index.twig" at line 2.
library/twig/twig/test/Twig/Tests/Fixtures/tags/verbatim/whitespace_control.test ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "verbatim" tag
3
+ --TEMPLATE--
4
+ 1***
5
+
6
+ {%- verbatim %}
7
+ {{ 'bla' }}
8
+ {% endverbatim %}
9
+
10
+ 1***
11
+ 2***
12
+
13
+ {%- verbatim -%}
14
+ {{ 'bla' }}
15
+ {% endverbatim %}
16
+
17
+ 2***
18
+ 3***
19
+
20
+ {%- verbatim -%}
21
+ {{ 'bla' }}
22
+ {% endverbatim -%}
23
+
24
+ 3***
25
+ 4***
26
+
27
+ {%- verbatim -%}
28
+ {{ 'bla' }}
29
+ {%- endverbatim %}
30
+
31
+ 4***
32
+ 5***
33
+
34
+ {%- verbatim -%}
35
+ {{ 'bla' }}
36
+ {%- endverbatim -%}
37
+
38
+ 5***
39
+ --DATA--
40
+ return array()
41
+ --EXPECT--
42
+ 1***
43
+ {{ 'bla' }}
44
+
45
+
46
+ 1***
47
+ 2***{{ 'bla' }}
48
+
49
+
50
+ 2***
51
+ 3***{{ 'bla' }}
52
+ 3***
53
+ 4***{{ 'bla' }}
54
+
55
+ 4***
56
+ 5***{{ 'bla' }}5***
library/twig/twig/test/Twig/Tests/Fixtures/tags/with/basic.test ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "with" tag
3
+ --TEMPLATE--
4
+ {% with %}
5
+ {% set bar = 'BAZ' %}
6
+ {{ foo }}{{ bar }}
7
+ {% endwith %}
8
+ {{ foo }}{{ bar }}
9
+ --DATA--
10
+ return array('foo' => 'foo', 'bar' => 'bar')
11
+ --EXPECT--
12
+ fooBAZ
13
+ foobar
library/twig/twig/test/Twig/Tests/Fixtures/tags/with/expression.test ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "with" tag with expression
3
+ --TEMPLATE--
4
+ {% with {foo: 'foo', bar: 'BAZ'} %}
5
+ {{ foo }}{{ bar }}
6
+ {% endwith %}
7
+ --DATA--
8
+ return array('foo' => 'baz')
9
+ --EXPECT--
10
+ fooBAZ
library/twig/twig/test/Twig/Tests/Fixtures/tags/with/nested.test ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ nested "with" tags
3
+ --TEMPLATE--
4
+ {% set foo, bar = 'foo', 'bar' %}
5
+ {% with {bar: 'BAZ'} %}
6
+ {% with {foo: 'FOO'} %}
7
+ {{ foo }}{{ bar }}
8
+ {% endwith %}
9
+ {% endwith %}
10
+ {{ foo }}{{ bar }}
11
+ --DATA--
12
+ return array()
13
+ --EXPECT--
14
+ FOOBAZ
15
+ foobar
library/twig/twig/test/Twig/Tests/Fixtures/tags/with/with_no_hash.test ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "with" tag with an expression that is not a hash
3
+ --TEMPLATE--
4
+ {% with vars %}
5
+ {{ foo }}{{ bar }}
6
+ {% endwith %}
7
+ --DATA--
8
+ return array('vars' => 'no-hash')
9
+ --EXCEPTION--
10
+ Twig_Error_Runtime: Variables passed to the "with" tag must be a hash in "index.twig" at line 2.
library/twig/twig/test/Twig/Tests/Fixtures/tags/with/with_only.test ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "with" tag with expression and only
3
+ --TEMPLATE--
4
+ {% with {foo: 'foo', bar: 'BAZ'} only %}
5
+ {{ foo }}{{ bar }}{{ baz }}
6
+ {% endwith %}
7
+ --DATA--
8
+ return array('foo' => 'baz', 'baz' => 'baz')
9
+ --EXCEPTION--
10
+ Twig_Error_Runtime: Variable "baz" does not exist in "index.twig" at line 3.
library/twig/twig/test/Twig/Tests/Fixtures/tests/array.test ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ array index test
3
+ --TEMPLATE--
4
+ {% for key, value in days %}
5
+ {{ key }}
6
+ {% endfor %}
7
+ --DATA--
8
+ return array('days' => array(
9
+ 1 => array('money' => 9),
10
+ 2 => array('money' => 21),
11
+ 3 => array('money' => 38),
12
+ 4 => array('money' => 6),
13
+ 18 => array('money' => 6),
14
+ 19 => array('money' => 3),
15
+ 31 => array('money' => 11),
16
+ ));
17
+ --EXPECT--
18
+ 1
19
+ 2
20
+ 3
21
+ 4
22
+ 18
23
+ 19
24
+ 31
library/twig/twig/test/Twig/Tests/Fixtures/tests/constant.test ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "const" test
3
+ --TEMPLATE--
4
+ {{ 8 is constant('E_NOTICE') ? 'ok' : 'no' }}
5
+ {{ 'bar' is constant('TwigTestFoo::BAR_NAME') ? 'ok' : 'no' }}
6
+ {{ value is constant('TwigTestFoo::BAR_NAME') ? 'ok' : 'no' }}
7
+ {{ 2 is constant('ARRAY_AS_PROPS', object) ? 'ok' : 'no' }}
8
+ --DATA--
9
+ return array('value' => 'bar', 'object' => new ArrayObject(array('hi')));
10
+ --EXPECT--
11
+ ok
12
+ ok
13
+ ok
14
+ ok
library/twig/twig/test/Twig/Tests/Fixtures/tests/defined.test ADDED
@@ -0,0 +1,129 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "defined" test
3
+ --TEMPLATE--
4
+ {{ definedVar is defined ? 'ok' : 'ko' }}
5
+ {{ definedVar is not defined ? 'ko' : 'ok' }}
6
+ {{ undefinedVar is defined ? 'ko' : 'ok' }}
7
+ {{ undefinedVar is not defined ? 'ok' : 'ko' }}
8
+ {{ zeroVar is defined ? 'ok' : 'ko' }}
9
+ {{ nullVar is defined ? 'ok' : 'ko' }}
10
+ {{ nested.definedVar is defined ? 'ok' : 'ko' }}
11
+ {{ nested['definedVar'] is defined ? 'ok' : 'ko' }}
12
+ {{ nested.definedVar is not defined ? 'ko' : 'ok' }}
13
+ {{ nested.undefinedVar is defined ? 'ko' : 'ok' }}
14
+ {{ nested['undefinedVar'] is defined ? 'ko' : 'ok' }}
15
+ {{ nested.undefinedVar is not defined ? 'ok' : 'ko' }}
16
+ {{ nested.zeroVar is defined ? 'ok' : 'ko' }}
17
+ {{ nested.nullVar is defined ? 'ok' : 'ko' }}
18
+ {{ nested.definedArray.0 is defined ? 'ok' : 'ko' }}
19
+ {{ nested['definedArray'][0] is defined ? 'ok' : 'ko' }}
20
+ {{ object.foo is defined ? 'ok' : 'ko' }}
21
+ {{ object.undefinedMethod is defined ? 'ko' : 'ok' }}
22
+ {{ object.getFoo() is defined ? 'ok' : 'ko' }}
23
+ {{ object.getFoo('a') is defined ? 'ok' : 'ko' }}
24
+ {{ object.undefinedMethod() is defined ? 'ko' : 'ok' }}
25
+ {{ object.undefinedMethod('a') is defined ? 'ko' : 'ok' }}
26
+ {{ object.self.foo is defined ? 'ok' : 'ko' }}
27
+ {{ object.self.undefinedMethod is defined ? 'ko' : 'ok' }}
28
+ {{ object.undefinedMethod.self is defined ? 'ko' : 'ok' }}
29
+ {{ 0 is defined ? 'ok' : 'ko' }}
30
+ {{ "foo" is defined ? 'ok' : 'ko' }}
31
+ {{ true is defined ? 'ok' : 'ko' }}
32
+ {{ false is defined ? 'ok' : 'ko' }}
33
+ {{ null is defined ? 'ok' : 'ko' }}
34
+ {{ [1, 2] is defined ? 'ok' : 'ko' }}
35
+ {{ { foo: "bar" } is defined ? 'ok' : 'ko' }}
36
+ --DATA--
37
+ return array(
38
+ 'definedVar' => 'defined',
39
+ 'zeroVar' => 0,
40
+ 'nullVar' => null,
41
+ 'nested' => array(
42
+ 'definedVar' => 'defined',
43
+ 'zeroVar' => 0,
44
+ 'nullVar' => null,
45
+ 'definedArray' => array(0),
46
+ ),
47
+ 'object' => new TwigTestFoo(),
48
+ );
49
+ --EXPECT--
50
+ ok
51
+ ok
52
+ ok
53
+ ok
54
+ ok
55
+ ok
56
+ ok
57
+ ok
58
+ ok
59
+ ok
60
+ ok
61
+ ok
62
+ ok
63
+ ok
64
+ ok
65
+ ok
66
+ ok
67
+ ok
68
+ ok
69
+ ok
70
+ ok
71
+ ok
72
+ ok
73
+ ok
74
+ ok
75
+ ok
76
+ ok
77
+ ok
78
+ ok
79
+ ok
80
+ ok
81
+ ok
82
+ --DATA--
83
+ return array(
84
+ 'definedVar' => 'defined',
85
+ 'zeroVar' => 0,
86
+ 'nullVar' => null,
87
+ 'nested' => array(
88
+ 'definedVar' => 'defined',
89
+ 'zeroVar' => 0,
90
+ 'nullVar' => null,
91
+ 'definedArray' => array(0),
92
+ ),
93
+ 'object' => new TwigTestFoo(),
94
+ );
95
+ --CONFIG--
96
+ return array('strict_variables' => false)
97
+ --EXPECT--
98
+ ok
99
+ ok
100
+ ok
101
+ ok
102
+ ok
103
+ ok
104
+ ok
105
+ ok
106
+ ok
107
+ ok
108
+ ok
109
+ ok
110
+ ok
111
+ ok
112
+ ok
113
+ ok
114
+ ok
115
+ ok
116
+ ok
117
+ ok
118
+ ok
119
+ ok
120
+ ok
121
+ ok
122
+ ok
123
+ ok
124
+ ok
125
+ ok
126
+ ok
127
+ ok
128
+ ok
129
+ ok
library/twig/twig/test/Twig/Tests/Fixtures/tests/defined_for_attribute.test ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "defined" support for attribute
3
+ --TEMPLATE--
4
+ {{ attribute(nested, "definedVar") is defined ? 'ok' : 'ko' }}
5
+ {{ attribute(nested, "undefinedVar") is not defined ? 'ok' : 'ko' }}
6
+ {{ attribute(nested, definedVarName) is defined ? 'ok' : 'ko' }}
7
+ {{ attribute(nested, undefinedVarName) is not defined ? 'ok' : 'ko' }}
8
+ --DATA--
9
+ return array(
10
+ 'nested' => array(
11
+ 'definedVar' => 'defined',
12
+ ),
13
+ 'definedVarName' => 'definedVar',
14
+ 'undefinedVarName' => 'undefinedVar',
15
+ );
16
+ --EXPECT--
17
+ ok
18
+ ok
19
+ ok
20
+ ok
21
+ --DATA--
22
+ return array(
23
+ 'nested' => array(
24
+ 'definedVar' => 'defined',
25
+ ),
26
+ 'definedVarName' => 'definedVar',
27
+ 'undefinedVarName' => 'undefinedVar',
28
+ );
29
+ --CONFIG--
30
+ return array('strict_variables' => false)
31
+ --EXPECT--
32
+ ok
33
+ ok
34
+ ok
35
+ ok
library/twig/twig/test/Twig/Tests/Fixtures/tests/defined_for_blocks.test ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "defined" support for blocks
3
+ --TEMPLATE--
4
+ {% extends 'parent' %}
5
+ {% block icon %}icon{% endblock %}
6
+ {% block body %}
7
+ {{ parent() }}
8
+ {{ block('foo') is defined ? 'ok' : 'ko' }}
9
+ {{ block('footer') is defined ? 'ok' : 'ko' }}
10
+ {{ block('icon') is defined ? 'ok' : 'ko' }}
11
+ {{ block('block1') is defined ? 'ok' : 'ko' }}
12
+ {%- embed 'embed' %}
13
+ {% block content %}content{% endblock %}
14
+ {% endembed %}
15
+ {% endblock %}
16
+ {% use 'blocks' %}
17
+ --TEMPLATE(parent)--
18
+ {% block body %}
19
+ {{ block('icon') is defined ? 'ok' : 'ko' -}}
20
+ {% endblock %}
21
+ {% block footer %}{% endblock %}
22
+ --TEMPLATE(embed)--
23
+ {{ block('icon') is defined ? 'ok' : 'ko' }}
24
+ {{ block('content') is defined ? 'ok' : 'ko' }}
25
+ {{ block('block1') is defined ? 'ok' : 'ko' }}
26
+ --TEMPLATE(blocks)--
27
+ {% block block1 %}{%endblock %}
28
+ --DATA--
29
+ return array()
30
+ --EXPECT--
31
+ ok
32
+ ko
33
+ ok
34
+ ok
35
+ ok
36
+ ko
37
+ ok
38
+ ko
library/twig/twig/test/Twig/Tests/Fixtures/tests/defined_for_blocks_with_template.test ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "defined" support for blocks with a template argument
3
+ --TEMPLATE--
4
+ {{ block('foo', 'included.twig') is defined ? 'ok' : 'ko' }}
5
+ {{ block('foo', included_loaded) is defined ? 'ok' : 'ko' }}
6
+ {{ block('foo', included_loaded_internal) is defined ? 'ok' : 'ko' }}
7
+ --TEMPLATE(included.twig)--
8
+ {% block foo %}FOO{% endblock %}
9
+ --DATA--
10
+ return array(
11
+ 'included_loaded' => $twig->load('included.twig'),
12
+ 'included_loaded_internal' => $twig->loadTemplate('included.twig'),
13
+ )
14
+ --EXPECT--
15
+ ok
16
+ ok
17
+ ok
library/twig/twig/test/Twig/Tests/Fixtures/tests/defined_for_constants.test ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "defined" support for constants
3
+ --TEMPLATE--
4
+ {{ constant('DATE_W3C') is defined ? 'ok' : 'ko' }}
5
+ {{ constant('ARRAY_AS_PROPS', object) is defined ? 'ok' : 'ko' }}
6
+ {{ constant('FOOBAR') is not defined ? 'ok' : 'ko' }}
7
+ {{ constant('FOOBAR', object) is not defined ? 'ok' : 'ko' }}
8
+ --DATA--
9
+ return array('expect' => DATE_W3C, 'object' => new ArrayObject(array('hi')));
10
+ --EXPECT--
11
+ ok
12
+ ok
13
+ ok
14
+ ok
library/twig/twig/test/Twig/Tests/Fixtures/tests/empty.test ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "empty" test
3
+ --TEMPLATE--
4
+ {{ foo is empty ? 'ok' : 'ko' }}
5
+ {{ bar is empty ? 'ok' : 'ko' }}
6
+ {{ foobar is empty ? 'ok' : 'ko' }}
7
+ {{ array is empty ? 'ok' : 'ko' }}
8
+ {{ zero is empty ? 'ok' : 'ko' }}
9
+ {{ string is empty ? 'ok' : 'ko' }}
10
+ {{ countable_empty is empty ? 'ok' : 'ko' }}
11
+ {{ countable_not_empty is empty ? 'ok' : 'ko' }}
12
+ {{ markup_empty is empty ? 'ok' : 'ko' }}
13
+ {{ markup_not_empty is empty ? 'ok' : 'ko' }}
14
+ --DATA--
15
+
16
+ class CountableStub implements Countable
17
+ {
18
+ private $items;
19
+
20
+ public function __construct(array $items)
21
+ {
22
+ $this->items = $items;
23
+ }
24
+
25
+ public function count()
26
+ {
27
+ return count($this->items);
28
+ }
29
+ }
30
+ return array(
31
+ 'foo' => '', 'bar' => null, 'foobar' => false, 'array' => array(), 'zero' => 0, 'string' => '0',
32
+ 'countable_empty' => new CountableStub(array()), 'countable_not_empty' => new CountableStub(array(1, 2)),
33
+ 'markup_empty' => new Twig_Markup('', 'UTF-8'), 'markup_not_empty' => new Twig_Markup('test', 'UTF-8'),
34
+ );
35
+ --EXPECT--
36
+ ok
37
+ ok
38
+ ok
39
+ ok
40
+ ko
41
+ ko
42
+ ok
43
+ ko
44
+ ok
45
+ ko
library/twig/twig/test/Twig/Tests/Fixtures/tests/even.test ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "even" test
3
+ --TEMPLATE--
4
+ {{ 1 is even ? 'ko' : 'ok' }}
5
+ {{ 2 is even ? 'ok' : 'ko' }}
6
+ {{ 1 is not even ? 'ok' : 'ko' }}
7
+ {{ 2 is not even ? 'ko' : 'ok' }}
8
+ --DATA--
9
+ return array()
10
+ --EXPECT--
11
+ ok
12
+ ok
13
+ ok
14
+ ok
library/twig/twig/test/Twig/Tests/Fixtures/tests/in.test ADDED
@@ -0,0 +1,128 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ Twig supports the in operator
3
+ --TEMPLATE--
4
+ {% if bar in foo %}
5
+ TRUE
6
+ {% endif %}
7
+ {% if not (bar in foo) %}
8
+ {% else %}
9
+ TRUE
10
+ {% endif %}
11
+ {% if bar not in foo %}
12
+ {% else %}
13
+ TRUE
14
+ {% endif %}
15
+ {% if 'a' in bar %}
16
+ TRUE
17
+ {% endif %}
18
+ {% if 'c' not in bar %}
19
+ TRUE
20
+ {% endif %}
21
+ {% if '' in bar %}
22
+ TRUE
23
+ {% endif %}
24
+ {% if '' in '' %}
25
+ TRUE
26
+ {% endif %}
27
+ {% if '0' not in '' %}
28
+ TRUE
29
+ {% endif %}
30
+ {% if 'a' not in '0' %}
31
+ TRUE
32
+ {% endif %}
33
+ {% if '0' in '0' %}
34
+ TRUE
35
+ {% endif %}
36
+
37
+ {{ false in [0, 1] ? 'TRUE' : 'FALSE' }}
38
+ {{ true in [0, 1] ? 'TRUE' : 'FALSE' }}
39
+ {{ '0' in [0, 1] ? 'TRUE' : 'FALSE' }}
40
+ {{ '' in [0, 1] ? 'TRUE' : 'FALSE' }}
41
+ {{ 0 in ['', 1] ? 'TRUE' : 'FALSE' }}
42
+
43
+ {{ '' in 'foo' ? 'TRUE' : 'FALSE' }}
44
+ {{ 0 in 'foo' ? 'TRUE' : 'FALSE' }}
45
+ {{ false in 'foo' ? 'TRUE' : 'FALSE' }}
46
+ {{ false in '100' ? 'TRUE' : 'FALSE' }}
47
+ {{ true in '100' ? 'TRUE' : 'FALSE' }}
48
+
49
+ {{ [] in [true, false] ? 'TRUE' : 'FALSE' }}
50
+ {{ [] in [true, ''] ? 'TRUE' : 'FALSE' }}
51
+ {{ [] in [true, []] ? 'TRUE' : 'FALSE' }}
52
+
53
+ {{ resource ? 'TRUE' : 'FALSE' }}
54
+ {{ resource in 'foo'~resource ? 'TRUE' : 'FALSE' }}
55
+ {{ object in 'stdClass' ? 'TRUE' : 'FALSE' }}
56
+ {{ [] in 'Array' ? 'TRUE' : 'FALSE' }}
57
+ {{ dir_object in 'foo'~dir_object ? 'TRUE' : 'FALSE' }}
58
+
59
+ {{ ''~resource in resource ? 'TRUE' : 'FALSE' }}
60
+ {{ 'stdClass' in object ? 'TRUE' : 'FALSE' }}
61
+ {{ 'Array' in [] ? 'TRUE' : 'FALSE' }}
62
+ {{ ''~dir_object in dir_object ? 'TRUE' : 'FALSE' }}
63
+
64
+ {{ resource in [''~resource] ? 'TRUE' : 'FALSE' }}
65
+ {{ resource in [resource + 1 - 1] ? 'TRUE' : 'FALSE' }}
66
+ {{ dir_object in [''~dir_object] ? 'TRUE' : 'FALSE' }}
67
+
68
+ {{ 5 in 125 ? 'TRUE' : 'FALSE' }}
69
+ {{ 5 in '125' ? 'TRUE' : 'FALSE' }}
70
+ {{ '5' in 125 ? 'TRUE' : 'FALSE' }}
71
+ {{ '5' in '125' ? 'TRUE' : 'FALSE' }}
72
+
73
+ {{ 5.5 in 125.5 ? 'TRUE' : 'FALSE' }}
74
+ {{ 5.5 in '125.5' ? 'TRUE' : 'FALSE' }}
75
+ {{ '5.5' in 125.5 ? 'TRUE' : 'FALSE' }}
76
+ --DATA--
77
+ return array('bar' => 'bar', 'foo' => array('bar' => 'bar'), 'dir_object' => new SplFileInfo(dirname(__FILE__)), 'object' => new stdClass(), 'resource' => opendir(dirname(__FILE__)))
78
+ --EXPECT--
79
+ TRUE
80
+ TRUE
81
+ TRUE
82
+ TRUE
83
+ TRUE
84
+ TRUE
85
+ TRUE
86
+ TRUE
87
+ TRUE
88
+ TRUE
89
+
90
+ TRUE
91
+ TRUE
92
+ TRUE
93
+ TRUE
94
+ TRUE
95
+
96
+ TRUE
97
+ FALSE
98
+ FALSE
99
+ FALSE
100
+ FALSE
101
+
102
+ TRUE
103
+ FALSE
104
+ TRUE
105
+
106
+ TRUE
107
+ FALSE
108
+ FALSE
109
+ FALSE
110
+ FALSE
111
+
112
+ FALSE
113
+ FALSE
114
+ FALSE
115
+ FALSE
116
+
117
+ FALSE
118
+ FALSE
119
+ FALSE
120
+
121
+ FALSE
122
+ TRUE
123
+ FALSE
124
+ TRUE
125
+
126
+ FALSE
127
+ TRUE
128
+ FALSE
library/twig/twig/test/Twig/Tests/Fixtures/tests/in_with_objects.test ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ Twig supports the in operator when using objects
3
+ --TEMPLATE--
4
+ {% if object in object_list %}
5
+ TRUE
6
+ {% endif %}
7
+ --DATA--
8
+ $foo = new TwigTestFoo();
9
+ $foo1 = new TwigTestFoo();
10
+
11
+ $foo->position = $foo1;
12
+ $foo1->position = $foo;
13
+
14
+ return array(
15
+ 'object' => $foo,
16
+ 'object_list' => array($foo1, $foo),
17
+ );
18
+ --EXPECT--
19
+ TRUE
library/twig/twig/test/Twig/Tests/Fixtures/tests/iterable.test ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "iterable" test
3
+ --TEMPLATE--
4
+ {{ foo is iterable ? 'ok' : 'ko' }}
5
+ {{ traversable is iterable ? 'ok' : 'ko' }}
6
+ {{ obj is iterable ? 'ok' : 'ko' }}
7
+ {{ val is iterable ? 'ok' : 'ko' }}
8
+ --DATA--
9
+ return array(
10
+ 'foo' => array(),
11
+ 'traversable' => new ArrayIterator(array()),
12
+ 'obj' => new stdClass(),
13
+ 'val' => 'test',
14
+ );
15
+ --EXPECT--
16
+ ok
17
+ ok
18
+ ko
19
+ ko
library/twig/twig/test/Twig/Tests/Fixtures/tests/null_coalesce.test ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ Twig supports the ?? operator
3
+ --TEMPLATE--
4
+ {{ 'OK' ?? 'KO' }}
5
+ {{ null ?? 'OK' }}
6
+ {{ bar ?? 'KO' }}
7
+ {{ baz ?? 'OK' }}
8
+ {{ foo.bar ?? 'KO' }}
9
+ {{ foo.missing ?? 'OK' }}
10
+ {{ foo.bar.baz.missing ?? 'OK' }}
11
+ {{ foo['bar'] ?? 'KO' }}
12
+ {{ foo['missing'] ?? 'OK' }}
13
+ {{ nope ?? nada ?? 'OK' }}
14
+ {{ 1 + nope ?? nada ?? 2 }}
15
+ {{ 1 + nope ?? 3 + nada ?? 2 }}
16
+ --DATA--
17
+ return array('bar' => 'OK', 'foo' => array('bar' => 'OK'))
18
+ --EXPECT--
19
+ OK
20
+ OK
21
+ OK
22
+ OK
23
+ OK
24
+ OK
25
+ OK
26
+ OK
27
+ OK
28
+ OK
29
+ 3
30
+ 6
library/twig/twig/test/Twig/Tests/Fixtures/tests/odd.test ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "odd" test
3
+ --TEMPLATE--
4
+ {{ 1 is odd ? 'ok' : 'ko' }}
5
+ {{ 2 is odd ? 'ko' : 'ok' }}
6
+ --DATA--
7
+ return array()
8
+ --EXPECT--
9
+ ok
10
+ ok
library/twig/twig/test/Twig/Tests/IntegrationTest.php ADDED
@@ -0,0 +1,254 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 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
+ // This function is defined to check that escaping strategies
13
+ // like html works even if a function with the same name is defined.
14
+ function html()
15
+ {
16
+ return 'foo';
17
+ }
18
+
19
+ class Twig_Tests_IntegrationTest extends Twig_Test_IntegrationTestCase
20
+ {
21
+ public function getExtensions()
22
+ {
23
+ $policy = new Twig_Sandbox_SecurityPolicy(array(), array(), array(), array(), array());
24
+
25
+ return array(
26
+ new Twig_Extension_Debug(),
27
+ new Twig_Extension_Sandbox($policy, false),
28
+ new Twig_Extension_StringLoader(),
29
+ new TwigTestExtension(),
30
+ );
31
+ }
32
+
33
+ public function getFixturesDir()
34
+ {
35
+ return dirname(__FILE__).'/Fixtures/';
36
+ }
37
+ }
38
+
39
+ function test_foo($value = 'foo')
40
+ {
41
+ return $value;
42
+ }
43
+
44
+ class TwigTestFoo implements Iterator
45
+ {
46
+ const BAR_NAME = 'bar';
47
+
48
+ public $position = 0;
49
+ public $array = array(1, 2);
50
+
51
+ public function bar($param1 = null, $param2 = null)
52
+ {
53
+ return 'bar'.($param1 ? '_'.$param1 : '').($param2 ? '-'.$param2 : '');
54
+ }
55
+
56
+ public function getFoo()
57
+ {
58
+ return 'foo';
59
+ }
60
+
61
+ public function getSelf()
62
+ {
63
+ return $this;
64
+ }
65
+
66
+ public function is()
67
+ {
68
+ return 'is';
69
+ }
70
+
71
+ public function in()
72
+ {
73
+ return 'in';
74
+ }
75
+
76
+ public function not()
77
+ {
78
+ return 'not';
79
+ }
80
+
81
+ public function strToLower($value)
82
+ {
83
+ return strtolower($value);
84
+ }
85
+
86
+ public function rewind()
87
+ {
88
+ $this->position = 0;
89
+ }
90
+
91
+ public function current()
92
+ {
93
+ return $this->array[$this->position];
94
+ }
95
+
96
+ public function key()
97
+ {
98
+ return 'a';
99
+ }
100
+
101
+ public function next()
102
+ {
103
+ ++$this->position;
104
+ }
105
+
106
+ public function valid()
107
+ {
108
+ return isset($this->array[$this->position]);
109
+ }
110
+ }
111
+
112
+ class TwigTestTokenParser_§ extends Twig_TokenParser
113
+ {
114
+ public function parse(Twig_Token $token)
115
+ {
116
+ $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
117
+
118
+ return new Twig_Node_Print(new Twig_Node_Expression_Constant('§', -1), -1);
119
+ }
120
+
121
+ public function getTag()
122
+ {
123
+ return '§';
124
+ }
125
+ }
126
+
127
+ class TwigTestExtension extends Twig_Extension
128
+ {
129
+ public function getTokenParsers()
130
+ {
131
+ return array(
132
+ new TwigTestTokenParser_§(),
133
+ );
134
+ }
135
+
136
+ public function getFilters()
137
+ {
138
+ return array(
139
+ new Twig_SimpleFilter('§', array($this, '§Filter')),
140
+ new Twig_SimpleFilter('escape_and_nl2br', array($this, 'escape_and_nl2br'), array('needs_environment' => true, 'is_safe' => array('html'))),
141
+ new Twig_SimpleFilter('nl2br', array($this, 'nl2br'), array('pre_escape' => 'html', 'is_safe' => array('html'))),
142
+ new Twig_SimpleFilter('escape_something', array($this, 'escape_something'), array('is_safe' => array('something'))),
143
+ new Twig_SimpleFilter('preserves_safety', array($this, 'preserves_safety'), array('preserves_safety' => array('html'))),
144
+ new Twig_SimpleFilter('static_call_string', 'TwigTestExtension::staticCall'),
145
+ new Twig_SimpleFilter('static_call_array', array('TwigTestExtension', 'staticCall')),
146
+ new Twig_SimpleFilter('magic_call', array($this, 'magicCall')),
147
+ new Twig_SimpleFilter('magic_call_string', 'TwigTestExtension::magicStaticCall'),
148
+ new Twig_SimpleFilter('magic_call_array', array('TwigTestExtension', 'magicStaticCall')),
149
+ new Twig_SimpleFilter('*_path', array($this, 'dynamic_path')),
150
+ new Twig_SimpleFilter('*_foo_*_bar', array($this, 'dynamic_foo')),
151
+ );
152
+ }
153
+
154
+ public function getFunctions()
155
+ {
156
+ return array(
157
+ new Twig_SimpleFunction('§', array($this, '§Function')),
158
+ new Twig_SimpleFunction('safe_br', array($this, 'br'), array('is_safe' => array('html'))),
159
+ new Twig_SimpleFunction('unsafe_br', array($this, 'br')),
160
+ new Twig_SimpleFunction('static_call_string', 'TwigTestExtension::staticCall'),
161
+ new Twig_SimpleFunction('static_call_array', array('TwigTestExtension', 'staticCall')),
162
+ new Twig_SimpleFunction('*_path', array($this, 'dynamic_path')),
163
+ new Twig_SimpleFunction('*_foo_*_bar', array($this, 'dynamic_foo')),
164
+ );
165
+ }
166
+
167
+ public function getTests()
168
+ {
169
+ return array(
170
+ new Twig_SimpleTest('multi word', array($this, 'is_multi_word')),
171
+ );
172
+ }
173
+
174
+ public function §Filter($value)
175
+ {
176
+ return "§{$value}§";
177
+ }
178
+
179
+ public function §Function($value)
180
+ {
181
+ return "§{$value}§";
182
+ }
183
+
184
+ /**
185
+ * nl2br which also escapes, for testing escaper filters.
186
+ */
187
+ public function escape_and_nl2br($env, $value, $sep = '<br />')
188
+ {
189
+ return $this->nl2br(twig_escape_filter($env, $value, 'html'), $sep);
190
+ }
191
+
192
+ /**
193
+ * nl2br only, for testing filters with pre_escape.
194
+ */
195
+ public function nl2br($value, $sep = '<br />')
196
+ {
197
+ // not secure if $value contains html tags (not only entities)
198
+ // don't use
199
+ return str_replace("\n", "$sep\n", $value);
200
+ }
201
+
202
+ public function dynamic_path($element, $item)
203
+ {
204
+ return $element.'/'.$item;
205
+ }
206
+
207
+ public function dynamic_foo($foo, $bar, $item)
208
+ {
209
+ return $foo.'/'.$bar.'/'.$item;
210
+ }
211
+
212
+ public function escape_something($value)
213
+ {
214
+ return strtoupper($value);
215
+ }
216
+
217
+ public function preserves_safety($value)
218
+ {
219
+ return strtoupper($value);
220
+ }
221
+
222
+ public static function staticCall($value)
223
+ {
224
+ return "*$value*";
225
+ }
226
+
227
+ public function br()
228
+ {
229
+ return '<br />';
230
+ }
231
+
232
+ public function is_multi_word($value)
233
+ {
234
+ return false !== strpos($value, ' ');
235
+ }
236
+
237
+ public function __call($method, $arguments)
238
+ {
239
+ if ('magicCall' !== $method) {
240
+ throw new BadMethodCallException('Unexpected call to __call');
241
+ }
242
+
243
+ return 'magic_'.$arguments[0];
244
+ }
245
+
246
+ public static function __callStatic($method, $arguments)
247
+ {
248
+ if ('magicStaticCall' !== $method) {
249
+ throw new BadMethodCallException('Unexpected call to __callStatic');
250
+ }
251
+
252
+ return 'static_magic_'.$arguments[0];
253
+ }
254
+ }
library/twig/twig/test/Twig/Tests/LegacyFixtures/autoescape/filename.legacy.test ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "filename" autoescape strategy
3
+ --TEMPLATE--
4
+ {{ br -}}
5
+ {{ include('index.html.twig') -}}
6
+ {{ include('index.txt.twig') -}}
7
+ --TEMPLATE(index.html.twig)--
8
+ {{ br -}}
9
+ --TEMPLATE(index.txt.twig)--
10
+ {{ br -}}
11
+ --DATA--
12
+ return array('br' => '<br />')
13
+ --CONFIG--
14
+ return array('autoescape' => 'filename')
15
+ --EXPECT--
16
+ &lt;br /&gt;
17
+ &lt;br /&gt;
18
+ <br />
library/twig/twig/test/Twig/Tests/LegacyFixtures/functions/undefined_block.legacy.test ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ "block" function with undefined block
3
+ --TEMPLATE--
4
+ {% extends "base.twig" %}
5
+ {% block foo %}{{ parent() }}{{ block('unknown') }}{{ block('bar') }}{% endblock %}
6
+ --TEMPLATE(base.twig)--
7
+ {% block foo %}Foo{% endblock %}
8
+ {% block bar %}Bar{% endblock %}
9
+ --DATA--
10
+ return array()
11
+ --EXPECT--
12
+ FooBarBar
library/twig/twig/test/Twig/Tests/LegacyFixtures/test.legacy.test ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
1
+ --TEST--
2
+ Old test classes usage
3
+ --TEMPLATE--
4
+ {{ 'foo' is multi word ? 'yes' : 'no' }}
5
+ --DATA--
6
+ return array()
7
+ --EXPECT--
8
+ no
library/twig/twig/test/Twig/Tests/LegacyIntegrationTest.php ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 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_Tests_LegacyIntegrationTest extends Twig_Test_IntegrationTestCase
13
+ {
14
+ public function getExtensions()
15
+ {
16
+ return array(
17
+ new LegacyTwigTestExtension(),
18
+ );
19
+ }
20
+
21
+ public function getFixturesDir()
22
+ {
23
+ return dirname(__FILE__).'/LegacyFixtures/';
24
+ }
25
+
26
+ public function getTests($name, $legacyTests = false)
27
+ {
28
+ if (!$legacyTests) {
29
+ return array(array('not', '-', '', array(), '', array()));
30
+ }
31
+
32
+ return parent::getTests($name, true);
33
+ }
34
+ }
35
+
36
+ class LegacyTwigTestExtension extends Twig_Extension
37
+ {
38
+ public function getTests()
39
+ {
40
+ return array(
41
+ 'multi word' => new Twig_Test_Method($this, 'is_multi_word'),
42
+ );
43
+ }
44
+
45
+ public function is_multi_word($value)
46
+ {
47
+ return false !== strpos($value, ' ');
48
+ }
49
+
50
+ public function getName()
51
+ {
52
+ return 'legacy_integration_test';
53
+ }
54
+ }
library/twig/twig/test/Twig/Tests/LexerTest.php ADDED
@@ -0,0 +1,311 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 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_Tests_LexerTest extends PHPUnit_Framework_TestCase
12
+ {
13
+ /**
14
+ * @group legacy
15
+ */
16
+ public function testLegacyConstructorSignature()
17
+ {
18
+ $lexer = new Twig_Lexer(new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock()));
19
+ $stream = $lexer->tokenize('{{ foo }}', 'foo');
20
+ $this->assertEquals('foo', $stream->getFilename());
21
+ $this->assertEquals('{{ foo }}', $stream->getSource());
22
+ }
23
+
24
+ public function testNameLabelForTag()
25
+ {
26
+ $template = '{% § %}';
27
+
28
+ $lexer = new Twig_Lexer(new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock()));
29
+ $stream = $lexer->tokenize(new Twig_Source($template, 'index'));
30
+
31
+ $stream->expect(Twig_Token::BLOCK_START_TYPE);
32
+ $this->assertSame('§', $stream->expect(Twig_Token::NAME_TYPE)->getValue());
33
+ }
34
+
35
+ public function testNameLabelForFunction()
36
+ {
37
+ $template = '{{ §() }}';
38
+
39
+ $lexer = new Twig_Lexer(new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock()));
40
+ $stream = $lexer->tokenize(new Twig_Source($template, 'index'));
41
+
42
+ $stream->expect(Twig_Token::VAR_START_TYPE);
43
+ $this->assertSame('§', $stream->expect(Twig_Token::NAME_TYPE)->getValue());
44
+ }
45
+
46
+ public function testBracketsNesting()
47
+ {
48
+ $template = '{{ {"a":{"b":"c"}} }}';
49
+
50
+ $this->assertEquals(2, $this->countToken($template, Twig_Token::PUNCTUATION_TYPE, '{'));
51
+ $this->assertEquals(2, $this->countToken($template, Twig_Token::PUNCTUATION_TYPE, '}'));
52
+ }
53
+
54
+ protected function countToken($template, $type, $value = null)
55
+ {
56
+ $lexer = new Twig_Lexer(new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock()));
57
+ $stream = $lexer->tokenize(new Twig_Source($template, 'index'));
58
+
59
+ $count = 0;
60
+ while (!$stream->isEOF()) {
61
+ $token = $stream->next();
62
+ if ($type === $token->getType()) {
63
+ if (null === $value || $value === $token->getValue()) {
64
+ ++$count;
65
+ }
66
+ }
67
+ }
68
+
69
+ return $count;
70
+ }
71
+
72
+ public function testLineDirective()
73
+ {
74
+ $template = "foo\n"
75
+ ."bar\n"
76
+ ."{% line 10 %}\n"
77
+ ."{{\n"
78
+ ."baz\n"
79
+ ."}}\n";
80
+
81
+ $lexer = new Twig_Lexer(new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock()));
82
+ $stream = $lexer->tokenize(new Twig_Source($template, 'index'));
83
+
84
+ // foo\nbar\n
85
+ $this->assertSame(1, $stream->expect(Twig_Token::TEXT_TYPE)->getLine());
86
+ // \n (after {% line %})
87
+ $this->assertSame(10, $stream->expect(Twig_Token::TEXT_TYPE)->getLine());
88
+ // {{
89
+ $this->assertSame(11, $stream->expect(Twig_Token::VAR_START_TYPE)->getLine());
90
+ // baz
91
+ $this->assertSame(12, $stream->expect(Twig_Token::NAME_TYPE)->getLine());
92
+ }
93
+
94
+ public function testLineDirectiveInline()
95
+ {
96
+ $template = "foo\n"
97
+ ."bar{% line 10 %}{{\n"
98
+ ."baz\n"
99
+ ."}}\n";
100
+
101
+ $lexer = new Twig_Lexer(new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock()));
102
+ $stream = $lexer->tokenize(new Twig_Source($template, 'index'));
103
+
104
+ // foo\nbar
105
+ $this->assertSame(1, $stream->expect(Twig_Token::TEXT_TYPE)->getLine());
106
+ // {{
107
+ $this->assertSame(10, $stream->expect(Twig_Token::VAR_START_TYPE)->getLine());
108
+ // baz
109
+ $this->assertSame(11, $stream->expect(Twig_Token::NAME_TYPE)->getLine());
110
+ }
111
+
112
+ public function testLongComments()
113
+ {
114
+ $template = '{# '.str_repeat('*', 100000).' #}';
115
+
116
+ $lexer = new Twig_Lexer(new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock()));
117
+ $lexer->tokenize(new Twig_Source($template, 'index'));
118
+
119
+ // should not throw an exception
120
+ }
121
+
122
+ public function testLongVerbatim()
123
+ {
124
+ $template = '{% verbatim %}'.str_repeat('*', 100000).'{% endverbatim %}';
125
+
126
+ $lexer = new Twig_Lexer(new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock()));
127
+ $lexer->tokenize(new Twig_Source($template, 'index'));
128
+
129
+ // should not throw an exception
130
+ }
131
+
132
+ public function testLongVar()
133
+ {
134
+ $template = '{{ '.str_repeat('x', 100000).' }}';
135
+
136
+ $lexer = new Twig_Lexer(new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock()));
137
+ $lexer->tokenize(new Twig_Source($template, 'index'));
138
+
139
+ // should not throw an exception
140
+ }
141
+
142
+ public function testLongBlock()
143
+ {
144
+ $template = '{% '.str_repeat('x', 100000).' %}';
145
+
146
+ $lexer = new Twig_Lexer(new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock()));
147
+ $lexer->tokenize(new Twig_Source($template, 'index'));
148
+
149
+ // should not throw an exception
150
+ }
151
+
152
+ public function testBigNumbers()
153
+ {
154
+ $template = '{{ 922337203685477580700 }}';
155
+
156
+ $lexer = new Twig_Lexer(new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock()));
157
+ $stream = $lexer->tokenize(new Twig_Source($template, 'index'));
158
+ $stream->next();
159
+ $node = $stream->next();
160
+ $this->assertEquals('922337203685477580700', $node->getValue());
161
+ }
162
+
163
+ public function testStringWithEscapedDelimiter()
164
+ {
165
+ $tests = array(
166
+ "{{ 'foo \' bar' }}" => 'foo \' bar',
167
+ '{{ "foo \" bar" }}' => 'foo " bar',
168
+ );
169
+ $lexer = new Twig_Lexer(new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock()));
170
+ foreach ($tests as $template => $expected) {
171
+ $stream = $lexer->tokenize(new Twig_Source($template, 'index'));
172
+ $stream->expect(Twig_Token::VAR_START_TYPE);
173
+ $stream->expect(Twig_Token::STRING_TYPE, $expected);
174
+ }
175
+ }
176
+
177
+ public function testStringWithInterpolation()
178
+ {
179
+ $template = 'foo {{ "bar #{ baz + 1 }" }}';
180
+
181
+ $lexer = new Twig_Lexer(new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock()));
182
+ $stream = $lexer->tokenize(new Twig_Source($template, 'index'));
183
+ $stream->expect(Twig_Token::TEXT_TYPE, 'foo ');
184
+ $stream->expect(Twig_Token::VAR_START_TYPE);
185
+ $stream->expect(Twig_Token::STRING_TYPE, 'bar ');
186
+ $stream->expect(Twig_Token::INTERPOLATION_START_TYPE);
187
+ $stream->expect(Twig_Token::NAME_TYPE, 'baz');
188
+ $stream->expect(Twig_Token::OPERATOR_TYPE, '+');
189
+ $stream->expect(Twig_Token::NUMBER_TYPE, '1');
190
+ $stream->expect(Twig_Token::INTERPOLATION_END_TYPE);
191
+ $stream->expect(Twig_Token::VAR_END_TYPE);
192
+ }
193
+
194
+ public function testStringWithEscapedInterpolation()
195
+ {
196
+ $template = '{{ "bar \#{baz+1}" }}';
197
+
198
+ $lexer = new Twig_Lexer(new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock()));
199
+ $stream = $lexer->tokenize(new Twig_Source($template, 'index'));
200
+ $stream->expect(Twig_Token::VAR_START_TYPE);
201
+ $stream->expect(Twig_Token::STRING_TYPE, 'bar #{baz+1}');
202
+ $stream->expect(Twig_Token::VAR_END_TYPE);
203
+ }
204
+
205
+ public function testStringWithHash()
206
+ {
207
+ $template = '{{ "bar # baz" }}';
208
+
209
+ $lexer = new Twig_Lexer(new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock()));
210
+ $stream = $lexer->tokenize(new Twig_Source($template, 'index'));
211
+ $stream->expect(Twig_Token::VAR_START_TYPE);
212
+ $stream->expect(Twig_Token::STRING_TYPE, 'bar # baz');
213
+ $stream->expect(Twig_Token::VAR_END_TYPE);
214
+ }
215
+
216
+ /**
217
+ * @expectedException Twig_Error_Syntax
218
+ * @expectedExceptionMessage Unclosed """
219
+ */
220
+ public function testStringWithUnterminatedInterpolation()
221
+ {
222
+ $template = '{{ "bar #{x" }}';
223
+
224
+ $lexer = new Twig_Lexer(new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock()));
225
+ $lexer->tokenize(new Twig_Source($template, 'index'));
226
+ }
227
+
228
+ public function testStringWithNestedInterpolations()
229
+ {
230
+ $template = '{{ "bar #{ "foo#{bar}" }" }}';
231
+
232
+ $lexer = new Twig_Lexer(new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock()));
233
+ $stream = $lexer->tokenize(new Twig_Source($template, 'index'));
234
+ $stream->expect(Twig_Token::VAR_START_TYPE);
235
+ $stream->expect(Twig_Token::STRING_TYPE, 'bar ');
236
+ $stream->expect(Twig_Token::INTERPOLATION_START_TYPE);
237
+ $stream->expect(Twig_Token::STRING_TYPE, 'foo');
238
+ $stream->expect(Twig_Token::INTERPOLATION_START_TYPE);
239
+ $stream->expect(Twig_Token::NAME_TYPE, 'bar');
240
+ $stream->expect(Twig_Token::INTERPOLATION_END_TYPE);
241
+ $stream->expect(Twig_Token::INTERPOLATION_END_TYPE);
242
+ $stream->expect(Twig_Token::VAR_END_TYPE);
243
+ }
244
+
245
+ public function testStringWithNestedInterpolationsInBlock()
246
+ {
247
+ $template = '{% foo "bar #{ "foo#{bar}" }" %}';
248
+
249
+ $lexer = new Twig_Lexer(new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock()));
250
+ $stream = $lexer->tokenize(new Twig_Source($template, 'index'));
251
+ $stream->expect(Twig_Token::BLOCK_START_TYPE);
252
+ $stream->expect(Twig_Token::NAME_TYPE, 'foo');
253
+ $stream->expect(Twig_Token::STRING_TYPE, 'bar ');
254
+ $stream->expect(Twig_Token::INTERPOLATION_START_TYPE);
255
+ $stream->expect(Twig_Token::STRING_TYPE, 'foo');
256
+ $stream->expect(Twig_Token::INTERPOLATION_START_TYPE);
257
+ $stream->expect(Twig_Token::NAME_TYPE, 'bar');
258
+ $stream->expect(Twig_Token::INTERPOLATION_END_TYPE);
259
+ $stream->expect(Twig_Token::INTERPOLATION_END_TYPE);
260
+ $stream->expect(Twig_Token::BLOCK_END_TYPE);
261
+ }
262
+
263
+ public function testOperatorEndingWithALetterAtTheEndOfALine()
264
+ {
265
+ $template = "{{ 1 and\n0}}";
266
+
267
+ $lexer = new Twig_Lexer(new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock()));
268
+ $stream = $lexer->tokenize(new Twig_Source($template, 'index'));
269
+ $stream->expect(Twig_Token::VAR_START_TYPE);
270
+ $stream->expect(Twig_Token::NUMBER_TYPE, 1);
271
+ $stream->expect(Twig_Token::OPERATOR_TYPE, 'and');
272
+ }
273
+
274
+ /**
275
+ * @expectedException Twig_Error_Syntax
276
+ * @expectedExceptionMessage Unclosed "variable" in "index" at line 3
277
+ */
278
+ public function testUnterminatedVariable()
279
+ {
280
+ $template = '
281
+
282
+ {{
283
+
284
+ bar
285
+
286
+
287
+ ';
288
+
289
+ $lexer = new Twig_Lexer(new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock()));
290
+ $lexer->tokenize(new Twig_Source($template, 'index'));
291
+ }
292
+
293
+ /**
294
+ * @expectedException Twig_Error_Syntax
295
+ * @expectedExceptionMessage Unclosed "block" in "index" at line 3
296
+ */
297
+ public function testUnterminatedBlock()
298
+ {
299
+ $template = '
300
+
301
+ {%
302
+
303
+ bar
304
+
305
+
306
+ ';
307
+
308
+ $lexer = new Twig_Lexer(new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock()));
309
+ $lexer->tokenize(new Twig_Source($template, 'index'));
310
+ }
311
+ }
library/twig/twig/test/Twig/Tests/Loader/ArrayTest.php ADDED
@@ -0,0 +1,111 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 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_Tests_Loader_ArrayTest extends PHPUnit_Framework_TestCase
13
+ {
14
+ /**
15
+ * @group legacy
16
+ */
17
+ public function testGetSource()
18
+ {
19
+ $loader = new Twig_Loader_Array(array('foo' => 'bar'));
20
+
21
+ $this->assertEquals('bar', $loader->getSource('foo'));
22
+ }
23
+
24
+ /**
25
+ * @group legacy
26
+ * @expectedException Twig_Error_Loader
27
+ */
28
+ public function testGetSourceWhenTemplateDoesNotExist()
29
+ {
30
+ $loader = new Twig_Loader_Array(array());
31
+
32
+ $loader->getSource('foo');
33
+ }
34
+
35
+ /**
36
+ * @expectedException Twig_Error_Loader
37
+ */
38
+ public function testGetSourceContextWhenTemplateDoesNotExist()
39
+ {
40
+ $loader = new Twig_Loader_Array(array());
41
+
42
+ $loader->getSourceContext('foo');
43
+ }
44
+
45
+ public function testGetCacheKey()
46
+ {
47
+ $loader = new Twig_Loader_Array(array('foo' => 'bar'));
48
+
49
+ $this->assertEquals('bar', $loader->getCacheKey('foo'));
50
+ }
51
+
52
+ /**
53
+ * @expectedException Twig_Error_Loader
54
+ */
55
+ public function testGetCacheKeyWhenTemplateDoesNotExist()
56
+ {
57
+ $loader = new Twig_Loader_Array(array());
58
+
59
+ $loader->getCacheKey('foo');
60
+ }
61
+
62
+ public function testSetTemplate()
63
+ {
64
+ $loader = new Twig_Loader_Array(array());
65
+ $loader->setTemplate('foo', 'bar');
66
+
67
+ $this->assertEquals('bar', $loader->getSourceContext('foo')->getCode());
68
+ }
69
+
70
+ public function testIsFresh()
71
+ {
72
+ $loader = new Twig_Loader_Array(array('foo' => 'bar'));
73
+ $this->assertTrue($loader->isFresh('foo', time()));
74
+ }
75
+
76
+ /**
77
+ * @expectedException Twig_Error_Loader
78
+ */
79
+ public function testIsFreshWhenTemplateDoesNotExist()
80
+ {
81
+ $loader = new Twig_Loader_Array(array());
82
+
83
+ $loader->isFresh('foo', time());
84
+ }
85
+
86
+ public function testTemplateReference()
87
+ {
88
+ $name = new Twig_Test_Loader_TemplateReference('foo');
89
+ $loader = new Twig_Loader_Array(array('foo' => 'bar'));
90
+
91
+ $loader->getCacheKey($name);
92
+ $loader->getSourceContext($name);
93
+ $loader->isFresh($name, time());
94
+ $loader->setTemplate($name, 'foobar');
95
+ }
96
+ }
97
+
98
+ class Twig_Test_Loader_TemplateReference
99
+ {
100
+ private $name;
101
+
102
+ public function __construct($name)
103
+ {
104
+ $this->name = $name;
105
+ }
106
+
107
+ public function __toString()
108
+ {
109
+ return $this->name;
110
+ }
111
+ }
library/twig/twig/test/Twig/Tests/Loader/ChainTest.php ADDED
@@ -0,0 +1,124 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 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_Tests_Loader_ChainTest extends PHPUnit_Framework_TestCase
13
+ {
14
+ /**
15
+ * @group legacy
16
+ */
17
+ public function testGetSource()
18
+ {
19
+ $loader = new Twig_Loader_Chain(array(
20
+ new Twig_Loader_Array(array('foo' => 'bar')),
21
+ new Twig_Loader_Array(array('foo' => 'foobar', 'bar' => 'foo')),
22
+ ));
23
+
24
+ $this->assertEquals('bar', $loader->getSource('foo'));
25
+ $this->assertEquals('foo', $loader->getSource('bar'));
26
+ }
27
+
28
+ public function testGetSourceContext()
29
+ {
30
+ $path = dirname(__FILE__).'/../Fixtures';
31
+ $loader = new Twig_Loader_Chain(array(
32
+ new Twig_Loader_Array(array('foo' => 'bar')),
33
+ new Twig_Loader_Array(array('errors/index.html' => 'baz')),
34
+ new Twig_Loader_Filesystem(array($path)),
35
+ ));
36
+
37
+ $this->assertEquals('foo', $loader->getSourceContext('foo')->getName());
38
+ $this->assertSame('', $loader->getSourceContext('foo')->getPath());
39
+
40
+ $this->assertEquals('errors/index.html', $loader->getSourceContext('errors/index.html')->getName());
41
+ $this->assertSame('', $loader->getSourceContext('errors/index.html')->getPath());
42
+ $this->assertEquals('baz', $loader->getSourceContext('errors/index.html')->getCode());
43
+
44
+ $this->assertEquals('errors/base.html', $loader->getSourceContext('errors/base.html')->getName());
45
+ $this->assertEquals(realpath($path.'/errors/base.html'), realpath($loader->getSourceContext('errors/base.html')->getPath()));
46
+ $this->assertNotEquals('baz', $loader->getSourceContext('errors/base.html')->getCode());
47
+ }
48
+
49
+ /**
50
+ * @expectedException Twig_Error_Loader
51
+ */
52
+ public function testGetSourceContextWhenTemplateDoesNotExist()
53
+ {
54
+ $loader = new Twig_Loader_Chain(array());
55
+
56
+ $loader->getSourceContext('foo');
57
+ }
58
+
59
+ /**
60
+ * @group legacy
61
+ * @expectedException Twig_Error_Loader
62
+ */
63
+ public function testGetSourceWhenTemplateDoesNotExist()
64
+ {
65
+ $loader = new Twig_Loader_Chain(array());
66
+
67
+ $loader->getSource('foo');
68
+ }
69
+
70
+ public function testGetCacheKey()
71
+ {
72
+ $loader = new Twig_Loader_Chain(array(
73
+ new Twig_Loader_Array(array('foo' => 'bar')),
74
+ new Twig_Loader_Array(array('foo' => 'foobar', 'bar' => 'foo')),
75
+ ));
76
+
77
+ $this->assertEquals('bar', $loader->getCacheKey('foo'));
78
+ $this->assertEquals('foo', $loader->getCacheKey('bar'));
79
+ }
80
+
81
+ /**
82
+ * @expectedException Twig_Error_Loader
83
+ */
84
+ public function testGetCacheKeyWhenTemplateDoesNotExist()
85
+ {
86
+ $loader = new Twig_Loader_Chain(array());
87
+
88
+ $loader->getCacheKey('foo');
89
+ }
90
+
91
+ public function testAddLoader()
92
+ {
93
+ $loader = new Twig_Loader_Chain();
94
+ $loader->addLoader(new Twig_Loader_Array(array('foo' => 'bar')));
95
+
96
+ $this->assertEquals('bar', $loader->getSourceContext('foo')->getCode());
97
+ }
98
+
99
+ public function testExists()
100
+ {
101
+ $loader1 = $this->getMockBuilder('Twig_ChainTestLoaderWithExistsInterface')->getMock();
102
+ $loader1->expects($this->once())->method('exists')->will($this->returnValue(false));
103
+ $loader1->expects($this->never())->method('getSourceContext');
104
+
105
+ // can be removed in 2.0
106
+ $loader2 = $this->getMockBuilder('Twig_ChainTestLoaderInterface')->getMock();
107
+ //$loader2 = $this->getMockBuilder(array('Twig_LoaderInterface', 'Twig_SourceContextLoaderInterface'))->getMock();
108
+ $loader2->expects($this->once())->method('getSourceContext')->will($this->returnValue(new Twig_Source('content', 'index')));
109
+
110
+ $loader = new Twig_Loader_Chain();
111
+ $loader->addLoader($loader1);
112
+ $loader->addLoader($loader2);
113
+
114
+ $this->assertTrue($loader->exists('foo'));
115
+ }
116
+ }
117
+
118
+ interface Twig_ChainTestLoaderInterface extends Twig_LoaderInterface, Twig_SourceContextLoaderInterface
119
+ {
120
+ }
121
+
122
+ interface Twig_ChainTestLoaderWithExistsInterface extends Twig_LoaderInterface, Twig_ExistsLoaderInterface, Twig_SourceContextLoaderInterface
123
+ {
124
+ }
library/twig/twig/test/Twig/Tests/Loader/FilesystemTest.php ADDED
@@ -0,0 +1,226 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 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_Tests_Loader_FilesystemTest extends PHPUnit_Framework_TestCase
13
+ {
14
+ public function testGetSourceContext()
15
+ {
16
+ $path = dirname(__FILE__).'/../Fixtures';
17
+ $loader = new Twig_Loader_Filesystem(array($path));
18
+ $this->assertEquals('errors/index.html', $loader->getSourceContext('errors/index.html')->getName());
19
+ $this->assertEquals(realpath($path.'/errors/index.html'), realpath($loader->getSourceContext('errors/index.html')->getPath()));
20
+ }
21
+
22
+ /**
23
+ * @dataProvider getSecurityTests
24
+ */
25
+ public function testSecurity($template)
26
+ {
27
+ $loader = new Twig_Loader_Filesystem(array(dirname(__FILE__).'/../Fixtures'));
28
+
29
+ try {
30
+ $loader->getCacheKey($template);
31
+ $this->fail();
32
+ } catch (Twig_Error_Loader $e) {
33
+ $this->assertNotContains('Unable to find template', $e->getMessage());
34
+ }
35
+ }
36
+
37
+ public function getSecurityTests()
38
+ {
39
+ return array(
40
+ array("AutoloaderTest\0.php"),
41
+ array('..\\AutoloaderTest.php'),
42
+ array('..\\\\\\AutoloaderTest.php'),
43
+ array('../AutoloaderTest.php'),
44
+ array('..////AutoloaderTest.php'),
45
+ array('./../AutoloaderTest.php'),
46
+ array('.\\..\\AutoloaderTest.php'),
47
+ array('././././././../AutoloaderTest.php'),
48
+ array('.\\./.\\./.\\./../AutoloaderTest.php'),
49
+ array('foo/../../AutoloaderTest.php'),
50
+ array('foo\\..\\..\\AutoloaderTest.php'),
51
+ array('foo/../bar/../../AutoloaderTest.php'),
52
+ array('foo/bar/../../../AutoloaderTest.php'),
53
+ array('filters/../../AutoloaderTest.php'),
54
+ array('filters//..//..//AutoloaderTest.php'),
55
+ array('filters\\..\\..\\AutoloaderTest.php'),
56
+ array('filters\\\\..\\\\..\\\\AutoloaderTest.php'),
57
+ array('filters\\//../\\/\\..\\AutoloaderTest.php'),
58
+ array('/../AutoloaderTest.php'),
59
+ );
60
+ }
61
+
62
+ /**
63
+ * @dataProvider getBasePaths
64
+ */
65
+ public function testPaths($basePath, $cacheKey, $rootPath)
66
+ {
67
+ $loader = new Twig_Loader_Filesystem(array($basePath.'/normal', $basePath.'/normal_bis'), $rootPath);
68
+ $loader->setPaths(array($basePath.'/named', $basePath.'/named_bis'), 'named');
69
+ $loader->addPath($basePath.'/named_ter', 'named');
70
+ $loader->addPath($basePath.'/normal_ter');
71
+ $loader->prependPath($basePath.'/normal_final');
72
+ $loader->prependPath($basePath.'/named/../named_quater', 'named');
73
+ $loader->prependPath($basePath.'/named_final', 'named');
74
+
75
+ $this->assertEquals(array(
76
+ $basePath.'/normal_final',
77
+ $basePath.'/normal',
78
+ $basePath.'/normal_bis',
79
+ $basePath.'/normal_ter',
80
+ ), $loader->getPaths());
81
+ $this->assertEquals(array(
82
+ $basePath.'/named_final',
83
+ $basePath.'/named/../named_quater',
84
+ $basePath.'/named',
85
+ $basePath.'/named_bis',
86
+ $basePath.'/named_ter',
87
+ ), $loader->getPaths('named'));
88
+
89
+ // do not use realpath here as it would make the test unuseful
90
+ $this->assertEquals($cacheKey, str_replace('\\', '/', $loader->getCacheKey('@named/named_absolute.html')));
91
+ $this->assertEquals("path (final)\n", $loader->getSourceContext('index.html')->getCode());
92
+ $this->assertEquals("path (final)\n", $loader->getSourceContext('@__main__/index.html')->getCode());
93
+ $this->assertEquals("named path (final)\n", $loader->getSourceContext('@named/index.html')->getCode());
94
+ }
95
+
96
+ public function getBasePaths()
97
+ {
98
+ return array(
99
+ array(
100
+ dirname(__FILE__).'/Fixtures',
101
+ 'test/Twig/Tests/Loader/Fixtures/named_quater/named_absolute.html',
102
+ null,
103
+ ),
104
+ array(
105
+ dirname(__FILE__).'/Fixtures/../Fixtures',
106
+ 'test/Twig/Tests/Loader/Fixtures/named_quater/named_absolute.html',
107
+ null,
108
+ ),
109
+ array(
110
+ 'test/Twig/Tests/Loader/Fixtures',
111
+ 'test/Twig/Tests/Loader/Fixtures/named_quater/named_absolute.html',
112
+ getcwd(),
113
+ ),
114
+ array(
115
+ 'Fixtures',
116
+ 'Fixtures/named_quater/named_absolute.html',
117
+ getcwd().'/test/Twig/Tests/Loader',
118
+ ),
119
+ array(
120
+ 'Fixtures',
121
+ 'Fixtures/named_quater/named_absolute.html',
122
+ getcwd().'/test/../test/Twig/Tests/Loader',
123
+ ),
124
+ );
125
+ }
126
+
127
+ public function testEmptyConstructor()
128
+ {
129
+ $loader = new Twig_Loader_Filesystem();
130
+ $this->assertEquals(array(), $loader->getPaths());
131
+ }
132
+
133
+ public function testGetNamespaces()
134
+ {
135
+ $loader = new Twig_Loader_Filesystem(sys_get_temp_dir());
136
+ $this->assertEquals(array(Twig_Loader_Filesystem::MAIN_NAMESPACE), $loader->getNamespaces());
137
+
138
+ $loader->addPath(sys_get_temp_dir(), 'named');
139
+ $this->assertEquals(array(Twig_Loader_Filesystem::MAIN_NAMESPACE, 'named'), $loader->getNamespaces());
140
+ }
141
+
142
+ public function testFindTemplateExceptionNamespace()
143
+ {
144
+ $basePath = dirname(__FILE__).'/Fixtures';
145
+
146
+ $loader = new Twig_Loader_Filesystem(array($basePath.'/normal'));
147
+ $loader->addPath($basePath.'/named', 'named');
148
+
149
+ try {
150
+ $loader->getSourceContext('@named/nowhere.html');
151
+ } catch (Exception $e) {
152
+ $this->assertInstanceof('Twig_Error_Loader', $e);
153
+ $this->assertContains('Unable to find template "@named/nowhere.html"', $e->getMessage());
154
+ }
155
+ }
156
+
157
+ public function testFindTemplateWithCache()
158
+ {
159
+ $basePath = dirname(__FILE__).'/Fixtures';
160
+
161
+ $loader = new Twig_Loader_Filesystem(array($basePath.'/normal'));
162
+ $loader->addPath($basePath.'/named', 'named');
163
+
164
+ // prime the cache for index.html in the named namespace
165
+ $namedSource = $loader->getSourceContext('@named/index.html')->getCode();
166
+ $this->assertEquals("named path\n", $namedSource);
167
+
168
+ // get index.html from the main namespace
169
+ $this->assertEquals("path\n", $loader->getSourceContext('index.html')->getCode());
170
+ }
171
+
172
+ public function testLoadTemplateAndRenderBlockWithCache()
173
+ {
174
+ $loader = new Twig_Loader_Filesystem(array());
175
+ $loader->addPath(dirname(__FILE__).'/Fixtures/themes/theme2');
176
+ $loader->addPath(dirname(__FILE__).'/Fixtures/themes/theme1');
177
+ $loader->addPath(dirname(__FILE__).'/Fixtures/themes/theme1', 'default_theme');
178
+
179
+ $twig = new Twig_Environment($loader);
180
+
181
+ $template = $twig->loadTemplate('blocks.html.twig');
182
+ $this->assertSame('block from theme 1', $template->renderBlock('b1', array()));
183
+
184
+ $template = $twig->loadTemplate('blocks.html.twig');
185
+ $this->assertSame('block from theme 2', $template->renderBlock('b2', array()));
186
+ }
187
+
188
+ public function getArrayInheritanceTests()
189
+ {
190
+ return array(
191
+ 'valid array inheritance' => array('array_inheritance_valid_parent.html.twig'),
192
+ 'array inheritance with null first template' => array('array_inheritance_null_parent.html.twig'),
193
+ 'array inheritance with empty first template' => array('array_inheritance_empty_parent.html.twig'),
194
+ 'array inheritance with non-existent first template' => array('array_inheritance_nonexistent_parent.html.twig'),
195
+ );
196
+ }
197
+
198
+ /**
199
+ * @dataProvider getArrayInheritanceTests
200
+ *
201
+ * @param $templateName string Template name with array inheritance
202
+ */
203
+ public function testArrayInheritance($templateName)
204
+ {
205
+ $loader = new Twig_Loader_Filesystem(array());
206
+ $loader->addPath(dirname(__FILE__).'/Fixtures/inheritance');
207
+
208
+ $twig = new Twig_Environment($loader);
209
+
210
+ $template = $twig->loadTemplate($templateName);
211
+ $this->assertSame('VALID Child', $template->renderBlock('body', array()));
212
+ }
213
+
214
+ /**
215
+ * @requires PHP 5.3
216
+ */
217
+ public function testLoadTemplateFromPhar()
218
+ {
219
+ $loader = new Twig_Loader_Filesystem(array());
220
+ // phar-sample.phar was created with the following script:
221
+ // $f = new Phar('phar-test.phar');
222
+ // $f->addFromString('hello.twig', 'hello from phar');
223
+ $loader->addPath('phar://'.dirname(__FILE__).'/Fixtures/phar/phar-sample.phar');
224
+ $this->assertSame('hello from phar', $loader->getSourceContext('hello.twig')->getCode());
225
+ }
226
+ }
library/twig/twig/test/Twig/Tests/Loader/Fixtures/inheritance/array_inheritance_empty_parent.html.twig ADDED
@@ -0,0 +1,3 @@
 
 
 
1
+ {% extends ['','parent.html.twig'] %}
2
+
3
+ {% block body %}{{ parent() }} Child{% endblock %}
library/twig/twig/test/Twig/Tests/Loader/Fixtures/inheritance/array_inheritance_nonexistent_parent.html.twig ADDED
@@ -0,0 +1,3 @@
 
 
 
1
+ {% extends ['nonexistent.html.twig','parent.html.twig'] %}
2
+
3
+ {% block body %}{{ parent() }} Child{% endblock %}
library/twig/twig/test/Twig/Tests/Loader/Fixtures/inheritance/array_inheritance_null_parent.html.twig ADDED
@@ -0,0 +1,3 @@
 
 
 
1
+ {% extends [null,'parent.html.twig'] %}
2
+
3
+ {% block body %}{{ parent() }} Child{% endblock %}
library/twig/twig/test/Twig/Tests/Loader/Fixtures/inheritance/array_inheritance_valid_parent.html.twig ADDED
@@ -0,0 +1,3 @@
 
 
 
1
+ {% extends ['parent.html.twig','spare_parent.html.twig'] %}
2
+
3
+ {% block body %}{{ parent() }} Child{% endblock %}
library/twig/twig/test/Twig/Tests/Loader/Fixtures/inheritance/parent.html.twig ADDED
@@ -0,0 +1 @@
 
1
+ {% block body %}VALID{% endblock %}
library/twig/twig/test/Twig/Tests/Loader/Fixtures/inheritance/spare_parent.html.twig ADDED
@@ -0,0 +1 @@
 
1
+ {% block body %}SPARE PARENT{% endblock %}
library/twig/twig/test/Twig/Tests/Loader/Fixtures/named/index.html ADDED
@@ -0,0 +1 @@
 
1
+ named path
library/twig/twig/test/Twig/Tests/Loader/Fixtures/named_bis/index.html ADDED
@@ -0,0 +1 @@
 
1
+ named path (bis)
library/twig/twig/test/Twig/Tests/Loader/Fixtures/named_final/index.html ADDED
@@ -0,0 +1 @@
 
1
+ named path (final)
library/twig/twig/test/Twig/Tests/Loader/Fixtures/named_quater/named_absolute.html ADDED
@@ -0,0 +1 @@
 
1
+ named path (quater)
library/twig/twig/test/Twig/Tests/Loader/Fixtures/named_ter/index.html ADDED
@@ -0,0 +1 @@
 
1
+ named path (ter)
library/twig/twig/test/Twig/Tests/Loader/Fixtures/normal/index.html ADDED
@@ -0,0 +1 @@
 
1
+ path
library/twig/twig/test/Twig/Tests/Loader/Fixtures/normal_bis/index.html ADDED
@@ -0,0 +1 @@
 
1
+ path (bis)
library/twig/twig/test/Twig/Tests/Loader/Fixtures/normal_final/index.html ADDED
@@ -0,0 +1 @@
 
1
+ path (final)
library/twig/twig/test/Twig/Tests/Loader/Fixtures/normal_ter/index.html ADDED
@@ -0,0 +1 @@
 
1
+ path (ter)
library/twig/twig/test/Twig/Tests/Loader/Fixtures/phar/phar-sample.phar ADDED
Binary file
library/twig/twig/test/Twig/Tests/Loader/Fixtures/themes/theme1/blocks.html.twig ADDED
@@ -0,0 +1,3 @@
 
 
 
1
+ {% block b1 %}block from theme 1{% endblock %}
2
+
3
+ {% block b2 %}block from theme 1{% endblock %}
library/twig/twig/test/Twig/Tests/Loader/Fixtures/themes/theme2/blocks.html.twig ADDED
@@ -0,0 +1,3 @@
 
 
 
1
+ {% use '@default_theme/blocks.html.twig' %}
2
+
3
+ {% block b2 %}block from theme 2{% endblock %}
library/twig/twig/test/Twig/Tests/NativeExtensionTest.php ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 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_Tests_NativeExtensionTest extends PHPUnit_Framework_TestCase
13
+ {
14
+ /**
15
+ * @requires PHP 5.3
16
+ */
17
+ public function testGetProperties()
18
+ {
19
+ if (defined('HHVM_VERSION')) {
20
+ $this->markTestSkipped('Skip under HHVM as the behavior is not the same as plain PHP (which is an edge case anyway)');
21
+ }
22
+
23
+ $twig = new Twig_Environment(new Twig_Loader_Array(array('index' => '{{ d1.date }}{{ d2.date }}')), array(
24
+ 'debug' => true,
25
+ 'cache' => false,
26
+ 'autoescape' => false,
27
+ ));
28
+
29
+ $d1 = new DateTime();
30
+ $d2 = new DateTime();
31
+ $output = $twig->render('index', compact('d1', 'd2'));
32
+
33
+ // If it fails, PHP will crash.
34
+ $this->assertEquals($output, $d1->date.$d2->date);
35
+ }
36
+ }
library/twig/twig/test/Twig/Tests/Node/AutoEscapeTest.php ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 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_Tests_Node_AutoEscapeTest extends Twig_Test_NodeTestCase
13
+ {
14
+ public function testConstructor()
15
+ {
16
+ $body = new Twig_Node(array(new Twig_Node_Text('foo', 1)));
17
+ $node = new Twig_Node_AutoEscape(true, $body, 1);
18
+
19
+ $this->assertEquals($body, $node->getNode('body'));
20
+ $this->assertTrue($node->getAttribute('value'));
21
+ }
22
+
23
+ public function getTests()
24
+ {
25
+ $body = new Twig_Node(array(new Twig_Node_Text('foo', 1)));
26
+ $node = new Twig_Node_AutoEscape(true, $body, 1);
27
+
28
+ return array(
29
+ array($node, "// line 1\necho \"foo\";"),
30
+ );
31
+ }
32
+ }
library/twig/twig/test/Twig/Tests/Node/BlockReferenceTest.php ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 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_Tests_Node_BlockReferenceTest extends Twig_Test_NodeTestCase
13
+ {
14
+ public function testConstructor()
15
+ {
16
+ $node = new Twig_Node_BlockReference('foo', 1);
17
+
18
+ $this->assertEquals('foo', $node->getAttribute('name'));
19
+ }
20
+
21
+ public function getTests()
22
+ {
23
+ return array(
24
+ array(new Twig_Node_BlockReference('foo', 1), <<<EOF
25
+ // line 1
26
+ \$this->displayBlock('foo', \$context, \$blocks);
27
+ EOF
28
+ ),
29
+ );
30
+ }
31
+ }
library/twig/twig/test/Twig/Tests/Node/BlockTest.php ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 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_Tests_Node_BlockTest extends Twig_Test_NodeTestCase
13
+ {
14
+ public function testConstructor()
15
+ {
16
+ $body = new Twig_Node_Text('foo', 1);
17
+ $node = new Twig_Node_Block('foo', $body, 1);
18
+
19
+ $this->assertEquals($body, $node->getNode('body'));
20
+ $this->assertEquals('foo', $node->getAttribute('name'));
21
+ }
22
+
23
+ public function getTests()
24
+ {
25
+ $body = new Twig_Node_Text('foo', 1);
26
+ $node = new Twig_Node_Block('foo', $body, 1);
27
+
28
+ return array(
29
+ array($node, <<<EOF
30
+ // line 1
31
+ public function block_foo(\$context, array \$blocks = array())
32
+ {
33
+ echo "foo";
34
+ }
35
+ EOF
36
+ ),
37
+ );
38
+ }
39
+ }
library/twig/twig/test/Twig/Tests/Node/DoTest.php ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 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_Tests_Node_DoTest extends Twig_Test_NodeTestCase
13
+ {
14
+ public function testConstructor()
15
+ {
16
+ $expr = new Twig_Node_Expression_Constant('foo', 1);
17
+ $node = new Twig_Node_Do($expr, 1);
18
+
19
+ $this->assertEquals($expr, $node->getNode('expr'));
20
+ }
21
+
22
+ public function getTests()
23
+ {
24
+ $tests = array();
25
+
26
+ $expr = new Twig_Node_Expression_Constant('foo', 1);
27
+ $node = new Twig_Node_Do($expr, 1);
28
+ $tests[] = array($node, "// line 1\n\"foo\";");
29
+
30
+ return $tests;
31
+ }
32
+ }
library/twig/twig/test/Twig/Tests/Node/Expression/ArrayTest.php ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 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_Tests_Node_Expression_ArrayTest extends Twig_Test_NodeTestCase
13
+ {
14
+ public function testConstructor()
15
+ {
16
+ $elements = array(new Twig_Node_Expression_Constant('foo', 1), $foo = new Twig_Node_Expression_Constant('bar', 1));
17
+ $node = new Twig_Node_Expression_Array($elements, 1);
18
+
19
+ $this->assertEquals($foo, $node->getNode(1));
20
+ }
21
+
22
+ public function getTests()
23
+ {
24
+ $elements = array(
25
+ new Twig_Node_Expression_Constant('foo', 1),
26
+ new Twig_Node_Expression_Constant('bar', 1),
27
+
28
+ new Twig_Node_Expression_Constant('bar', 1),
29
+ new Twig_Node_Expression_Constant('foo', 1),
30
+ );
31
+ $node = new Twig_Node_Expression_Array($elements, 1);
32
+
33
+ return array(
34
+ array($node, 'array("foo" => "bar", "bar" => "foo")'),
35
+ );
36
+ }
37
+ }
library/twig/twig/test/Twig/Tests/Node/Expression/AssignNameTest.php ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 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_Tests_Node_Expression_AssignNameTest extends Twig_Test_NodeTestCase
13
+ {
14
+ public function testConstructor()
15
+ {
16
+ $node = new Twig_Node_Expression_AssignName('foo', 1);
17
+
18
+ $this->assertEquals('foo', $node->getAttribute('name'));
19
+ }
20
+
21
+ public function getTests()
22
+ {
23
+ $node = new Twig_Node_Expression_AssignName('foo', 1);
24
+
25
+ return array(
26
+ array($node, '$context["foo"]'),
27
+ );
28
+ }
29
+ }
library/twig/twig/test/Twig/Tests/Node/Expression/Binary/AddTest.php ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 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_Tests_Node_Expression_Binary_AddTest extends Twig_Test_NodeTestCase
13
+ {
14
+ public function testConstructor()
15
+ {
16
+ $left = new Twig_Node_Expression_Constant(1, 1);
17
+ $right = new Twig_Node_Expression_Constant(2, 1);
18
+ $node = new Twig_Node_Expression_Binary_Add($left, $right, 1);
19
+
20
+ $this->assertEquals($left, $node->getNode('left'));
21
+ $this->assertEquals($right, $node->getNode('right'));
22
+ }
23
+
24
+ public function getTests()
25
+ {
26
+ $left = new Twig_Node_Expression_Constant(1, 1);
27
+ $right = new Twig_Node_Expression_Constant(2, 1);
28
+ $node = new Twig_Node_Expression_Binary_Add($left, $right, 1);
29
+
30
+ return array(
31
+ array($node, '(1 + 2)'),
32
+ );
33
+ }
34
+ }
library/twig/twig/test/Twig/Tests/Node/Expression/Binary/AndTest.php ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 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_Tests_Node_Expression_Binary_AndTest extends Twig_Test_NodeTestCase
13
+ {
14
+ public function testConstructor()
15
+ {
16
+ $left = new Twig_Node_Expression_Constant(1, 1);
17
+ $right = new Twig_Node_Expression_Constant(2, 1);
18
+ $node = new Twig_Node_Expression_Binary_And($left, $right, 1);
19
+
20
+ $this->assertEquals($left, $node->getNode('left'));
21
+ $this->assertEquals($right, $node->getNode('right'));
22
+ }
23
+
24
+ public function getTests()
25
+ {
26
+ $left = new Twig_Node_Expression_Constant(1, 1);
27
+ $right = new Twig_Node_Expression_Constant(2, 1);
28
+ $node = new Twig_Node_Expression_Binary_And($left, $right, 1);
29
+
30
+ return array(
31
+ array($node, '(1 && 2)'),
32
+ );
33
+ }
34
+ }
library/twig/twig/test/Twig/Tests/Node/Expression/Binary/ConcatTest.php ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 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_Tests_Node_Expression_Binary_ConcatTest extends Twig_Test_NodeTestCase
13
+ {
14
+ public function testConstructor()
15
+ {
16
+ $left = new Twig_Node_Expression_Constant(1, 1);
17
+ $right = new Twig_Node_Expression_Constant(2, 1);
18
+ $node = new Twig_Node_Expression_Binary_Concat($left, $right, 1);
19
+
20
+ $this->assertEquals($left, $node->getNode('left'));
21
+ $this->assertEquals($right, $node->getNode('right'));
22
+ }
23
+
24
+ public function getTests()
25
+ {
26
+ $left = new Twig_Node_Expression_Constant(1, 1);
27
+ $right = new Twig_Node_Expression_Constant(2, 1);
28
+ $node = new Twig_Node_Expression_Binary_Concat($left, $right, 1);
29
+
30
+ return array(
31
+ array($node, '(1 . 2)'),
32
+ );
33
+ }
34
+ }
library/twig/twig/test/Twig/Tests/Node/Expression/Binary/DivTest.php ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 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_Tests_Node_Expression_Binary_DivTest extends Twig_Test_NodeTestCase
13
+ {
14
+ public function testConstructor()
15
+ {
16
+ $left = new Twig_Node_Expression_Constant(1, 1);
17
+ $right = new Twig_Node_Expression_Constant(2, 1);
18
+ $node = new Twig_Node_Expression_Binary_Div($left, $right, 1);
19
+
20
+ $this->assertEquals($left, $node->getNode('left'));
21
+ $this->assertEquals($right, $node->getNode('right'));
22
+ }
23
+
24
+ public function getTests()
25
+ {
26
+ $left = new Twig_Node_Expression_Constant(1, 1);
27
+ $right = new Twig_Node_Expression_Constant(2, 1);
28
+ $node = new Twig_Node_Expression_Binary_Div($left, $right, 1);
29
+
30
+ return array(
31
+ array($node, '(1 / 2)'),
32
+ );
33
+ }
34
+ }
library/twig/twig/test/Twig/Tests/Node/Expression/Binary/FloorDivTest.php ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 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_Tests_Node_Expression_Binary_FloorDivTest extends Twig_Test_NodeTestCase
13
+ {
14
+ public function testConstructor()
15
+ {
16
+ $left = new Twig_Node_Expression_Constant(1, 1);
17
+ $right = new Twig_Node_Expression_Constant(2, 1);
18
+ $node = new Twig_Node_Expression_Binary_FloorDiv($left, $right, 1);
19
+
20
+ $this->assertEquals($left, $node->getNode('left'));
21
+ $this->assertEquals($right, $node->getNode('right'));
22
+ }
23
+
24
+ public function getTests()
25
+ {
26
+ $left = new Twig_Node_Expression_Constant(1, 1);
27
+ $right = new Twig_Node_Expression_Constant(2, 1);
28
+ $node = new Twig_Node_Expression_Binary_FloorDiv($left, $right, 1);
29
+
30
+ return array(
31
+ array($node, '(int) floor((1 / 2))'),
32
+ );
33
+ }
34
+ }
library/twig/twig/test/Twig/Tests/Node/Expression/Binary/ModTest.php ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 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_Tests_Node_Expression_Binary_ModTest extends Twig_Test_NodeTestCase
13
+ {
14
+ public function testConstructor()
15
+ {
16
+ $left = new Twig_Node_Expression_Constant(1, 1);
17
+ $right = new Twig_Node_Expression_Constant(2, 1);
18
+ $node = new Twig_Node_Expression_Binary_Mod($left, $right, 1);
19
+
20
+ $this->assertEquals($left, $node->getNode('left'));
21
+ $this->assertEquals($right, $node->getNode('right'));
22
+ }
23
+
24
+ public function getTests()
25
+ {
26
+ $left = new Twig_Node_Expression_Constant(1, 1);
27
+ $right = new Twig_Node_Expression_Constant(2, 1);
28
+ $node = new Twig_Node_Expression_Binary_Mod($left, $right, 1);
29
+
30
+ return array(
31
+ array($node, '(1 % 2)'),
32
+ );
33
+ }
34
+ }
library/twig/twig/test/Twig/Tests/Node/Expression/Binary/MulTest.php ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 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_Tests_Node_Expression_Binary_MulTest extends Twig_Test_NodeTestCase
13
+ {
14
+ public function testConstructor()
15
+ {
16
+ $left = new Twig_Node_Expression_Constant(1, 1);
17
+ $right = new Twig_Node_Expression_Constant(2, 1);
18
+ $node = new Twig_Node_Expression_Binary_Mul($left, $right, 1);
19
+
20
+ $this->assertEquals($left, $node->getNode('left'));
21
+ $this->assertEquals($right, $node->getNode('right'));
22
+ }
23
+
24
+ public function getTests()
25
+ {
26
+ $left = new Twig_Node_Expression_Constant(1, 1);
27
+ $right = new Twig_Node_Expression_Constant(2, 1);
28
+ $node = new Twig_Node_Expression_Binary_Mul($left, $right, 1);
29
+
30
+ return array(
31
+ array($node, '(1 * 2)'),
32
+ );
33
+ }
34
+ }
library/twig/twig/test/Twig/Tests/Node/Expression/Binary/OrTest.php ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 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_Tests_Node_Expression_Binary_OrTest extends Twig_Test_NodeTestCase
13
+ {
14
+ public function testConstructor()
15
+ {
16
+ $left = new Twig_Node_Expression_Constant(1, 1);
17
+ $right = new Twig_Node_Expression_Constant(2, 1);
18
+ $node = new Twig_Node_Expression_Binary_Or($left, $right, 1);
19
+
20
+ $this->assertEquals($left, $node->getNode('left'));
21
+ $this->assertEquals($right, $node->getNode('right'));
22
+ }
23
+
24
+ public function getTests()
25
+ {
26
+ $left = new Twig_Node_Expression_Constant(1, 1);
27
+ $right = new Twig_Node_Expression_Constant(2, 1);
28
+ $node = new Twig_Node_Expression_Binary_Or($left, $right, 1);
29
+
30
+ return array(
31
+ array($node, '(1 || 2)'),
32
+ );
33
+ }
34
+ }
library/twig/twig/test/Twig/Tests/Node/Expression/Binary/SubTest.php ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 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_Tests_Node_Expression_Binary_SubTest extends Twig_Test_NodeTestCase
13
+ {
14
+ public function testConstructor()
15
+ {
16
+ $left = new Twig_Node_Expression_Constant(1, 1);
17
+ $right = new Twig_Node_Expression_Constant(2, 1);
18
+ $node = new Twig_Node_Expression_Binary_Sub($left, $right, 1);
19
+
20
+ $this->assertEquals($left, $node->getNode('left'));
21
+ $this->assertEquals($right, $node->getNode('right'));
22
+ }
23
+
24
+ public function getTests()
25
+ {
26
+ $left = new Twig_Node_Expression_Constant(1, 1);
27
+ $right = new Twig_Node_Expression_Constant(2, 1);
28
+ $node = new Twig_Node_Expression_Binary_Sub($left, $right, 1);
29
+
30
+ return array(
31
+ array($node, '(1 - 2)'),
32
+ );
33
+ }
34
+ }
library/twig/twig/test/Twig/Tests/Node/Expression/CallTest.php ADDED
@@ -0,0 +1,147 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 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_Tests_Node_Expression_CallTest extends PHPUnit_Framework_TestCase
13
+ {
14
+ public function testGetArguments()
15
+ {
16
+ $node = new Twig_Tests_Node_Expression_Call(array(), array('type' => 'function', 'name' => 'date'));
17
+ $this->assertEquals(array('U', null), $node->getArguments('date', array('format' => 'U', 'timestamp' => null)));
18
+ }
19
+
20
+ /**
21
+ * @expectedException Twig_Error_Syntax
22
+ * @expectedExceptionMessage Positional arguments cannot be used after named arguments for function "date".
23
+ */
24
+ public function testGetArgumentsWhenPositionalArgumentsAfterNamedArguments()
25
+ {
26
+ $node = new Twig_Tests_Node_Expression_Call(array(), array('type' => 'function', 'name' => 'date'));
27
+ $node->getArguments('date', array('timestamp' => 123456, 'Y-m-d'));
28
+ }
29
+
30
+ /**
31
+ * @expectedException Twig_Error_Syntax
32
+ * @expectedExceptionMessage Argument "format" is defined twice for function "date".
33
+ */
34
+ public function testGetArgumentsWhenArgumentIsDefinedTwice()
35
+ {
36
+ $node = new Twig_Tests_Node_Expression_Call(array(), array('type' => 'function', 'name' => 'date'));
37
+ $node->getArguments('date', array('Y-m-d', 'format' => 'U'));
38
+ }
39
+
40
+ /**
41
+ * @expectedException Twig_Error_Syntax
42
+ * @expectedExceptionMessage Unknown argument "unknown" for function "date(format, timestamp)".
43
+ */
44
+ public function testGetArgumentsWithWrongNamedArgumentName()
45
+ {
46
+ $node = new Twig_Tests_Node_Expression_Call(array(), array('type' => 'function', 'name' => 'date'));
47
+ $node->getArguments('date', array('Y-m-d', 'timestamp' => null, 'unknown' => ''));
48
+ }
49
+
50
+ /**
51
+ * @expectedException Twig_Error_Syntax
52
+ * @expectedExceptionMessage Unknown arguments "unknown1", "unknown2" for function "date(format, timestamp)".
53
+ */
54
+ public function testGetArgumentsWithWrongNamedArgumentNames()
55
+ {
56
+ $node = new Twig_Tests_Node_Expression_Call(array(), array('type' => 'function', 'name' => 'date'));
57
+ $node->getArguments('date', array('Y-m-d', 'timestamp' => null, 'unknown1' => '', 'unknown2' => ''));
58
+ }
59
+
60
+ /**
61
+ * @expectedException Twig_Error_Syntax
62
+ * @expectedExceptionMessage Argument "case_sensitivity" could not be assigned for function "substr_compare(main_str, str, offset, length, case_sensitivity)" because it is mapped to an internal PHP function which cannot determine default value for optional argument "length".
63
+ */
64
+ public function testResolveArgumentsWithMissingValueForOptionalArgument()
65
+ {
66
+ if (defined('HHVM_VERSION')) {
67
+ $this->markTestSkipped('Skip under HHVM as the behavior is not the same as plain PHP (which is an edge case anyway)');
68
+ }
69
+
70
+ $node = new Twig_Tests_Node_Expression_Call(array(), array('type' => 'function', 'name' => 'substr_compare'));
71
+ $node->getArguments('substr_compare', array('abcd', 'bc', 'offset' => 1, 'case_sensitivity' => true));
72
+ }
73
+
74
+ public function testResolveArgumentsOnlyNecessaryArgumentsForCustomFunction()
75
+ {
76
+ $node = new Twig_Tests_Node_Expression_Call(array(), array('type' => 'function', 'name' => 'custom_function'));
77
+
78
+ $this->assertEquals(array('arg1'), $node->getArguments(array($this, 'customFunction'), array('arg1' => 'arg1')));
79
+ }
80
+
81
+ public function testGetArgumentsForStaticMethod()
82
+ {
83
+ $node = new Twig_Tests_Node_Expression_Call(array(), array('type' => 'function', 'name' => 'custom_static_function'));
84
+ $this->assertEquals(array('arg1'), $node->getArguments(__CLASS__.'::customStaticFunction', array('arg1' => 'arg1')));
85
+ }
86
+
87
+ /**
88
+ * @expectedException LogicException
89
+ * @expectedExceptionMessage The last parameter of "Twig_Tests_Node_Expression_CallTest::customFunctionWithArbitraryArguments" for function "foo" must be an array with default value, eg. "array $arg = array()".
90
+ */
91
+ public function testResolveArgumentsWithMissingParameterForArbitraryArguments()
92
+ {
93
+ $node = new Twig_Tests_Node_Expression_Call(array(), array('type' => 'function', 'name' => 'foo', 'is_variadic' => true));
94
+ $node->getArguments(array($this, 'customFunctionWithArbitraryArguments'), array());
95
+ }
96
+
97
+ public static function customStaticFunction($arg1, $arg2 = 'default', $arg3 = array())
98
+ {
99
+ }
100
+
101
+ public function customFunction($arg1, $arg2 = 'default', $arg3 = array())
102
+ {
103
+ }
104
+
105
+ public function customFunctionWithArbitraryArguments()
106
+ {
107
+ }
108
+
109
+ /**
110
+ * @expectedException LogicException
111
+ * @expectedExceptionMessageRegExp #^The last parameter of "custom_Twig_Tests_Node_Expression_CallTest_function" for function "foo" must be an array with default value, eg\. "array \$arg \= array\(\)"\.$#
112
+ */
113
+ public function testResolveArgumentsWithMissingParameterForArbitraryArgumentsOnFunction()
114
+ {
115
+ $node = new Twig_Tests_Node_Expression_Call(array(), array('type' => 'function', 'name' => 'foo', 'is_variadic' => true));
116
+ $node->getArguments('custom_Twig_Tests_Node_Expression_CallTest_function', array());
117
+ }
118
+
119
+ /**
120
+ * @expectedException LogicException
121
+ * @expectedExceptionMessageRegExp #^The last parameter of "CallableTestClass\:\:__invoke" for function "foo" must be an array with default value, eg\. "array \$arg \= array\(\)"\.$#
122
+ */
123
+ public function testResolveArgumentsWithMissingParameterForArbitraryArgumentsOnObject()
124
+ {
125
+ $node = new Twig_Tests_Node_Expression_Call(array(), array('type' => 'function', 'name' => 'foo', 'is_variadic' => true));
126
+ $node->getArguments(new CallableTestClass(), array());
127
+ }
128
+ }
129
+
130
+ class Twig_Tests_Node_Expression_Call extends Twig_Node_Expression_Call
131
+ {
132
+ public function getArguments($callable, $arguments)
133
+ {
134
+ return parent::getArguments($callable, $arguments);
135
+ }
136
+ }
137
+
138
+ class CallableTestClass
139
+ {
140
+ public function __invoke($required)
141
+ {
142
+ }
143
+ }
144
+
145
+ function custom_Twig_Tests_Node_Expression_CallTest_function($required)
146
+ {
147
+ }
library/twig/twig/test/Twig/Tests/Node/Expression/ConditionalTest.php ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 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_Tests_Node_Expression_ConditionalTest extends Twig_Test_NodeTestCase
13
+ {
14
+ public function testConstructor()
15
+ {
16
+ $expr1 = new Twig_Node_Expression_Constant(1, 1);
17
+ $expr2 = new Twig_Node_Expression_Constant(2, 1);
18
+ $expr3 = new Twig_Node_Expression_Constant(3, 1);
19
+ $node = new Twig_Node_Expression_Conditional($expr1, $expr2, $expr3, 1);
20
+
21
+ $this->assertEquals($expr1, $node->getNode('expr1'));
22
+ $this->assertEquals($expr2, $node->getNode('expr2'));
23
+ $this->assertEquals($expr3, $node->getNode('expr3'));
24
+ }
25
+
26
+ public function getTests()
27
+ {
28
+ $tests = array();
29
+
30
+ $expr1 = new Twig_Node_Expression_Constant(1, 1);
31
+ $expr2 = new Twig_Node_Expression_Constant(2, 1);
32
+ $expr3 = new Twig_Node_Expression_Constant(3, 1);
33
+ $node = new Twig_Node_Expression_Conditional($expr1, $expr2, $expr3, 1);
34
+ $tests[] = array($node, '((1) ? (2) : (3))');
35
+
36
+ return $tests;
37
+ }
38
+ }
library/twig/twig/test/Twig/Tests/Node/Expression/ConstantTest.php ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 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_Tests_Node_Expression_ConstantTest extends Twig_Test_NodeTestCase
13
+ {
14
+ public function testConstructor()
15
+ {
16
+ $node = new Twig_Node_Expression_Constant('foo', 1);
17
+
18
+ $this->assertEquals('foo', $node->getAttribute('value'));
19
+ }
20
+
21
+ public function getTests()
22
+ {
23
+ $tests = array();
24
+
25
+ $node = new Twig_Node_Expression_Constant('foo', 1);
26
+ $tests[] = array($node, '"foo"');
27
+
28
+ return $tests;
29
+ }
30
+ }
library/twig/twig/test/Twig/Tests/Node/Expression/FilterTest.php ADDED
@@ -0,0 +1,154 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 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_Tests_Node_Expression_FilterTest extends Twig_Test_NodeTestCase
13
+ {
14
+ public function testConstructor()
15
+ {
16
+ $expr = new Twig_Node_Expression_Constant('foo', 1);
17
+ $name = new Twig_Node_Expression_Constant('upper', 1);
18
+ $args = new Twig_Node();
19
+ $node = new Twig_Node_Expression_Filter($expr, $name, $args, 1);
20
+
21
+ $this->assertEquals($expr, $node->getNode('node'));
22
+ $this->assertEquals($name, $node->getNode('filter'));
23
+ $this->assertEquals($args, $node->getNode('arguments'));
24
+ }
25
+
26
+ public function getTests()
27
+ {
28
+ $environment = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock());
29
+ $environment->addFilter(new Twig_SimpleFilter('bar', 'bar', array('needs_environment' => true)));
30
+ $environment->addFilter(new Twig_SimpleFilter('barbar', 'twig_tests_filter_barbar', array('needs_context' => true, 'is_variadic' => true)));
31
+
32
+ $tests = array();
33
+
34
+ $expr = new Twig_Node_Expression_Constant('foo', 1);
35
+ $node = $this->createFilter($expr, 'upper');
36
+ $node = $this->createFilter($node, 'number_format', array(new Twig_Node_Expression_Constant(2, 1), new Twig_Node_Expression_Constant('.', 1), new Twig_Node_Expression_Constant(',', 1)));
37
+
38
+ if (function_exists('mb_get_info')) {
39
+ $tests[] = array($node, 'twig_number_format_filter($this->env, twig_upper_filter($this->env, "foo"), 2, ".", ",")');
40
+ } else {
41
+ $tests[] = array($node, 'twig_number_format_filter($this->env, strtoupper("foo"), 2, ".", ",")');
42
+ }
43
+
44
+ // named arguments
45
+ $date = new Twig_Node_Expression_Constant(0, 1);
46
+ $node = $this->createFilter($date, 'date', array(
47
+ 'timezone' => new Twig_Node_Expression_Constant('America/Chicago', 1),
48
+ 'format' => new Twig_Node_Expression_Constant('d/m/Y H:i:s P', 1),
49
+ ));
50
+ $tests[] = array($node, 'twig_date_format_filter($this->env, 0, "d/m/Y H:i:s P", "America/Chicago")');
51
+
52
+ // skip an optional argument
53
+ $date = new Twig_Node_Expression_Constant(0, 1);
54
+ $node = $this->createFilter($date, 'date', array(
55
+ 'timezone' => new Twig_Node_Expression_Constant('America/Chicago', 1),
56
+ ));
57
+ $tests[] = array($node, 'twig_date_format_filter($this->env, 0, null, "America/Chicago")');
58
+
59
+ // underscores vs camelCase for named arguments
60
+ $string = new Twig_Node_Expression_Constant('abc', 1);
61
+ $node = $this->createFilter($string, 'reverse', array(
62
+ 'preserve_keys' => new Twig_Node_Expression_Constant(true, 1),
63
+ ));
64
+ $tests[] = array($node, 'twig_reverse_filter($this->env, "abc", true)');
65
+ $node = $this->createFilter($string, 'reverse', array(
66
+ 'preserveKeys' => new Twig_Node_Expression_Constant(true, 1),
67
+ ));
68
+ $tests[] = array($node, 'twig_reverse_filter($this->env, "abc", true)');
69
+
70
+ // filter as an anonymous function
71
+ if (PHP_VERSION_ID >= 50300) {
72
+ $node = $this->createFilter(new Twig_Node_Expression_Constant('foo', 1), 'anonymous');
73
+ $tests[] = array($node, 'call_user_func_array($this->env->getFilter(\'anonymous\')->getCallable(), array("foo"))');
74
+ }
75
+
76
+ // needs environment
77
+ $node = $this->createFilter($string, 'bar');
78
+ $tests[] = array($node, 'bar($this->env, "abc")', $environment);
79
+
80
+ $node = $this->createFilter($string, 'bar', array(new Twig_Node_Expression_Constant('bar', 1)));
81
+ $tests[] = array($node, 'bar($this->env, "abc", "bar")', $environment);
82
+
83
+ // arbitrary named arguments
84
+ $node = $this->createFilter($string, 'barbar');
85
+ $tests[] = array($node, 'twig_tests_filter_barbar($context, "abc")', $environment);
86
+
87
+ $node = $this->createFilter($string, 'barbar', array('foo' => new Twig_Node_Expression_Constant('bar', 1)));
88
+ $tests[] = array($node, 'twig_tests_filter_barbar($context, "abc", null, null, array("foo" => "bar"))', $environment);
89
+
90
+ $node = $this->createFilter($string, 'barbar', array('arg2' => new Twig_Node_Expression_Constant('bar', 1)));
91
+ $tests[] = array($node, 'twig_tests_filter_barbar($context, "abc", null, "bar")', $environment);
92
+
93
+ $node = $this->createFilter($string, 'barbar', array(
94
+ new Twig_Node_Expression_Constant('1', 1),
95
+ new Twig_Node_Expression_Constant('2', 1),
96
+ new Twig_Node_Expression_Constant('3', 1),
97
+ 'foo' => new Twig_Node_Expression_Constant('bar', 1),
98
+ ));
99
+ $tests[] = array($node, 'twig_tests_filter_barbar($context, "abc", "1", "2", array(0 => "3", "foo" => "bar"))', $environment);
100
+
101
+ return $tests;
102
+ }
103
+
104
+ /**
105
+ * @expectedException Twig_Error_Syntax
106
+ * @expectedExceptionMessage Unknown argument "foobar" for filter "date(format, timezone)" at line 1.
107
+ */
108
+ public function testCompileWithWrongNamedArgumentName()
109
+ {
110
+ $date = new Twig_Node_Expression_Constant(0, 1);
111
+ $node = $this->createFilter($date, 'date', array(
112
+ 'foobar' => new Twig_Node_Expression_Constant('America/Chicago', 1),
113
+ ));
114
+
115
+ $compiler = $this->getCompiler();
116
+ $compiler->compile($node);
117
+ }
118
+
119
+ /**
120
+ * @expectedException Twig_Error_Syntax
121
+ * @expectedExceptionMessage Value for argument "from" is required for filter "replace".
122
+ */
123
+ public function testCompileWithMissingNamedArgument()
124
+ {
125
+ $value = new Twig_Node_Expression_Constant(0, 1);
126
+ $node = $this->createFilter($value, 'replace', array(
127
+ 'to' => new Twig_Node_Expression_Constant('foo', 1),
128
+ ));
129
+
130
+ $compiler = $this->getCompiler();
131
+ $compiler->compile($node);
132
+ }
133
+
134
+ protected function createFilter($node, $name, array $arguments = array())
135
+ {
136
+ $name = new Twig_Node_Expression_Constant($name, 1);
137
+ $arguments = new Twig_Node($arguments);
138
+
139
+ return new Twig_Node_Expression_Filter($node, $name, $arguments, 1);
140
+ }
141
+
142
+ protected function getEnvironment()
143
+ {
144
+ if (PHP_VERSION_ID >= 50300) {
145
+ return include 'PHP53/FilterInclude.php';
146
+ }
147
+
148
+ return parent::getEnvironment();
149
+ }
150
+ }
151
+
152
+ function twig_tests_filter_barbar($context, $string, $arg1 = null, $arg2 = null, array $args = array())
153
+ {
154
+ }
library/twig/twig/test/Twig/Tests/Node/Expression/FunctionTest.php ADDED
@@ -0,0 +1,110 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 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_Tests_Node_Expression_FunctionTest extends Twig_Test_NodeTestCase
13
+ {
14
+ public function testConstructor()
15
+ {
16
+ $name = 'function';
17
+ $args = new Twig_Node();
18
+ $node = new Twig_Node_Expression_Function($name, $args, 1);
19
+
20
+ $this->assertEquals($name, $node->getAttribute('name'));
21
+ $this->assertEquals($args, $node->getNode('arguments'));
22
+ }
23
+
24
+ public function getTests()
25
+ {
26
+ $environment = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock());
27
+ $environment->addFunction(new Twig_SimpleFunction('foo', 'foo', array()));
28
+ $environment->addFunction(new Twig_SimpleFunction('bar', 'bar', array('needs_environment' => true)));
29
+ $environment->addFunction(new Twig_SimpleFunction('foofoo', 'foofoo', array('needs_context' => true)));
30
+ $environment->addFunction(new Twig_SimpleFunction('foobar', 'foobar', array('needs_environment' => true, 'needs_context' => true)));
31
+ $environment->addFunction(new Twig_SimpleFunction('barbar', 'twig_tests_function_barbar', array('is_variadic' => true)));
32
+
33
+ $tests = array();
34
+
35
+ $node = $this->createFunction('foo');
36
+ $tests[] = array($node, 'foo()', $environment);
37
+
38
+ $node = $this->createFunction('foo', array(new Twig_Node_Expression_Constant('bar', 1), new Twig_Node_Expression_Constant('foobar', 1)));
39
+ $tests[] = array($node, 'foo("bar", "foobar")', $environment);
40
+
41
+ $node = $this->createFunction('bar');
42
+ $tests[] = array($node, 'bar($this->env)', $environment);
43
+
44
+ $node = $this->createFunction('bar', array(new Twig_Node_Expression_Constant('bar', 1)));
45
+ $tests[] = array($node, 'bar($this->env, "bar")', $environment);
46
+
47
+ $node = $this->createFunction('foofoo');
48
+ $tests[] = array($node, 'foofoo($context)', $environment);
49
+
50
+ $node = $this->createFunction('foofoo', array(new Twig_Node_Expression_Constant('bar', 1)));
51
+ $tests[] = array($node, 'foofoo($context, "bar")', $environment);
52
+
53
+ $node = $this->createFunction('foobar');
54
+ $tests[] = array($node, 'foobar($this->env, $context)', $environment);
55
+
56
+ $node = $this->createFunction('foobar', array(new Twig_Node_Expression_Constant('bar', 1)));
57
+ $tests[] = array($node, 'foobar($this->env, $context, "bar")', $environment);
58
+
59
+ // named arguments
60
+ $node = $this->createFunction('date', array(
61
+ 'timezone' => new Twig_Node_Expression_Constant('America/Chicago', 1),
62
+ 'date' => new Twig_Node_Expression_Constant(0, 1),
63
+ ));
64
+ $tests[] = array($node, 'twig_date_converter($this->env, 0, "America/Chicago")');
65
+
66
+ // arbitrary named arguments
67
+ $node = $this->createFunction('barbar');
68
+ $tests[] = array($node, 'twig_tests_function_barbar()', $environment);
69
+
70
+ $node = $this->createFunction('barbar', array('foo' => new Twig_Node_Expression_Constant('bar', 1)));
71
+ $tests[] = array($node, 'twig_tests_function_barbar(null, null, array("foo" => "bar"))', $environment);
72
+
73
+ $node = $this->createFunction('barbar', array('arg2' => new Twig_Node_Expression_Constant('bar', 1)));
74
+ $tests[] = array($node, 'twig_tests_function_barbar(null, "bar")', $environment);
75
+
76
+ $node = $this->createFunction('barbar', array(
77
+ new Twig_Node_Expression_Constant('1', 1),
78
+ new Twig_Node_Expression_Constant('2', 1),
79
+ new Twig_Node_Expression_Constant('3', 1),
80
+ 'foo' => new Twig_Node_Expression_Constant('bar', 1),
81
+ ));
82
+ $tests[] = array($node, 'twig_tests_function_barbar("1", "2", array(0 => "3", "foo" => "bar"))', $environment);
83
+
84
+ // function as an anonymous function
85
+ if (PHP_VERSION_ID >= 50300) {
86
+ $node = $this->createFunction('anonymous', array(new Twig_Node_Expression_Constant('foo', 1)));
87
+ $tests[] = array($node, 'call_user_func_array($this->env->getFunction(\'anonymous\')->getCallable(), array("foo"))');
88
+ }
89
+
90
+ return $tests;
91
+ }
92
+
93
+ protected function createFunction($name, array $arguments = array())
94
+ {
95
+ return new Twig_Node_Expression_Function($name, new Twig_Node($arguments), 1);
96
+ }
97
+
98
+ protected function getEnvironment()
99
+ {
100
+ if (PHP_VERSION_ID >= 50300) {
101
+ return include 'PHP53/FunctionInclude.php';
102
+ }
103
+
104
+ return parent::getEnvironment();
105
+ }
106
+ }
107
+
108
+ function twig_tests_function_barbar($arg1 = null, $arg2 = null, array $args = array())
109
+ {
110
+ }
library/twig/twig/test/Twig/Tests/Node/Expression/GetAttrTest.php ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 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_Tests_Node_Expression_GetAttrTest extends Twig_Test_NodeTestCase
13
+ {
14
+ public function testConstructor()
15
+ {
16
+ $expr = new Twig_Node_Expression_Name('foo', 1);
17
+ $attr = new Twig_Node_Expression_Constant('bar', 1);
18
+ $args = new Twig_Node_Expression_Array(array(), 1);
19
+ $args->addElement(new Twig_Node_Expression_Name('foo', 1));
20
+ $args->addElement(new Twig_Node_Expression_Constant('bar', 1));
21
+ $node = new Twig_Node_Expression_GetAttr($expr, $attr, $args, Twig_Template::ARRAY_CALL, 1);
22
+
23
+ $this->assertEquals($expr, $node->getNode('node'));
24
+ $this->assertEquals($attr, $node->getNode('attribute'));
25
+ $this->assertEquals($args, $node->getNode('arguments'));
26
+ $this->assertEquals(Twig_Template::ARRAY_CALL, $node->getAttribute('type'));
27
+ }
28
+
29
+ public function getTests()
30
+ {
31
+ $tests = array();
32
+
33
+ $expr = new Twig_Node_Expression_Name('foo', 1);
34
+ $attr = new Twig_Node_Expression_Constant('bar', 1);
35
+ $args = new Twig_Node_Expression_Array(array(), 1);
36
+ $node = new Twig_Node_Expression_GetAttr($expr, $attr, $args, Twig_Template::ANY_CALL, 1);
37
+ $tests[] = array($node, sprintf('%s%s, "bar", array())', $this->getAttributeGetter(), $this->getVariableGetter('foo', 1)));
38
+
39
+ $node = new Twig_Node_Expression_GetAttr($expr, $attr, $args, Twig_Template::ARRAY_CALL, 1);
40
+ $tests[] = array($node, sprintf('%s%s, "bar", array(), "array")', $this->getAttributeGetter(), $this->getVariableGetter('foo', 1)));
41
+
42
+ $args = new Twig_Node_Expression_Array(array(), 1);
43
+ $args->addElement(new Twig_Node_Expression_Name('foo', 1));
44
+ $args->addElement(new Twig_Node_Expression_Constant('bar', 1));
45
+ $node = new Twig_Node_Expression_GetAttr($expr, $attr, $args, Twig_Template::METHOD_CALL, 1);
46
+ $tests[] = array($node, sprintf('%s%s, "bar", array(0 => %s, 1 => "bar"), "method")', $this->getAttributeGetter(), $this->getVariableGetter('foo', 1), $this->getVariableGetter('foo')));
47
+
48
+ return $tests;
49
+ }
50
+ }
library/twig/twig/test/Twig/Tests/Node/Expression/NameTest.php ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 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_Tests_Node_Expression_NameTest extends Twig_Test_NodeTestCase
13
+ {
14
+ public function testConstructor()
15
+ {
16
+ $node = new Twig_Node_Expression_Name('foo', 1);
17
+
18
+ $this->assertEquals('foo', $node->getAttribute('name'));
19
+ }
20
+
21
+ public function getTests()
22
+ {
23
+ $node = new Twig_Node_Expression_Name('foo', 1);
24
+ $context = new Twig_Node_Expression_Name('_context', 1);
25
+
26
+ $env = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock(), array('strict_variables' => true));
27
+ $env1 = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock(), array('strict_variables' => false));
28
+
29
+ if (PHP_VERSION_ID >= 70000) {
30
+ $output = '($context["foo"] ?? $this->getContext($context, "foo"))';
31
+ } elseif (PHP_VERSION_ID >= 50400) {
32
+ $output = '(isset($context["foo"]) ? $context["foo"] : $this->getContext($context, "foo"))';
33
+ } else {
34
+ $output = '$this->getContext($context, "foo")';
35
+ }
36
+
37
+ return array(
38
+ array($node, "// line 1\n".$output, $env),
39
+ array($node, $this->getVariableGetter('foo', 1), $env1),
40
+ array($context, "// line 1\n\$context"),
41
+ );
42
+ }
43
+ }
library/twig/twig/test/Twig/Tests/Node/Expression/NullCoalesceTest.php ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 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_Tests_Node_Expression_NullCoalesceTest extends Twig_Test_NodeTestCase
13
+ {
14
+ public function getTests()
15
+ {
16
+ $tests = array();
17
+
18
+ $left = new Twig_Node_Expression_Name('foo', 1);
19
+ $right = new Twig_Node_Expression_Constant(2, 1);
20
+ $node = new Twig_Node_Expression_NullCoalesce($left, $right, 1);
21
+ if (PHP_VERSION_ID >= 70000) {
22
+ $tests[] = array($node, "((// line 1\n\$context[\"foo\"]) ?? (2))");
23
+ } elseif (PHP_VERSION_ID >= 50400) {
24
+ $tests[] = array($node, "(((// line 1\narray_key_exists(\"foo\", \$context) && !(null === (isset(\$context[\"foo\"]) ? \$context[\"foo\"] : null)))) ? ((isset(\$context[\"foo\"]) ? \$context[\"foo\"] : null)) : (2))");
25
+ } else {
26
+ $tests[] = array($node, "(((// line 1\narray_key_exists(\"foo\", \$context) && !(null === \$this->getContext(\$context, \"foo\")))) ? (\$this->getContext(\$context, \"foo\")) : (2))");
27
+ }
28
+
29
+ return $tests;
30
+ }
31
+ }
library/twig/twig/test/Twig/Tests/Node/Expression/PHP53/FilterInclude.php ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
1
+ <?php
2
+
3
+ $env = new Twig_Environment(new Twig_Loader_Array(array()));
4
+ $env->addFilter(new Twig_SimpleFilter('anonymous', function () {}));
5
+
6
+ return $env;
library/twig/twig/test/Twig/Tests/Node/Expression/PHP53/FunctionInclude.php ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
1
+ <?php
2
+
3
+ $env = new Twig_Environment(new Twig_Loader_Array(array()));
4
+ $env->addFunction(new Twig_SimpleFunction('anonymous', function () {}));
5
+
6
+ return $env;
library/twig/twig/test/Twig/Tests/Node/Expression/PHP53/TestInclude.php ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
1
+ <?php
2
+
3
+ $env = new Twig_Environment(new Twig_Loader_Array(array()));
4
+ $env->addTest(new Twig_SimpleTest('anonymous', function () {}));
5
+
6
+ return $env;
library/twig/twig/test/Twig/Tests/Node/Expression/ParentTest.php ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 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_Tests_Node_Expression_ParentTest extends Twig_Test_NodeTestCase
13
+ {
14
+ public function testConstructor()
15
+ {
16
+ $node = new Twig_Node_Expression_Parent('foo', 1);
17
+
18
+ $this->assertEquals('foo', $node->getAttribute('name'));
19
+ }
20
+
21
+ public function getTests()
22
+ {
23
+ $tests = array();
24
+ $tests[] = array(new Twig_Node_Expression_Parent('foo', 1), '$this->renderParentBlock("foo", $context, $blocks)');
25
+
26
+ return $tests;
27
+ }
28
+ }
library/twig/twig/test/Twig/Tests/Node/Expression/TestTest.php ADDED
@@ -0,0 +1,82 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 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_Tests_Node_Expression_TestTest extends Twig_Test_NodeTestCase
13
+ {
14
+ public function testConstructor()
15
+ {
16
+ $expr = new Twig_Node_Expression_Constant('foo', 1);
17
+ $name = new Twig_Node_Expression_Constant('null', 1);
18
+ $args = new Twig_Node();
19
+ $node = new Twig_Node_Expression_Test($expr, $name, $args, 1);
20
+
21
+ $this->assertEquals($expr, $node->getNode('node'));
22
+ $this->assertEquals($args, $node->getNode('arguments'));
23
+ $this->assertEquals($name, $node->getAttribute('name'));
24
+ }
25
+
26
+ public function getTests()
27
+ {
28
+ $environment = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock());
29
+ $environment->addTest(new Twig_SimpleTest('barbar', 'twig_tests_test_barbar', array('is_variadic' => true, 'need_context' => true)));
30
+
31
+ $tests = array();
32
+
33
+ $expr = new Twig_Node_Expression_Constant('foo', 1);
34
+ $node = new Twig_Node_Expression_Test_Null($expr, 'null', new Twig_Node(array()), 1);
35
+ $tests[] = array($node, '(null === "foo")');
36
+
37
+ // test as an anonymous function
38
+ if (PHP_VERSION_ID >= 50300) {
39
+ $node = $this->createTest(new Twig_Node_Expression_Constant('foo', 1), 'anonymous', array(new Twig_Node_Expression_Constant('foo', 1)));
40
+ $tests[] = array($node, 'call_user_func_array($this->env->getTest(\'anonymous\')->getCallable(), array("foo", "foo"))');
41
+ }
42
+
43
+ // arbitrary named arguments
44
+ $string = new Twig_Node_Expression_Constant('abc', 1);
45
+ $node = $this->createTest($string, 'barbar');
46
+ $tests[] = array($node, 'twig_tests_test_barbar("abc")', $environment);
47
+
48
+ $node = $this->createTest($string, 'barbar', array('foo' => new Twig_Node_Expression_Constant('bar', 1)));
49
+ $tests[] = array($node, 'twig_tests_test_barbar("abc", null, null, array("foo" => "bar"))', $environment);
50
+
51
+ $node = $this->createTest($string, 'barbar', array('arg2' => new Twig_Node_Expression_Constant('bar', 1)));
52
+ $tests[] = array($node, 'twig_tests_test_barbar("abc", null, "bar")', $environment);
53
+
54
+ $node = $this->createTest($string, 'barbar', array(
55
+ new Twig_Node_Expression_Constant('1', 1),
56
+ new Twig_Node_Expression_Constant('2', 1),
57
+ new Twig_Node_Expression_Constant('3', 1),
58
+ 'foo' => new Twig_Node_Expression_Constant('bar', 1),
59
+ ));
60
+ $tests[] = array($node, 'twig_tests_test_barbar("abc", "1", "2", array(0 => "3", "foo" => "bar"))', $environment);
61
+
62
+ return $tests;
63
+ }
64
+
65
+ protected function createTest($node, $name, array $arguments = array())
66
+ {
67
+ return new Twig_Node_Expression_Test($node, $name, new Twig_Node($arguments), 1);
68
+ }
69
+
70
+ protected function getEnvironment()
71
+ {
72
+ if (PHP_VERSION_ID >= 50300) {
73
+ return include 'PHP53/TestInclude.php';
74
+ }
75
+
76
+ return parent::getEnvironment();
77
+ }
78
+ }
79
+
80
+ function twig_tests_test_barbar($string, $arg1 = null, $arg2 = null, array $args = array())
81
+ {
82
+ }
library/twig/twig/test/Twig/Tests/Node/Expression/Unary/NegTest.php ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 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_Tests_Node_Expression_Unary_NegTest extends Twig_Test_NodeTestCase
13
+ {
14
+ public function testConstructor()
15
+ {
16
+ $expr = new Twig_Node_Expression_Constant(1, 1);
17
+ $node = new Twig_Node_Expression_Unary_Neg($expr, 1);
18
+
19
+ $this->assertEquals($expr, $node->getNode('node'));
20
+ }
21
+
22
+ public function getTests()
23
+ {
24
+ $node = new Twig_Node_Expression_Constant(1, 1);
25
+ $node = new Twig_Node_Expression_Unary_Neg($node, 1);
26
+
27
+ return array(
28
+ array($node, '-1'),
29
+ array(new Twig_Node_Expression_Unary_Neg($node, 1), '- -1'),
30
+ );
31
+ }
32
+ }
library/twig/twig/test/Twig/Tests/Node/Expression/Unary/NotTest.php ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 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_Tests_Node_Expression_Unary_NotTest extends Twig_Test_NodeTestCase
13
+ {
14
+ public function testConstructor()
15
+ {
16
+ $expr = new Twig_Node_Expression_Constant(1, 1);
17
+ $node = new Twig_Node_Expression_Unary_Not($expr, 1);
18
+
19
+ $this->assertEquals($expr, $node->getNode('node'));
20
+ }
21
+
22
+ public function getTests()
23
+ {
24
+ $node = new Twig_Node_Expression_Constant(1, 1);
25
+ $node = new Twig_Node_Expression_Unary_Not($node, 1);
26
+
27
+ return array(
28
+ array($node, '!1'),
29
+ );
30
+ }
31
+ }
library/twig/twig/test/Twig/Tests/Node/Expression/Unary/PosTest.php ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 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_Tests_Node_Expression_Unary_PosTest extends Twig_Test_NodeTestCase
13
+ {
14
+ public function testConstructor()
15
+ {
16
+ $expr = new Twig_Node_Expression_Constant(1, 1);
17
+ $node = new Twig_Node_Expression_Unary_Pos($expr, 1);
18
+
19
+ $this->assertEquals($expr, $node->getNode('node'));
20
+ }
21
+
22
+ public function getTests()
23
+ {
24
+ $node = new Twig_Node_Expression_Constant(1, 1);
25
+ $node = new Twig_Node_Expression_Unary_Pos($node, 1);
26
+
27
+ return array(
28
+ array($node, '+1'),
29
+ );
30
+ }
31
+ }
library/twig/twig/test/Twig/Tests/Node/ForTest.php ADDED
@@ -0,0 +1,191 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 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_Tests_Node_ForTest extends Twig_Test_NodeTestCase
13
+ {
14
+ public function testConstructor()
15
+ {
16
+ $keyTarget = new Twig_Node_Expression_AssignName('key', 1);
17
+ $valueTarget = new Twig_Node_Expression_AssignName('item', 1);
18
+ $seq = new Twig_Node_Expression_Name('items', 1);
19
+ $ifexpr = new Twig_Node_Expression_Constant(true, 1);
20
+ $body = new Twig_Node(array(new Twig_Node_Print(new Twig_Node_Expression_Name('foo', 1), 1)), array(), 1);
21
+ $else = null;
22
+ $node = new Twig_Node_For($keyTarget, $valueTarget, $seq, $ifexpr, $body, $else, 1);
23
+ $node->setAttribute('with_loop', false);
24
+
25
+ $this->assertEquals($keyTarget, $node->getNode('key_target'));
26
+ $this->assertEquals($valueTarget, $node->getNode('value_target'));
27
+ $this->assertEquals($seq, $node->getNode('seq'));
28
+ $this->assertTrue($node->getAttribute('ifexpr'));
29
+ $this->assertEquals('Twig_Node_If', get_class($node->getNode('body')));
30
+ $this->assertEquals($body, $node->getNode('body')->getNode('tests')->getNode(1)->getNode(0));
31
+ $this->assertFalse($node->hasNode('else'));
32
+
33
+ $else = new Twig_Node_Print(new Twig_Node_Expression_Name('foo', 1), 1);
34
+ $node = new Twig_Node_For($keyTarget, $valueTarget, $seq, $ifexpr, $body, $else, 1);
35
+ $node->setAttribute('with_loop', false);
36
+ $this->assertEquals($else, $node->getNode('else'));
37
+ }
38
+
39
+ public function getTests()
40
+ {
41
+ $tests = array();
42
+
43
+ $keyTarget = new Twig_Node_Expression_AssignName('key', 1);
44
+ $valueTarget = new Twig_Node_Expression_AssignName('item', 1);
45
+ $seq = new Twig_Node_Expression_Name('items', 1);
46
+ $ifexpr = null;
47
+ $body = new Twig_Node(array(new Twig_Node_Print(new Twig_Node_Expression_Name('foo', 1), 1)), array(), 1);
48
+ $else = null;
49
+ $node = new Twig_Node_For($keyTarget, $valueTarget, $seq, $ifexpr, $body, $else, 1);
50
+ $node->setAttribute('with_loop', false);
51
+
52
+ $tests[] = array($node, <<<EOF
53
+ // line 1
54
+ \$context['_parent'] = \$context;
55
+ \$context['_seq'] = twig_ensure_traversable({$this->getVariableGetter('items')});
56
+ foreach (\$context['_seq'] as \$context["key"] => \$context["item"]) {
57
+ echo {$this->getVariableGetter('foo')};
58
+ }
59
+ \$_parent = \$context['_parent'];
60
+ unset(\$context['_seq'], \$context['_iterated'], \$context['key'], \$context['item'], \$context['_parent'], \$context['loop']);
61
+ \$context = array_intersect_key(\$context, \$_parent) + \$_parent;
62
+ EOF
63
+ );
64
+
65
+ $keyTarget = new Twig_Node_Expression_AssignName('k', 1);
66
+ $valueTarget = new Twig_Node_Expression_AssignName('v', 1);
67
+ $seq = new Twig_Node_Expression_Name('values', 1);
68
+ $ifexpr = null;
69
+ $body = new Twig_Node(array(new Twig_Node_Print(new Twig_Node_Expression_Name('foo', 1), 1)), array(), 1);
70
+ $else = null;
71
+ $node = new Twig_Node_For($keyTarget, $valueTarget, $seq, $ifexpr, $body, $else, 1);
72
+ $node->setAttribute('with_loop', true);
73
+
74
+ $tests[] = array($node, <<<EOF
75
+ // line 1
76
+ \$context['_parent'] = \$context;
77
+ \$context['_seq'] = twig_ensure_traversable({$this->getVariableGetter('values')});
78
+ \$context['loop'] = array(
79
+ 'parent' => \$context['_parent'],
80
+ 'index0' => 0,
81
+ 'index' => 1,
82
+ 'first' => true,
83
+ );
84
+ if (is_array(\$context['_seq']) || (is_object(\$context['_seq']) && \$context['_seq'] instanceof Countable)) {
85
+ \$length = count(\$context['_seq']);
86
+ \$context['loop']['revindex0'] = \$length - 1;
87
+ \$context['loop']['revindex'] = \$length;
88
+ \$context['loop']['length'] = \$length;
89
+ \$context['loop']['last'] = 1 === \$length;
90
+ }
91
+ foreach (\$context['_seq'] as \$context["k"] => \$context["v"]) {
92
+ echo {$this->getVariableGetter('foo')};
93
+ ++\$context['loop']['index0'];
94
+ ++\$context['loop']['index'];
95
+ \$context['loop']['first'] = false;
96
+ if (isset(\$context['loop']['length'])) {
97
+ --\$context['loop']['revindex0'];
98
+ --\$context['loop']['revindex'];
99
+ \$context['loop']['last'] = 0 === \$context['loop']['revindex0'];
100
+ }
101
+ }
102
+ \$_parent = \$context['_parent'];
103
+ unset(\$context['_seq'], \$context['_iterated'], \$context['k'], \$context['v'], \$context['_parent'], \$context['loop']);
104
+ \$context = array_intersect_key(\$context, \$_parent) + \$_parent;
105
+ EOF
106
+ );
107
+
108
+ $keyTarget = new Twig_Node_Expression_AssignName('k', 1);
109
+ $valueTarget = new Twig_Node_Expression_AssignName('v', 1);
110
+ $seq = new Twig_Node_Expression_Name('values', 1);
111
+ $ifexpr = new Twig_Node_Expression_Constant(true, 1);
112
+ $body = new Twig_Node(array(new Twig_Node_Print(new Twig_Node_Expression_Name('foo', 1), 1)), array(), 1);
113
+ $else = null;
114
+ $node = new Twig_Node_For($keyTarget, $valueTarget, $seq, $ifexpr, $body, $else, 1);
115
+ $node->setAttribute('with_loop', true);
116
+
117
+ $tests[] = array($node, <<<EOF
118
+ // line 1
119
+ \$context['_parent'] = \$context;
120
+ \$context['_seq'] = twig_ensure_traversable({$this->getVariableGetter('values')});
121
+ \$context['loop'] = array(
122
+ 'parent' => \$context['_parent'],
123
+ 'index0' => 0,
124
+ 'index' => 1,
125
+ 'first' => true,
126
+ );
127
+ foreach (\$context['_seq'] as \$context["k"] => \$context["v"]) {
128
+ if (true) {
129
+ echo {$this->getVariableGetter('foo')};
130
+ ++\$context['loop']['index0'];
131
+ ++\$context['loop']['index'];
132
+ \$context['loop']['first'] = false;
133
+ }
134
+ }
135
+ \$_parent = \$context['_parent'];
136
+ unset(\$context['_seq'], \$context['_iterated'], \$context['k'], \$context['v'], \$context['_parent'], \$context['loop']);
137
+ \$context = array_intersect_key(\$context, \$_parent) + \$_parent;
138
+ EOF
139
+ );
140
+
141
+ $keyTarget = new Twig_Node_Expression_AssignName('k', 1);
142
+ $valueTarget = new Twig_Node_Expression_AssignName('v', 1);
143
+ $seq = new Twig_Node_Expression_Name('values', 1);
144
+ $ifexpr = null;
145
+ $body = new Twig_Node(array(new Twig_Node_Print(new Twig_Node_Expression_Name('foo', 1), 1)), array(), 1);
146
+ $else = new Twig_Node_Print(new Twig_Node_Expression_Name('foo', 1), 1);
147
+ $node = new Twig_Node_For($keyTarget, $valueTarget, $seq, $ifexpr, $body, $else, 1);
148
+ $node->setAttribute('with_loop', true);
149
+
150
+ $tests[] = array($node, <<<EOF
151
+ // line 1
152
+ \$context['_parent'] = \$context;
153
+ \$context['_seq'] = twig_ensure_traversable({$this->getVariableGetter('values')});
154
+ \$context['_iterated'] = false;
155
+ \$context['loop'] = array(
156
+ 'parent' => \$context['_parent'],
157
+ 'index0' => 0,
158
+ 'index' => 1,
159
+ 'first' => true,
160
+ );
161
+ if (is_array(\$context['_seq']) || (is_object(\$context['_seq']) && \$context['_seq'] instanceof Countable)) {
162
+ \$length = count(\$context['_seq']);
163
+ \$context['loop']['revindex0'] = \$length - 1;
164
+ \$context['loop']['revindex'] = \$length;
165
+ \$context['loop']['length'] = \$length;
166
+ \$context['loop']['last'] = 1 === \$length;
167
+ }
168
+ foreach (\$context['_seq'] as \$context["k"] => \$context["v"]) {
169
+ echo {$this->getVariableGetter('foo')};
170
+ \$context['_iterated'] = true;
171
+ ++\$context['loop']['index0'];
172
+ ++\$context['loop']['index'];
173
+ \$context['loop']['first'] = false;
174
+ if (isset(\$context['loop']['length'])) {
175
+ --\$context['loop']['revindex0'];
176
+ --\$context['loop']['revindex'];
177
+ \$context['loop']['last'] = 0 === \$context['loop']['revindex0'];
178
+ }
179
+ }
180
+ if (!\$context['_iterated']) {
181
+ echo {$this->getVariableGetter('foo')};
182
+ }
183
+ \$_parent = \$context['_parent'];
184
+ unset(\$context['_seq'], \$context['_iterated'], \$context['k'], \$context['v'], \$context['_parent'], \$context['loop']);
185
+ \$context = array_intersect_key(\$context, \$_parent) + \$_parent;
186
+ EOF
187
+ );
188
+
189
+ return $tests;
190
+ }
191
+ }
library/twig/twig/test/Twig/Tests/Node/IfTest.php ADDED
@@ -0,0 +1,88 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 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_Tests_Node_IfTest extends Twig_Test_NodeTestCase
13
+ {
14
+ public function testConstructor()
15
+ {
16
+ $t = new Twig_Node(array(
17
+ new Twig_Node_Expression_Constant(true, 1),
18
+ new Twig_Node_Print(new Twig_Node_Expression_Name('foo', 1), 1),
19
+ ), array(), 1);
20
+ $else = null;
21
+ $node = new Twig_Node_If($t, $else, 1);
22
+
23
+ $this->assertEquals($t, $node->getNode('tests'));
24
+ $this->assertFalse($node->hasNode('else'));
25
+
26
+ $else = new Twig_Node_Print(new Twig_Node_Expression_Name('bar', 1), 1);
27
+ $node = new Twig_Node_If($t, $else, 1);
28
+ $this->assertEquals($else, $node->getNode('else'));
29
+ }
30
+
31
+ public function getTests()
32
+ {
33
+ $tests = array();
34
+
35
+ $t = new Twig_Node(array(
36
+ new Twig_Node_Expression_Constant(true, 1),
37
+ new Twig_Node_Print(new Twig_Node_Expression_Name('foo', 1), 1),
38
+ ), array(), 1);
39
+ $else = null;
40
+ $node = new Twig_Node_If($t, $else, 1);
41
+
42
+ $tests[] = array($node, <<<EOF
43
+ // line 1
44
+ if (true) {
45
+ echo {$this->getVariableGetter('foo')};
46
+ }
47
+ EOF
48
+ );
49
+
50
+ $t = new Twig_Node(array(
51
+ new Twig_Node_Expression_Constant(true, 1),
52
+ new Twig_Node_Print(new Twig_Node_Expression_Name('foo', 1), 1),
53
+ new Twig_Node_Expression_Constant(false, 1),
54
+ new Twig_Node_Print(new Twig_Node_Expression_Name('bar', 1), 1),
55
+ ), array(), 1);
56
+ $else = null;
57
+ $node = new Twig_Node_If($t, $else, 1);
58
+
59
+ $tests[] = array($node, <<<EOF
60
+ // line 1
61
+ if (true) {
62
+ echo {$this->getVariableGetter('foo')};
63
+ } elseif (false) {
64
+ echo {$this->getVariableGetter('bar')};
65
+ }
66
+ EOF
67
+ );
68
+
69
+ $t = new Twig_Node(array(
70
+ new Twig_Node_Expression_Constant(true, 1),
71
+ new Twig_Node_Print(new Twig_Node_Expression_Name('foo', 1), 1),
72
+ ), array(), 1);
73
+ $else = new Twig_Node_Print(new Twig_Node_Expression_Name('bar', 1), 1);
74
+ $node = new Twig_Node_If($t, $else, 1);
75
+
76
+ $tests[] = array($node, <<<EOF
77
+ // line 1
78
+ if (true) {
79
+ echo {$this->getVariableGetter('foo')};
80
+ } else {
81
+ echo {$this->getVariableGetter('bar')};
82
+ }
83
+ EOF
84
+ );
85
+
86
+ return $tests;
87
+ }
88
+ }
library/twig/twig/test/Twig/Tests/Node/ImportTest.php ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 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_Tests_Node_ImportTest extends Twig_Test_NodeTestCase
13
+ {
14
+ public function testConstructor()
15
+ {
16
+ $macro = new Twig_Node_Expression_Constant('foo.twig', 1);
17
+ $var = new Twig_Node_Expression_AssignName('macro', 1);
18
+ $node = new Twig_Node_Import($macro, $var, 1);
19
+
20
+ $this->assertEquals($macro, $node->getNode('expr'));
21
+ $this->assertEquals($var, $node->getNode('var'));
22
+ }
23
+
24
+ public function getTests()
25
+ {
26
+ $tests = array();
27
+
28
+ $macro = new Twig_Node_Expression_Constant('foo.twig', 1);
29
+ $var = new Twig_Node_Expression_AssignName('macro', 1);
30
+ $node = new Twig_Node_Import($macro, $var, 1);
31
+
32
+ $tests[] = array($node, <<<EOF
33
+ // line 1
34
+ \$context["macro"] = \$this->loadTemplate("foo.twig", null, 1);
35
+ EOF
36
+ );
37
+
38
+ return $tests;
39
+ }
40
+ }
library/twig/twig/test/Twig/Tests/Node/IncludeTest.php ADDED
@@ -0,0 +1,83 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 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_Tests_Node_IncludeTest extends Twig_Test_NodeTestCase
13
+ {
14
+ public function testConstructor()
15
+ {
16
+ $expr = new Twig_Node_Expression_Constant('foo.twig', 1);
17
+ $node = new Twig_Node_Include($expr, null, false, false, 1);
18
+
19
+ $this->assertFalse($node->hasNode('variables'));
20
+ $this->assertEquals($expr, $node->getNode('expr'));
21
+ $this->assertFalse($node->getAttribute('only'));
22
+
23
+ $vars = new Twig_Node_Expression_Array(array(new Twig_Node_Expression_Constant('foo', 1), new Twig_Node_Expression_Constant(true, 1)), 1);
24
+ $node = new Twig_Node_Include($expr, $vars, true, false, 1);
25
+ $this->assertEquals($vars, $node->getNode('variables'));
26
+ $this->assertTrue($node->getAttribute('only'));
27
+ }
28
+
29
+ public function getTests()
30
+ {
31
+ $tests = array();
32
+
33
+ $expr = new Twig_Node_Expression_Constant('foo.twig', 1);
34
+ $node = new Twig_Node_Include($expr, null, false, false, 1);
35
+ $tests[] = array($node, <<<EOF
36
+ // line 1
37
+ \$this->loadTemplate("foo.twig", null, 1)->display(\$context);
38
+ EOF
39
+ );
40
+
41
+ $expr = new Twig_Node_Expression_Conditional(
42
+ new Twig_Node_Expression_Constant(true, 1),
43
+ new Twig_Node_Expression_Constant('foo', 1),
44
+ new Twig_Node_Expression_Constant('foo', 1),
45
+ 0
46
+ );
47
+ $node = new Twig_Node_Include($expr, null, false, false, 1);
48
+ $tests[] = array($node, <<<EOF
49
+ // line 1
50
+ \$this->loadTemplate(((true) ? ("foo") : ("foo")), null, 1)->display(\$context);
51
+ EOF
52
+ );
53
+
54
+ $expr = new Twig_Node_Expression_Constant('foo.twig', 1);
55
+ $vars = new Twig_Node_Expression_Array(array(new Twig_Node_Expression_Constant('foo', 1), new Twig_Node_Expression_Constant(true, 1)), 1);
56
+ $node = new Twig_Node_Include($expr, $vars, false, false, 1);
57
+ $tests[] = array($node, <<<EOF
58
+ // line 1
59
+ \$this->loadTemplate("foo.twig", null, 1)->display(array_merge(\$context, array("foo" => true)));
60
+ EOF
61
+ );
62
+
63
+ $node = new Twig_Node_Include($expr, $vars, true, false, 1);
64
+ $tests[] = array($node, <<<EOF
65
+ // line 1
66
+ \$this->loadTemplate("foo.twig", null, 1)->display(array("foo" => true));
67
+ EOF
68
+ );
69
+
70
+ $node = new Twig_Node_Include($expr, $vars, true, true, 1);
71
+ $tests[] = array($node, <<<EOF
72
+ // line 1
73
+ try {
74
+ \$this->loadTemplate("foo.twig", null, 1)->display(array("foo" => true));
75
+ } catch (Twig_Error_Loader \$e) {
76
+ // ignore missing template
77
+ }
78
+ EOF
79
+ );
80
+
81
+ return $tests;
82
+ }
83
+ }
library/twig/twig/test/Twig/Tests/Node/MacroTest.php ADDED
@@ -0,0 +1,74 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 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_Tests_Node_MacroTest extends Twig_Test_NodeTestCase
13
+ {
14
+ public function testConstructor()
15
+ {
16
+ $body = new Twig_Node_Text('foo', 1);
17
+ $arguments = new Twig_Node(array(new Twig_Node_Expression_Name('foo', 1)), array(), 1);
18
+ $node = new Twig_Node_Macro('foo', $body, $arguments, 1);
19
+
20
+ $this->assertEquals($body, $node->getNode('body'));
21
+ $this->assertEquals($arguments, $node->getNode('arguments'));
22
+ $this->assertEquals('foo', $node->getAttribute('name'));
23
+ }
24
+
25
+ public function getTests()
26
+ {
27
+ $body = new Twig_Node_Text('foo', 1);
28
+ $arguments = new Twig_Node(array(
29
+ 'foo' => new Twig_Node_Expression_Constant(null, 1),
30
+ 'bar' => new Twig_Node_Expression_Constant('Foo', 1),
31
+ ), array(), 1);
32
+ $node = new Twig_Node_Macro('foo', $body, $arguments, 1);
33
+
34
+ if (PHP_VERSION_ID >= 50600) {
35
+ $declaration = ', ...$__varargs__';
36
+ $varargs = '$__varargs__';
37
+ } else {
38
+ $declaration = '';
39
+ $varargs = 'func_num_args() > 2 ? array_slice(func_get_args(), 2) : array()';
40
+ }
41
+
42
+ return array(
43
+ array($node, <<<EOF
44
+ // line 1
45
+ public function getfoo(\$__foo__ = null, \$__bar__ = "Foo"$declaration)
46
+ {
47
+ \$context = \$this->env->mergeGlobals(array(
48
+ "foo" => \$__foo__,
49
+ "bar" => \$__bar__,
50
+ "varargs" => $varargs,
51
+ ));
52
+
53
+ \$blocks = array();
54
+
55
+ ob_start();
56
+ try {
57
+ echo "foo";
58
+ } catch (Exception \$e) {
59
+ ob_end_clean();
60
+
61
+ throw \$e;
62
+ } catch (Throwable \$e) {
63
+ ob_end_clean();
64
+
65
+ throw \$e;
66
+ }
67
+
68
+ return ('' === \$tmp = ob_get_clean()) ? '' : new Twig_Markup(\$tmp, \$this->env->getCharset());
69
+ }
70
+ EOF
71
+ ),
72
+ );
73
+ }
74
+ }
library/twig/twig/test/Twig/Tests/Node/ModuleTest.php ADDED
@@ -0,0 +1,223 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 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_Tests_Node_ModuleTest extends Twig_Test_NodeTestCase
13
+ {
14
+ public function testConstructor()
15
+ {
16
+ $body = new Twig_Node_Text('foo', 1);
17
+ $parent = new Twig_Node_Expression_Constant('layout.twig', 1);
18
+ $blocks = new Twig_Node();
19
+ $macros = new Twig_Node();
20
+ $traits = new Twig_Node();
21
+ $source = new Twig_Source('{{ foo }}', 'foo.twig');
22
+ $node = new Twig_Node_Module($body, $parent, $blocks, $macros, $traits, new Twig_Node(array()), $source);
23
+
24
+ $this->assertEquals($body, $node->getNode('body'));
25
+ $this->assertEquals($blocks, $node->getNode('blocks'));
26
+ $this->assertEquals($macros, $node->getNode('macros'));
27
+ $this->assertEquals($parent, $node->getNode('parent'));
28
+ $this->assertEquals($source->getName(), $node->getTemplateName());
29
+ }
30
+
31
+ public function getTests()
32
+ {
33
+ $twig = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock());
34
+
35
+ $tests = array();
36
+
37
+ $body = new Twig_Node_Text('foo', 1);
38
+ $extends = null;
39
+ $blocks = new Twig_Node();
40
+ $macros = new Twig_Node();
41
+ $traits = new Twig_Node();
42
+ $source = new Twig_Source('{{ foo }}', 'foo.twig');
43
+
44
+ $node = new Twig_Node_Module($body, $extends, $blocks, $macros, $traits, new Twig_Node(array()), $source);
45
+ $tests[] = array($node, <<<EOF
46
+ <?php
47
+
48
+ /* foo.twig */
49
+ class __TwigTemplate_%x extends Twig_Template
50
+ {
51
+ public function __construct(Twig_Environment \$env)
52
+ {
53
+ parent::__construct(\$env);
54
+
55
+ \$this->parent = false;
56
+
57
+ \$this->blocks = array(
58
+ );
59
+ }
60
+
61
+ protected function doDisplay(array \$context, array \$blocks = array())
62
+ {
63
+ // line 1
64
+ echo "foo";
65
+ }
66
+
67
+ public function getTemplateName()
68
+ {
69
+ return "foo.twig";
70
+ }
71
+
72
+ public function getDebugInfo()
73
+ {
74
+ return array ( 19 => 1,);
75
+ }
76
+
77
+ /** @deprecated since 1.27 (to be removed in 2.0). Use getSourceContext() instead */
78
+ public function getSource()
79
+ {
80
+ @trigger_error('The '.__METHOD__.' method is deprecated since version 1.27 and will be removed in 2.0. Use getSourceContext() instead.', E_USER_DEPRECATED);
81
+
82
+ return \$this->getSourceContext()->getCode();
83
+ }
84
+
85
+ public function getSourceContext()
86
+ {
87
+ return new Twig_Source("", "foo.twig", "");
88
+ }
89
+ }
90
+ EOF
91
+ , $twig, true);
92
+
93
+ $import = new Twig_Node_Import(new Twig_Node_Expression_Constant('foo.twig', 1), new Twig_Node_Expression_AssignName('macro', 1), 2);
94
+
95
+ $body = new Twig_Node(array($import));
96
+ $extends = new Twig_Node_Expression_Constant('layout.twig', 1);
97
+
98
+ $node = new Twig_Node_Module($body, $extends, $blocks, $macros, $traits, new Twig_Node(array()), $source);
99
+ $tests[] = array($node, <<<EOF
100
+ <?php
101
+
102
+ /* foo.twig */
103
+ class __TwigTemplate_%x extends Twig_Template
104
+ {
105
+ public function __construct(Twig_Environment \$env)
106
+ {
107
+ parent::__construct(\$env);
108
+
109
+ // line 1
110
+ \$this->parent = \$this->loadTemplate("layout.twig", "foo.twig", 1);
111
+ \$this->blocks = array(
112
+ );
113
+ }
114
+
115
+ protected function doGetParent(array \$context)
116
+ {
117
+ return "layout.twig";
118
+ }
119
+
120
+ protected function doDisplay(array \$context, array \$blocks = array())
121
+ {
122
+ // line 2
123
+ \$context["macro"] = \$this->loadTemplate("foo.twig", "foo.twig", 2);
124
+ // line 1
125
+ \$this->parent->display(\$context, array_merge(\$this->blocks, \$blocks));
126
+ }
127
+
128
+ public function getTemplateName()
129
+ {
130
+ return "foo.twig";
131
+ }
132
+
133
+ public function isTraitable()
134
+ {
135
+ return false;
136
+ }
137
+
138
+ public function getDebugInfo()
139
+ {
140
+ return array ( 26 => 1, 24 => 2, 11 => 1,);
141
+ }
142
+
143
+ /** @deprecated since 1.27 (to be removed in 2.0). Use getSourceContext() instead */
144
+ public function getSource()
145
+ {
146
+ @trigger_error('The '.__METHOD__.' method is deprecated since version 1.27 and will be removed in 2.0. Use getSourceContext() instead.', E_USER_DEPRECATED);
147
+
148
+ return \$this->getSourceContext()->getCode();
149
+ }
150
+
151
+ public function getSourceContext()
152
+ {
153
+ return new Twig_Source("", "foo.twig", "");
154
+ }
155
+ }
156
+ EOF
157
+ , $twig, true);
158
+
159
+ $set = new Twig_Node_Set(false, new Twig_Node(array(new Twig_Node_Expression_AssignName('foo', 4))), new Twig_Node(array(new Twig_Node_Expression_Constant('foo', 4))), 4);
160
+ $body = new Twig_Node(array($set));
161
+ $extends = new Twig_Node_Expression_Conditional(
162
+ new Twig_Node_Expression_Constant(true, 2),
163
+ new Twig_Node_Expression_Constant('foo', 2),
164
+ new Twig_Node_Expression_Constant('foo', 2),
165
+ 2
166
+ );
167
+
168
+ $twig = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock(), array('debug' => true));
169
+ $node = new Twig_Node_Module($body, $extends, $blocks, $macros, $traits, new Twig_Node(array()), $source);
170
+ $tests[] = array($node, <<<EOF
171
+ <?php
172
+
173
+ /* foo.twig */
174
+ class __TwigTemplate_%x extends Twig_Template
175
+ {
176
+ protected function doGetParent(array \$context)
177
+ {
178
+ // line 2
179
+ return \$this->loadTemplate(((true) ? ("foo") : ("foo")), "foo.twig", 2);
180
+ }
181
+
182
+ protected function doDisplay(array \$context, array \$blocks = array())
183
+ {
184
+ // line 4
185
+ \$context["foo"] = "foo";
186
+ // line 2
187
+ \$this->getParent(\$context)->display(\$context, array_merge(\$this->blocks, \$blocks));
188
+ }
189
+
190
+ public function getTemplateName()
191
+ {
192
+ return "foo.twig";
193
+ }
194
+
195
+ public function isTraitable()
196
+ {
197
+ return false;
198
+ }
199
+
200
+ public function getDebugInfo()
201
+ {
202
+ return array ( 17 => 2, 15 => 4, 9 => 2,);
203
+ }
204
+
205
+ /** @deprecated since 1.27 (to be removed in 2.0). Use getSourceContext() instead */
206
+ public function getSource()
207
+ {
208
+ @trigger_error('The '.__METHOD__.' method is deprecated since version 1.27 and will be removed in 2.0. Use getSourceContext() instead.', E_USER_DEPRECATED);
209
+
210
+ return \$this->getSourceContext()->getCode();
211
+ }
212
+
213
+ public function getSourceContext()
214
+ {
215
+ return new Twig_Source("{{ foo }}", "foo.twig", "");
216
+ }
217
+ }
218
+ EOF
219
+ , $twig, true);
220
+
221
+ return $tests;
222
+ }
223
+ }
library/twig/twig/test/Twig/Tests/Node/PrintTest.php ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 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_Tests_Node_PrintTest extends Twig_Test_NodeTestCase
13
+ {
14
+ public function testConstructor()
15
+ {
16
+ $expr = new Twig_Node_Expression_Constant('foo', 1);
17
+ $node = new Twig_Node_Print($expr, 1);
18
+
19
+ $this->assertEquals($expr, $node->getNode('expr'));
20
+ }
21
+
22
+ public function getTests()
23
+ {
24
+ $tests = array();
25
+ $tests[] = array(new Twig_Node_Print(new Twig_Node_Expression_Constant('foo', 1), 1), "// line 1\necho \"foo\";");
26
+
27
+ return $tests;
28
+ }
29
+ }
library/twig/twig/test/Twig/Tests/Node/SandboxTest.php ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 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_Tests_Node_SandboxTest extends Twig_Test_NodeTestCase
13
+ {
14
+ public function testConstructor()
15
+ {
16
+ $body = new Twig_Node_Text('foo', 1);
17
+ $node = new Twig_Node_Sandbox($body, 1);
18
+
19
+ $this->assertEquals($body, $node->getNode('body'));
20
+ }
21
+
22
+ public function getTests()
23
+ {
24
+ $tests = array();
25
+
26
+ $body = new Twig_Node_Text('foo', 1);
27
+ $node = new Twig_Node_Sandbox($body, 1);
28
+
29
+ $tests[] = array($node, <<<EOF
30
+ // line 1
31
+ \$sandbox = \$this->env->getExtension('Twig_Extension_Sandbox');
32
+ if (!\$alreadySandboxed = \$sandbox->isSandboxed()) {
33
+ \$sandbox->enableSandbox();
34
+ }
35
+ echo "foo";
36
+ if (!\$alreadySandboxed) {
37
+ \$sandbox->disableSandbox();
38
+ }
39
+ EOF
40
+ );
41
+
42
+ return $tests;
43
+ }
44
+ }
library/twig/twig/test/Twig/Tests/Node/SandboxedPrintTest.php ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 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_Tests_Node_SandboxedPrintTest extends Twig_Test_NodeTestCase
13
+ {
14
+ public function testConstructor()
15
+ {
16
+ $node = new Twig_Node_SandboxedPrint($expr = new Twig_Node_Expression_Constant('foo', 1), 1);
17
+
18
+ $this->assertEquals($expr, $node->getNode('expr'));
19
+ }
20
+
21
+ public function getTests()
22
+ {
23
+ $tests = array();
24
+
25
+ $tests[] = array(new Twig_Node_SandboxedPrint(new Twig_Node_Expression_Constant('foo', 1), 1), <<<EOF
26
+ // line 1
27
+ echo \$this->env->getExtension('Twig_Extension_Sandbox')->ensureToStringAllowed("foo");
28
+ EOF
29
+ );
30
+
31
+ return $tests;
32
+ }
33
+ }
library/twig/twig/test/Twig/Tests/Node/SetTest.php ADDED
@@ -0,0 +1,69 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 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_Tests_Node_SetTest extends Twig_Test_NodeTestCase
13
+ {
14
+ public function testConstructor()
15
+ {
16
+ $names = new Twig_Node(array(new Twig_Node_Expression_AssignName('foo', 1)), array(), 1);
17
+ $values = new Twig_Node(array(new Twig_Node_Expression_Constant('foo', 1)), array(), 1);
18
+ $node = new Twig_Node_Set(false, $names, $values, 1);
19
+
20
+ $this->assertEquals($names, $node->getNode('names'));
21
+ $this->assertEquals($values, $node->getNode('values'));
22
+ $this->assertFalse($node->getAttribute('capture'));
23
+ }
24
+
25
+ public function getTests()
26
+ {
27
+ $tests = array();
28
+
29
+ $names = new Twig_Node(array(new Twig_Node_Expression_AssignName('foo', 1)), array(), 1);
30
+ $values = new Twig_Node(array(new Twig_Node_Expression_Constant('foo', 1)), array(), 1);
31
+ $node = new Twig_Node_Set(false, $names, $values, 1);
32
+ $tests[] = array($node, <<<EOF
33
+ // line 1
34
+ \$context["foo"] = "foo";
35
+ EOF
36
+ );
37
+
38
+ $names = new Twig_Node(array(new Twig_Node_Expression_AssignName('foo', 1)), array(), 1);
39
+ $values = new Twig_Node(array(new Twig_Node_Print(new Twig_Node_Expression_Constant('foo', 1), 1)), array(), 1);
40
+ $node = new Twig_Node_Set(true, $names, $values, 1);
41
+ $tests[] = array($node, <<<EOF
42
+ // line 1
43
+ ob_start();
44
+ echo "foo";
45
+ \$context["foo"] = ('' === \$tmp = ob_get_clean()) ? '' : new Twig_Markup(\$tmp, \$this->env->getCharset());
46
+ EOF
47
+ );
48
+
49
+ $names = new Twig_Node(array(new Twig_Node_Expression_AssignName('foo', 1)), array(), 1);
50
+ $values = new Twig_Node_Text('foo', 1);
51
+ $node = new Twig_Node_Set(true, $names, $values, 1);
52
+ $tests[] = array($node, <<<EOF
53
+ // line 1
54
+ \$context["foo"] = ('' === \$tmp = "foo") ? '' : new Twig_Markup(\$tmp, \$this->env->getCharset());
55
+ EOF
56
+ );
57
+
58
+ $names = new Twig_Node(array(new Twig_Node_Expression_AssignName('foo', 1), new Twig_Node_Expression_AssignName('bar', 1)), array(), 1);
59
+ $values = new Twig_Node(array(new Twig_Node_Expression_Constant('foo', 1), new Twig_Node_Expression_Name('bar', 1)), array(), 1);
60
+ $node = new Twig_Node_Set(false, $names, $values, 1);
61
+ $tests[] = array($node, <<<EOF
62
+ // line 1
63
+ list(\$context["foo"], \$context["bar"]) = array("foo", {$this->getVariableGetter('bar')});
64
+ EOF
65
+ );
66
+
67
+ return $tests;
68
+ }
69
+ }
library/twig/twig/test/Twig/Tests/Node/SpacelessTest.php ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 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_Tests_Node_SpacelessTest extends Twig_Test_NodeTestCase
13
+ {
14
+ public function testConstructor()
15
+ {
16
+ $body = new Twig_Node(array(new Twig_Node_Text('<div> <div> foo </div> </div>', 1)));
17
+ $node = new Twig_Node_Spaceless($body, 1);
18
+
19
+ $this->assertEquals($body, $node->getNode('body'));
20
+ }
21
+
22
+ public function getTests()
23
+ {
24
+ $body = new Twig_Node(array(new Twig_Node_Text('<div> <div> foo </div> </div>', 1)));
25
+ $node = new Twig_Node_Spaceless($body, 1);
26
+
27
+ return array(
28
+ array($node, <<<EOF
29
+ // line 1
30
+ ob_start();
31
+ echo "<div> <div> foo </div> </div>";
32
+ echo trim(preg_replace('/>\s+</', '><', ob_get_clean()));
33
+ EOF
34
+ ),
35
+ );
36
+ }
37
+ }
library/twig/twig/test/Twig/Tests/Node/TextTest.php ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 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_Tests_Node_TextTest extends Twig_Test_NodeTestCase
13
+ {
14
+ public function testConstructor()
15
+ {
16
+ $node = new Twig_Node_Text('foo', 1);
17
+
18
+ $this->assertEquals('foo', $node->getAttribute('data'));
19
+ }
20
+
21
+ public function getTests()
22
+ {
23
+ $tests = array();
24
+ $tests[] = array(new Twig_Node_Text('foo', 1), "// line 1\necho \"foo\";");
25
+
26
+ return $tests;
27
+ }
28
+ }
library/twig/twig/test/Twig/Tests/NodeVisitor/OptimizerTest.php ADDED
@@ -0,0 +1,124 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 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_Tests_NodeVisitor_OptimizerTest extends PHPUnit_Framework_TestCase
12
+ {
13
+ public function testRenderBlockOptimizer()
14
+ {
15
+ $env = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock(), array('cache' => false, 'autoescape' => false));
16
+
17
+ $stream = $env->parse($env->tokenize(new Twig_Source('{{ block("foo") }}', 'index')));
18
+
19
+ $node = $stream->getNode('body')->getNode(0);
20
+
21
+ $this->assertEquals('Twig_Node_Expression_BlockReference', get_class($node));
22
+ $this->assertTrue($node->getAttribute('output'));
23
+ }
24
+
25
+ public function testRenderParentBlockOptimizer()
26
+ {
27
+ $env = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock(), array('cache' => false, 'autoescape' => false));
28
+
29
+ $stream = $env->parse($env->tokenize(new Twig_Source('{% extends "foo" %}{% block content %}{{ parent() }}{% endblock %}', 'index')));
30
+
31
+ $node = $stream->getNode('blocks')->getNode('content')->getNode(0)->getNode('body');
32
+
33
+ $this->assertEquals('Twig_Node_Expression_Parent', get_class($node));
34
+ $this->assertTrue($node->getAttribute('output'));
35
+ }
36
+
37
+ public function testRenderVariableBlockOptimizer()
38
+ {
39
+ if (PHP_VERSION_ID >= 50400) {
40
+ return;
41
+ }
42
+
43
+ $env = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock(), array('cache' => false, 'autoescape' => false));
44
+ $stream = $env->parse($env->tokenize(new Twig_Source('{{ block(name|lower) }}', 'index')));
45
+
46
+ $node = $stream->getNode('body')->getNode(0)->getNode(1);
47
+
48
+ $this->assertEquals('Twig_Node_Expression_BlockReference', get_class($node));
49
+ $this->assertTrue($node->getAttribute('output'));
50
+ }
51
+
52
+ /**
53
+ * @dataProvider getTestsForForOptimizer
54
+ */
55
+ public function testForOptimizer($template, $expected)
56
+ {
57
+ $env = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock(), array('cache' => false));
58
+
59
+ $stream = $env->parse($env->tokenize(new Twig_Source($template, 'index')));
60
+
61
+ foreach ($expected as $target => $withLoop) {
62
+ $this->assertTrue($this->checkForConfiguration($stream, $target, $withLoop), sprintf('variable %s is %soptimized', $target, $withLoop ? 'not ' : ''));
63
+ }
64
+ }
65
+
66
+ public function getTestsForForOptimizer()
67
+ {
68
+ return array(
69
+ array('{% for i in foo %}{% endfor %}', array('i' => false)),
70
+
71
+ array('{% for i in foo %}{{ loop.index }}{% endfor %}', array('i' => true)),
72
+
73
+ array('{% for i in foo %}{% for j in foo %}{% endfor %}{% endfor %}', array('i' => false, 'j' => false)),
74
+
75
+ array('{% for i in foo %}{% include "foo" %}{% endfor %}', array('i' => true)),
76
+
77
+ array('{% for i in foo %}{% include "foo" only %}{% endfor %}', array('i' => false)),
78
+
79
+ array('{% for i in foo %}{% include "foo" with { "foo": "bar" } only %}{% endfor %}', array('i' => false)),
80
+
81
+ array('{% for i in foo %}{% include "foo" with { "foo": loop.index } only %}{% endfor %}', array('i' => true)),
82
+
83
+ array('{% for i in foo %}{% for j in foo %}{{ loop.index }}{% endfor %}{% endfor %}', array('i' => false, 'j' => true)),
84
+
85
+ array('{% for i in foo %}{% for j in foo %}{{ loop.parent.loop.index }}{% endfor %}{% endfor %}', array('i' => true, 'j' => true)),
86
+
87
+ array('{% for i in foo %}{% set l = loop %}{% for j in foo %}{{ l.index }}{% endfor %}{% endfor %}', array('i' => true, 'j' => false)),
88
+
89
+ array('{% for i in foo %}{% for j in foo %}{{ foo.parent.loop.index }}{% endfor %}{% endfor %}', array('i' => false, 'j' => false)),
90
+
91
+ array('{% for i in foo %}{% for j in foo %}{{ loop["parent"].loop.index }}{% endfor %}{% endfor %}', array('i' => true, 'j' => true)),
92
+
93
+ array('{% for i in foo %}{{ include("foo") }}{% endfor %}', array('i' => true)),
94
+
95
+ array('{% for i in foo %}{{ include("foo", with_context = false) }}{% endfor %}', array('i' => false)),
96
+
97
+ array('{% for i in foo %}{{ include("foo", with_context = true) }}{% endfor %}', array('i' => true)),
98
+
99
+ array('{% for i in foo %}{{ include("foo", { "foo": "bar" }, with_context = false) }}{% endfor %}', array('i' => false)),
100
+
101
+ array('{% for i in foo %}{{ include("foo", { "foo": loop.index }, with_context = false) }}{% endfor %}', array('i' => true)),
102
+ );
103
+ }
104
+
105
+ public function checkForConfiguration(Twig_NodeInterface $node = null, $target, $withLoop)
106
+ {
107
+ if (null === $node) {
108
+ return;
109
+ }
110
+
111
+ foreach ($node as $n) {
112
+ if ($n instanceof Twig_Node_For) {
113
+ if ($target === $n->getNode('value_target')->getAttribute('name')) {
114
+ return $withLoop == $n->getAttribute('with_loop');
115
+ }
116
+ }
117
+
118
+ $ret = $this->checkForConfiguration($n, $target, $withLoop);
119
+ if (null !== $ret) {
120
+ return $ret;
121
+ }
122
+ }
123
+ }
124
+ }
library/twig/twig/test/Twig/Tests/ParserTest.php ADDED
@@ -0,0 +1,196 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 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_Tests_ParserTest extends PHPUnit_Framework_TestCase
12
+ {
13
+ /**
14
+ * @expectedException Twig_Error_Syntax
15
+ */
16
+ public function testSetMacroThrowsExceptionOnReservedMethods()
17
+ {
18
+ $parser = $this->getParser();
19
+ $parser->setMacro('parent', $this->getMockBuilder('Twig_Node_Macro')->disableOriginalConstructor()->getMock());
20
+ }
21
+
22
+ /**
23
+ * @expectedException Twig_Error_Syntax
24
+ * @expectedExceptionMessage Unknown "foo" tag. Did you mean "for" at line 1?
25
+ */
26
+ public function testUnknownTag()
27
+ {
28
+ $stream = new Twig_TokenStream(array(
29
+ new Twig_Token(Twig_Token::BLOCK_START_TYPE, '', 1),
30
+ new Twig_Token(Twig_Token::NAME_TYPE, 'foo', 1),
31
+ new Twig_Token(Twig_Token::BLOCK_END_TYPE, '', 1),
32
+ new Twig_Token(Twig_Token::EOF_TYPE, '', 1),
33
+ ));
34
+ $parser = new Twig_Parser(new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock()));
35
+ $parser->parse($stream);
36
+ }
37
+
38
+ /**
39
+ * @expectedException Twig_Error_Syntax
40
+ * @expectedExceptionMessage Unknown "foobar" tag at line 1.
41
+ */
42
+ public function testUnknownTagWithoutSuggestions()
43
+ {
44
+ $stream = new Twig_TokenStream(array(
45
+ new Twig_Token(Twig_Token::BLOCK_START_TYPE, '', 1),
46
+ new Twig_Token(Twig_Token::NAME_TYPE, 'foobar', 1),
47
+ new Twig_Token(Twig_Token::BLOCK_END_TYPE, '', 1),
48
+ new Twig_Token(Twig_Token::EOF_TYPE, '', 1),
49
+ ));
50
+ $parser = new Twig_Parser(new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock()));
51
+ $parser->parse($stream);
52
+ }
53
+
54
+ /**
55
+ * @dataProvider getFilterBodyNodesData
56
+ */
57
+ public function testFilterBodyNodes($input, $expected)
58
+ {
59
+ $parser = $this->getParser();
60
+
61
+ $this->assertEquals($expected, $parser->filterBodyNodes($input));
62
+ }
63
+
64
+ public function getFilterBodyNodesData()
65
+ {
66
+ return array(
67
+ array(
68
+ new Twig_Node(array(new Twig_Node_Text(' ', 1))),
69
+ new Twig_Node(array()),
70
+ ),
71
+ array(
72
+ $input = new Twig_Node(array(new Twig_Node_Set(false, new Twig_Node(), new Twig_Node(), 1))),
73
+ $input,
74
+ ),
75
+ array(
76
+ $input = new Twig_Node(array(new Twig_Node_Set(true, new Twig_Node(), new Twig_Node(array(new Twig_Node(array(new Twig_Node_Text('foo', 1))))), 1))),
77
+ $input,
78
+ ),
79
+ );
80
+ }
81
+
82
+ /**
83
+ * @dataProvider getFilterBodyNodesDataThrowsException
84
+ * @expectedException Twig_Error_Syntax
85
+ */
86
+ public function testFilterBodyNodesThrowsException($input)
87
+ {
88
+ $parser = $this->getParser();
89
+
90
+ $parser->filterBodyNodes($input);
91
+ }
92
+
93
+ public function getFilterBodyNodesDataThrowsException()
94
+ {
95
+ return array(
96
+ array(new Twig_Node_Text('foo', 1)),
97
+ array(new Twig_Node(array(new Twig_Node(array(new Twig_Node_Text('foo', 1)))))),
98
+ );
99
+ }
100
+
101
+ /**
102
+ * @expectedException Twig_Error_Syntax
103
+ * @expectedExceptionMessage A template that extends another one cannot start with a byte order mark (BOM); it must be removed at line 1
104
+ */
105
+ public function testFilterBodyNodesWithBOM()
106
+ {
107
+ $parser = $this->getParser();
108
+ $parser->filterBodyNodes(new Twig_Node_Text(chr(0xEF).chr(0xBB).chr(0xBF), 1));
109
+ }
110
+
111
+ public function testParseIsReentrant()
112
+ {
113
+ $twig = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock(), array(
114
+ 'autoescape' => false,
115
+ 'optimizations' => 0,
116
+ ));
117
+ $twig->addTokenParser(new TestTokenParser());
118
+
119
+ $parser = new Twig_Parser($twig);
120
+
121
+ $parser->parse(new Twig_TokenStream(array(
122
+ new Twig_Token(Twig_Token::BLOCK_START_TYPE, '', 1),
123
+ new Twig_Token(Twig_Token::NAME_TYPE, 'test', 1),
124
+ new Twig_Token(Twig_Token::BLOCK_END_TYPE, '', 1),
125
+ new Twig_Token(Twig_Token::VAR_START_TYPE, '', 1),
126
+ new Twig_Token(Twig_Token::NAME_TYPE, 'foo', 1),
127
+ new Twig_Token(Twig_Token::VAR_END_TYPE, '', 1),
128
+ new Twig_Token(Twig_Token::EOF_TYPE, '', 1),
129
+ )));
130
+
131
+ $this->assertNull($parser->getParent());
132
+ }
133
+
134
+ // The getVarName() must not depend on the template loaders,
135
+ // If this test does not throw any exception, that's good.
136
+ // see https://github.com/symfony/symfony/issues/4218
137
+ public function testGetVarName()
138
+ {
139
+ $twig = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock(), array(
140
+ 'autoescape' => false,
141
+ 'optimizations' => 0,
142
+ ));
143
+
144
+ $twig->parse($twig->tokenize(new Twig_Source(<<<EOF
145
+ {% from _self import foo %}
146
+
147
+ {% macro foo() %}
148
+ {{ foo }}
149
+ {% endmacro %}
150
+ EOF
151
+ , 'index')));
152
+ }
153
+
154
+ protected function getParser()
155
+ {
156
+ $parser = new TestParser(new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock()));
157
+ $parser->setParent(new Twig_Node());
158
+ $parser->stream = new Twig_TokenStream(array());
159
+
160
+ return $parser;
161
+ }
162
+ }
163
+
164
+ class TestParser extends Twig_Parser
165
+ {
166
+ public $stream;
167
+
168
+ public function filterBodyNodes(Twig_NodeInterface $node)
169
+ {
170
+ return parent::filterBodyNodes($node);
171
+ }
172
+ }
173
+
174
+ class TestTokenParser extends Twig_TokenParser
175
+ {
176
+ public function parse(Twig_Token $token)
177
+ {
178
+ // simulate the parsing of another template right in the middle of the parsing of the current template
179
+ $this->parser->parse(new Twig_TokenStream(array(
180
+ new Twig_Token(Twig_Token::BLOCK_START_TYPE, '', 1),
181
+ new Twig_Token(Twig_Token::NAME_TYPE, 'extends', 1),
182
+ new Twig_Token(Twig_Token::STRING_TYPE, 'base', 1),
183
+ new Twig_Token(Twig_Token::BLOCK_END_TYPE, '', 1),
184
+ new Twig_Token(Twig_Token::EOF_TYPE, '', 1),
185
+ )));
186
+
187
+ $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE);
188
+
189
+ return new Twig_Node(array());
190
+ }
191
+
192
+ public function getTag()
193
+ {
194
+ return 'test';
195
+ }
196
+ }
library/twig/twig/test/Twig/Tests/Profiler/Dumper/AbstractTest.php ADDED
@@ -0,0 +1,101 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 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
+ abstract class Twig_Tests_Profiler_Dumper_AbstractTest extends PHPUnit_Framework_TestCase
13
+ {
14
+ protected function getProfile()
15
+ {
16
+ $profile = $this->getMockBuilder('Twig_Profiler_Profile')->disableOriginalConstructor()->getMock();
17
+
18
+ $profile->expects($this->any())->method('isRoot')->will($this->returnValue(true));
19
+ $profile->expects($this->any())->method('getName')->will($this->returnValue('main'));
20
+ $profile->expects($this->any())->method('getDuration')->will($this->returnValue(1));
21
+ $profile->expects($this->any())->method('getMemoryUsage')->will($this->returnValue(0));
22
+ $profile->expects($this->any())->method('getPeakMemoryUsage')->will($this->returnValue(0));
23
+
24
+ $subProfiles = array(
25
+ $this->getIndexProfile(
26
+ array(
27
+ $this->getEmbeddedBlockProfile(),
28
+ $this->getEmbeddedTemplateProfile(
29
+ array(
30
+ $this->getIncludedTemplateProfile(),
31
+ )
32
+ ),
33
+ $this->getMacroProfile(),
34
+ $this->getEmbeddedTemplateProfile(
35
+ array(
36
+ $this->getIncludedTemplateProfile(),
37
+ )
38
+ ),
39
+ )
40
+ ),
41
+ );
42
+
43
+ $profile->expects($this->any())->method('getProfiles')->will($this->returnValue($subProfiles));
44
+ $profile->expects($this->any())->method('getIterator')->will($this->returnValue(new ArrayIterator($subProfiles)));
45
+
46
+ return $profile;
47
+ }
48
+
49
+ private function getIndexProfile(array $subProfiles = array())
50
+ {
51
+ return $this->generateProfile('main', 1, true, 'template', 'index.twig', $subProfiles);
52
+ }
53
+
54
+ private function getEmbeddedBlockProfile(array $subProfiles = array())
55
+ {
56
+ return $this->generateProfile('body', 0.0001, false, 'block', 'embedded.twig', $subProfiles);
57
+ }
58
+
59
+ private function getEmbeddedTemplateProfile(array $subProfiles = array())
60
+ {
61
+ return $this->generateProfile('main', 0.0001, true, 'template', 'embedded.twig', $subProfiles);
62
+ }
63
+
64
+ private function getIncludedTemplateProfile(array $subProfiles = array())
65
+ {
66
+ return $this->generateProfile('main', 0.0001, true, 'template', 'included.twig', $subProfiles);
67
+ }
68
+
69
+ private function getMacroProfile(array $subProfiles = array())
70
+ {
71
+ return $this->generateProfile('foo', 0.0001, false, 'macro', 'index.twig', $subProfiles);
72
+ }
73
+
74
+ /**
75
+ * @param string $name
76
+ * @param float $duration
77
+ * @param bool $isTemplate
78
+ * @param string $type
79
+ * @param string $templateName
80
+ * @param array $subProfiles
81
+ *
82
+ * @return Twig_Profiler_Profile
83
+ */
84
+ private function generateProfile($name, $duration, $isTemplate, $type, $templateName, array $subProfiles = array())
85
+ {
86
+ $profile = $this->getMockBuilder('Twig_Profiler_Profile')->disableOriginalConstructor()->getMock();
87
+
88
+ $profile->expects($this->any())->method('isRoot')->will($this->returnValue(false));
89
+ $profile->expects($this->any())->method('getName')->will($this->returnValue($name));
90
+ $profile->expects($this->any())->method('getDuration')->will($this->returnValue($duration));
91
+ $profile->expects($this->any())->method('getMemoryUsage')->will($this->returnValue(0));
92
+ $profile->expects($this->any())->method('getPeakMemoryUsage')->will($this->returnValue(0));
93
+ $profile->expects($this->any())->method('isTemplate')->will($this->returnValue($isTemplate));
94
+ $profile->expects($this->any())->method('getType')->will($this->returnValue($type));
95
+ $profile->expects($this->any())->method('getTemplate')->will($this->returnValue($templateName));
96
+ $profile->expects($this->any())->method('getProfiles')->will($this->returnValue($subProfiles));
97
+ $profile->expects($this->any())->method('getIterator')->will($this->returnValue(new ArrayIterator($subProfiles)));
98
+
99
+ return $profile;
100
+ }
101
+ }
library/twig/twig/test/Twig/Tests/Profiler/Dumper/BlackfireTest.php ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 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_Tests_Profiler_Dumper_BlackfireTest extends Twig_Tests_Profiler_Dumper_AbstractTest
13
+ {
14
+ public function testDump()
15
+ {
16
+ $dumper = new Twig_Profiler_Dumper_Blackfire();
17
+
18
+ $this->assertStringMatchesFormat(<<<EOF
19
+ file-format: BlackfireProbe
20
+ cost-dimensions: wt mu pmu
21
+ request-start: %d.%d
22
+
23
+ main()//1 %d %d %d
24
+ main()==>index.twig//1 %d %d %d
25
+ index.twig==>embedded.twig::block(body)//1 %d %d 0
26
+ index.twig==>embedded.twig//2 %d %d %d
27
+ embedded.twig==>included.twig//2 %d %d %d
28
+ index.twig==>index.twig::macro(foo)//1 %d %d %d
29
+ EOF
30
+ , $dumper->dump($this->getProfile()));
31
+ }
32
+ }
library/twig/twig/test/Twig/Tests/Profiler/Dumper/HtmlTest.php ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 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_Tests_Profiler_Dumper_HtmlTest extends Twig_Tests_Profiler_Dumper_AbstractTest
13
+ {
14
+ public function testDump()
15
+ {
16
+ $dumper = new Twig_Profiler_Dumper_Html();
17
+ $this->assertStringMatchesFormat(<<<EOF
18
+ <pre>main <span style="color: #d44">%d.%dms/%d%</span>
19
+ └ <span style="background-color: #ffd">index.twig</span> <span style="color: #d44">%d.%dms/%d%</span>
20
+ └ embedded.twig::block(<span style="background-color: #dfd">body</span>)
21
+ └ <span style="background-color: #ffd">embedded.twig</span>
22
+ │ └ <span style="background-color: #ffd">included.twig</span>
23
+ └ index.twig::macro(<span style="background-color: #ddf">foo</span>)
24
+ └ <span style="background-color: #ffd">embedded.twig</span>
25
+ └ <span style="background-color: #ffd">included.twig</span>
26
+ </pre>
27
+ EOF
28
+ , $dumper->dump($this->getProfile()));
29
+ }
30
+ }
library/twig/twig/test/Twig/Tests/Profiler/Dumper/TextTest.php ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 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_Tests_Profiler_Dumper_TextTest extends Twig_Tests_Profiler_Dumper_AbstractTest
13
+ {
14
+ public function testDump()
15
+ {
16
+ $dumper = new Twig_Profiler_Dumper_Text();
17
+ $this->assertStringMatchesFormat(<<<EOF
18
+ main %d.%dms/%d%
19
+ └ index.twig %d.%dms/%d%
20
+ └ embedded.twig::block(body)
21
+ └ embedded.twig
22
+ │ └ included.twig
23
+ └ index.twig::macro(foo)
24
+ └ embedded.twig
25
+ └ included.twig
26
+
27
+ EOF
28
+ , $dumper->dump($this->getProfile()));
29
+ }
30
+ }
library/twig/twig/test/Twig/Tests/Profiler/ProfileTest.php ADDED
@@ -0,0 +1,100 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 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_Tests_Profiler_ProfileTest extends PHPUnit_Framework_TestCase
13
+ {
14
+ public function testConstructor()
15
+ {
16
+ $profile = new Twig_Profiler_Profile('template', 'type', 'name');
17
+
18
+ $this->assertEquals('template', $profile->getTemplate());
19
+ $this->assertEquals('type', $profile->getType());
20
+ $this->assertEquals('name', $profile->getName());
21
+ }
22
+
23
+ public function testIsRoot()
24
+ {
25
+ $profile = new Twig_Profiler_Profile('template', Twig_Profiler_Profile::ROOT);
26
+ $this->assertTrue($profile->isRoot());
27
+
28
+ $profile = new Twig_Profiler_Profile('template', Twig_Profiler_Profile::TEMPLATE);
29
+ $this->assertFalse($profile->isRoot());
30
+ }
31
+
32
+ public function testIsTemplate()
33
+ {
34
+ $profile = new Twig_Profiler_Profile('template', Twig_Profiler_Profile::TEMPLATE);
35
+ $this->assertTrue($profile->isTemplate());
36
+
37
+ $profile = new Twig_Profiler_Profile('template', Twig_Profiler_Profile::ROOT);
38
+ $this->assertFalse($profile->isTemplate());
39
+ }
40
+
41
+ public function testIsBlock()
42
+ {
43
+ $profile = new Twig_Profiler_Profile('template', Twig_Profiler_Profile::BLOCK);
44
+ $this->assertTrue($profile->isBlock());
45
+
46
+ $profile = new Twig_Profiler_Profile('template', Twig_Profiler_Profile::ROOT);
47
+ $this->assertFalse($profile->isBlock());
48
+ }
49
+
50
+ public function testIsMacro()
51
+ {
52
+ $profile = new Twig_Profiler_Profile('template', Twig_Profiler_Profile::MACRO);
53
+ $this->assertTrue($profile->isMacro());
54
+
55
+ $profile = new Twig_Profiler_Profile('template', Twig_Profiler_Profile::ROOT);
56
+ $this->assertFalse($profile->isMacro());
57
+ }
58
+
59
+ public function testGetAddProfile()
60
+ {
61
+ $profile = new Twig_Profiler_Profile();
62
+ $profile->addProfile($a = new Twig_Profiler_Profile());
63
+ $profile->addProfile($b = new Twig_Profiler_Profile());
64
+
65
+ $this->assertSame(array($a, $b), $profile->getProfiles());
66
+ $this->assertSame(array($a, $b), iterator_to_array($profile));
67
+ }
68
+
69
+ public function testGetDuration()
70
+ {
71
+ $profile = new Twig_Profiler_Profile();
72
+ usleep(1);
73
+ $profile->leave();
74
+
75
+ $this->assertTrue($profile->getDuration() > 0, sprintf('Expected duration > 0, got: %f', $profile->getDuration()));
76
+ }
77
+
78
+ public function testSerialize()
79
+ {
80
+ $profile = new Twig_Profiler_Profile('template', 'type', 'name');
81
+ $profile1 = new Twig_Profiler_Profile('template1', 'type1', 'name1');
82
+ $profile->addProfile($profile1);
83
+ $profile->leave();
84
+ $profile1->leave();
85
+
86
+ $profile2 = unserialize(serialize($profile));
87
+ $profiles = $profile->getProfiles();
88
+ $this->assertCount(1, $profiles);
89
+ $profile3 = $profiles[0];
90
+
91
+ $this->assertEquals($profile->getTemplate(), $profile2->getTemplate());
92
+ $this->assertEquals($profile->getType(), $profile2->getType());
93
+ $this->assertEquals($profile->getName(), $profile2->getName());
94
+ $this->assertEquals($profile->getDuration(), $profile2->getDuration());
95
+
96
+ $this->assertEquals($profile1->getTemplate(), $profile3->getTemplate());
97
+ $this->assertEquals($profile1->getType(), $profile3->getType());
98
+ $this->assertEquals($profile1->getName(), $profile3->getName());
99
+ }
100
+ }
library/twig/twig/test/Twig/Tests/RuntimeFactoryLoaderTest.php ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 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_Tests_FactoryRuntimeLoaderTest extends PHPUnit_Framework_TestCase
13
+ {
14
+ public function testLoad()
15
+ {
16
+ $loader = new Twig_FactoryRuntimeLoader(array('stdClass' => 'getRuntime'));
17
+
18
+ $this->assertInstanceOf('stdClass', $loader->load('stdClass'));
19
+ }
20
+
21
+ public function testLoadReturnsNullForUnmappedRuntime()
22
+ {
23
+ $loader = new Twig_FactoryRuntimeLoader();
24
+
25
+ $this->assertNull($loader->load('stdClass'));
26
+ }
27
+ }
28
+
29
+ function getRuntime()
30
+ {
31
+ return new stdClass();
32
+ }
library/twig/twig/test/Twig/Tests/TemplateTest.php ADDED
@@ -0,0 +1,727 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 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_Tests_TemplateTest extends PHPUnit_Framework_TestCase
12
+ {
13
+ /**
14
+ * @expectedException LogicException
15
+ */
16
+ public function testDisplayBlocksAcceptTemplateOnlyAsBlocks()
17
+ {
18
+ $template = $this->getMockForAbstractClass('Twig_Template', array(), '', false);
19
+ $template->displayBlock('foo', array(), array('foo' => array(new stdClass(), 'foo')));
20
+ }
21
+
22
+ /**
23
+ * @dataProvider getAttributeExceptions
24
+ */
25
+ public function testGetAttributeExceptions($template, $message)
26
+ {
27
+ $templates = array('index' => $template);
28
+ $env = new Twig_Environment(new Twig_Loader_Array($templates), array('strict_variables' => true));
29
+ $template = $env->loadTemplate('index');
30
+
31
+ $context = array(
32
+ 'string' => 'foo',
33
+ 'null' => null,
34
+ 'empty_array' => array(),
35
+ 'array' => array('foo' => 'foo'),
36
+ 'array_access' => new Twig_TemplateArrayAccessObject(),
37
+ 'magic_exception' => new Twig_TemplateMagicPropertyObjectWithException(),
38
+ 'object' => new stdClass(),
39
+ );
40
+
41
+ try {
42
+ $template->render($context);
43
+ $this->fail('Accessing an invalid attribute should throw an exception.');
44
+ } catch (Twig_Error_Runtime $e) {
45
+ $this->assertSame(sprintf($message, 'index'), $e->getMessage());
46
+ }
47
+ }
48
+
49
+ public function getAttributeExceptions()
50
+ {
51
+ return array(
52
+ array('{{ string["a"] }}', 'Impossible to access a key ("a") on a string variable ("foo") in "%s" at line 1.'),
53
+ array('{{ null["a"] }}', 'Impossible to access a key ("a") on a null variable in "%s" at line 1.'),
54
+ array('{{ empty_array["a"] }}', 'Key "a" does not exist as the array is empty in "%s" at line 1.'),
55
+ array('{{ array["a"] }}', 'Key "a" for array with keys "foo" does not exist in "%s" at line 1.'),
56
+ array('{{ array_access["a"] }}', 'Key "a" in object with ArrayAccess of class "Twig_TemplateArrayAccessObject" does not exist in "%s" at line 1.'),
57
+ array('{{ string.a }}', 'Impossible to access an attribute ("a") on a string variable ("foo") in "%s" at line 1.'),
58
+ array('{{ string.a() }}', 'Impossible to invoke a method ("a") on a string variable ("foo") in "%s" at line 1.'),
59
+ array('{{ null.a }}', 'Impossible to access an attribute ("a") on a null variable in "%s" at line 1.'),
60
+ array('{{ null.a() }}', 'Impossible to invoke a method ("a") on a null variable in "%s" at line 1.'),
61
+ array('{{ empty_array.a }}', 'Key "a" does not exist as the array is empty in "%s" at line 1.'),
62
+ array('{{ array.a }}', 'Key "a" for array with keys "foo" does not exist in "%s" at line 1.'),
63
+ array('{{ attribute(array, -10) }}', 'Key "-10" for array with keys "foo" does not exist in "%s" at line 1.'),
64
+ array('{{ array_access.a }}', 'Neither the property "a" nor one of the methods "a()", "geta()"/"isa()" or "__call()" exist and have public access in class "Twig_TemplateArrayAccessObject" in "%s" at line 1.'),
65
+ array('{% from _self import foo %}{% macro foo(obj) %}{{ obj.missing_method() }}{% endmacro %}{{ foo(array_access) }}', 'Neither the property "missing_method" nor one of the methods "missing_method()", "getmissing_method()"/"ismissing_method()" or "__call()" exist and have public access in class "Twig_TemplateArrayAccessObject" in "%s" at line 1.'),
66
+ array('{{ magic_exception.test }}', 'An exception has been thrown during the rendering of a template ("Hey! Don\'t try to isset me!") in "%s" at line 1.'),
67
+ array('{{ object["a"] }}', 'Impossible to access a key "a" on an object of class "stdClass" that does not implement ArrayAccess interface in "%s" at line 1.'),
68
+ );
69
+ }
70
+
71
+ /**
72
+ * @dataProvider getGetAttributeWithSandbox
73
+ */
74
+ public function testGetAttributeWithSandbox($object, $item, $allowed)
75
+ {
76
+ $twig = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock());
77
+ $policy = new Twig_Sandbox_SecurityPolicy(array(), array(), array(/*method*/), array(/*prop*/), array());
78
+ $twig->addExtension(new Twig_Extension_Sandbox($policy, !$allowed));
79
+ $template = new Twig_TemplateTest($twig);
80
+
81
+ try {
82
+ $template->getAttribute($object, $item, array(), 'any');
83
+
84
+ if (!$allowed) {
85
+ $this->fail();
86
+ }
87
+ } catch (Twig_Sandbox_SecurityError $e) {
88
+ if ($allowed) {
89
+ $this->fail();
90
+ }
91
+
92
+ $this->assertContains('is not allowed', $e->getMessage());
93
+ }
94
+ }
95
+
96
+ public function getGetAttributeWithSandbox()
97
+ {
98
+ return array(
99
+ array(new Twig_TemplatePropertyObject(), 'defined', false),
100
+ array(new Twig_TemplatePropertyObject(), 'defined', true),
101
+ array(new Twig_TemplateMethodObject(), 'defined', false),
102
+ array(new Twig_TemplateMethodObject(), 'defined', true),
103
+ );
104
+ }
105
+
106
+ /**
107
+ * @group legacy
108
+ */
109
+ public function testGetAttributeWithTemplateAsObject()
110
+ {
111
+ // to be removed in 2.0
112
+ $twig = new Twig_Environment($this->getMockBuilder('Twig_TemplateTestLoaderInterface')->getMock());
113
+ //$twig = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface', 'Twig_SourceContextLoaderInterface')->getMock());
114
+
115
+ $template = new Twig_TemplateTest($twig, 'index.twig');
116
+ $template1 = new Twig_TemplateTest($twig, 'index1.twig');
117
+
118
+ $this->assertInstanceof('Twig_Markup', $template->getAttribute($template1, 'string'));
119
+ $this->assertEquals('some_string', $template->getAttribute($template1, 'string'));
120
+
121
+ $this->assertInstanceof('Twig_Markup', $template->getAttribute($template1, 'true'));
122
+ $this->assertEquals('1', $template->getAttribute($template1, 'true'));
123
+
124
+ $this->assertInstanceof('Twig_Markup', $template->getAttribute($template1, 'zero'));
125
+ $this->assertEquals('0', $template->getAttribute($template1, 'zero'));
126
+
127
+ $this->assertNotInstanceof('Twig_Markup', $template->getAttribute($template1, 'empty'));
128
+ $this->assertSame('', $template->getAttribute($template1, 'empty'));
129
+
130
+ $this->assertFalse($template->getAttribute($template1, 'env', array(), Twig_Template::ANY_CALL, true));
131
+ $this->assertFalse($template->getAttribute($template1, 'environment', array(), Twig_Template::ANY_CALL, true));
132
+ $this->assertFalse($template->getAttribute($template1, 'getEnvironment', array(), Twig_Template::METHOD_CALL, true));
133
+ $this->assertFalse($template->getAttribute($template1, 'displayWithErrorHandling', array(), Twig_Template::METHOD_CALL, true));
134
+ }
135
+
136
+ /**
137
+ * @group legacy
138
+ * @expectedDeprecation Calling "string" on template "index1.twig" from template "index.twig" is deprecated since version 1.28 and won't be supported anymore in 2.0.
139
+ * @expectedDeprecation Calling "string" on template "index1.twig" from template "index.twig" is deprecated since version 1.28 and won't be supported anymore in 2.0.
140
+ * @expectedDeprecation Calling "true" on template "index1.twig" from template "index.twig" is deprecated since version 1.28 and won't be supported anymore in 2.0.
141
+ * @expectedDeprecation Calling "true" on template "index1.twig" from template "index.twig" is deprecated since version 1.28 and won't be supported anymore in 2.0.
142
+ * @expectedDeprecation Calling "zero" on template "index1.twig" from template "index.twig" is deprecated since version 1.28 and won't be supported anymore in 2.0.
143
+ * @expectedDeprecation Calling "zero" on template "index1.twig" from template "index.twig" is deprecated since version 1.28 and won't be supported anymore in 2.0.
144
+ * @expectedDeprecation Calling "empty" on template "index1.twig" from template "index.twig" is deprecated since version 1.28 and won't be supported anymore in 2.0.
145
+ * @expectedDeprecation Calling "empty" on template "index1.twig" from template "index.twig" is deprecated since version 1.28 and won't be supported anymore in 2.0.
146
+ * @expectedDeprecation Calling "renderBlock" on template "index.twig" from template "index.twig" is deprecated since version 1.28 and won't be supported anymore in 2.0. Use block("name") instead).
147
+ * @expectedDeprecation Calling "displayBlock" on template "index.twig" from template "index.twig" is deprecated since version 1.28 and won't be supported anymore in 2.0. Use block("name") instead).
148
+ * @expectedDeprecation Calling "hasBlock" on template "index.twig" from template "index.twig" is deprecated since version 1.28 and won't be supported anymore in 2.0. Use "block("name") is defined" instead).
149
+ * @expectedDeprecation Calling "render" on template "index.twig" from template "index.twig" is deprecated since version 1.28 and won't be supported anymore in 2.0. Use include("index.twig") instead).
150
+ * @expectedDeprecation Calling "display" on template "index.twig" from template "index.twig" is deprecated since version 1.28 and won't be supported anymore in 2.0. Use include("index.twig") instead).
151
+ * @expectedDeprecation Calling "renderBlock" on template "index1.twig" from template "index.twig" is deprecated since version 1.28 and won't be supported anymore in 2.0. Use block("name", template) instead).
152
+ * @expectedDeprecation Calling "displayBlock" on template "index1.twig" from template "index.twig" is deprecated since version 1.28 and won't be supported anymore in 2.0. Use block("name", template) instead).
153
+ * @expectedDeprecation Calling "hasBlock" on template "index1.twig" from template "index.twig" is deprecated since version 1.28 and won't be supported anymore in 2.0. Use "block("name", template) is defined" instead).
154
+ * @expectedDeprecation Calling "render" on template "index1.twig" from template "index.twig" is deprecated since version 1.28 and won't be supported anymore in 2.0. Use include("index1.twig") instead).
155
+ * @expectedDeprecation Calling "display" on template "index1.twig" from template "index.twig" is deprecated since version 1.28 and won't be supported anymore in 2.0. Use include("index1.twig") instead).
156
+ */
157
+ public function testGetAttributeWithTemplateAsObjectForDeprecations()
158
+ {
159
+ // to be removed in 2.0
160
+ $twig = new Twig_Environment($this->getMockBuilder('Twig_TemplateTestLoaderInterface')->getMock());
161
+ //$twig = new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface', 'Twig_SourceContextLoaderInterface')->getMock());
162
+
163
+ $template = new Twig_TemplateTest($twig, 'index.twig');
164
+ $template1 = new Twig_TemplateTest($twig, 'index1.twig');
165
+
166
+ $this->assertInstanceof('Twig_Markup', $template->getAttribute($template1, 'string'));
167
+ $this->assertEquals('some_string', $template->getAttribute($template1, 'string'));
168
+
169
+ $this->assertInstanceof('Twig_Markup', $template->getAttribute($template1, 'true'));
170
+ $this->assertEquals('1', $template->getAttribute($template1, 'true'));
171
+
172
+ $this->assertInstanceof('Twig_Markup', $template->getAttribute($template1, 'zero'));
173
+ $this->assertEquals('0', $template->getAttribute($template1, 'zero'));
174
+
175
+ $this->assertNotInstanceof('Twig_Markup', $template->getAttribute($template1, 'empty'));
176
+ $this->assertSame('', $template->getAttribute($template1, 'empty'));
177
+
178
+ $blocks = array('name' => array($template1, 'block_name'));
179
+
180
+ // trigger some deprecation notice messages to check them with @expectedDeprecation
181
+ $template->getAttribute($template, 'renderBlock', array('name', array(), $blocks));
182
+ $template->getAttribute($template, 'displayBlock', array('name', array(), $blocks));
183
+ $template->getAttribute($template, 'hasBlock', array('name', array()));
184
+ $template->getAttribute($template, 'render', array(array()));
185
+ $template->getAttribute($template, 'display', array(array()));
186
+
187
+ $template->getAttribute($template1, 'renderBlock', array('name', array(), $blocks));
188
+ $template->getAttribute($template1, 'displayBlock', array('name', array(), $blocks));
189
+ $template->getAttribute($template1, 'hasBlock', array('name', array()));
190
+ $template->getAttribute($template1, 'render', array(array()));
191
+ $template->getAttribute($template1, 'display', array(array()));
192
+
193
+ $this->assertFalse($template->getAttribute($template1, 'env', array(), Twig_Template::ANY_CALL, true));
194
+ $this->assertFalse($template->getAttribute($template1, 'environment', array(), Twig_Template::ANY_CALL, true));
195
+ $this->assertFalse($template->getAttribute($template1, 'getEnvironment', array(), Twig_Template::METHOD_CALL, true));
196
+ $this->assertFalse($template->getAttribute($template1, 'displayWithErrorHandling', array(), Twig_Template::METHOD_CALL, true));
197
+ }
198
+
199
+ /**
200
+ * @group legacy
201
+ * @expectedDeprecation Silent display of undefined block "unknown" in template "index.twig" is deprecated since version 1.29 and will throw an exception in 2.0. Use the "block('unknown') is defined" expression to test for block existence.
202
+ * @expectedDeprecation Silent display of undefined block "unknown" in template "index.twig" is deprecated since version 1.29 and will throw an exception in 2.0. Use the "block('unknown') is defined" expression to test for block existence.
203
+ */
204
+ public function testRenderBlockWithUndefinedBlock()
205
+ {
206
+ $twig = new Twig_Environment($this->getMockBuilder('Twig_TemplateTestLoaderInterface')->getMock());
207
+
208
+ $template = new Twig_TemplateTest($twig, 'index.twig');
209
+ $template->renderBlock('unknown', array());
210
+ $template->displayBlock('unknown', array());
211
+ }
212
+
213
+ public function testGetAttributeOnArrayWithConfusableKey()
214
+ {
215
+ $template = new Twig_TemplateTest(new Twig_Environment($this->getMockBuilder('Twig_LoaderInterface')->getMock()));
216
+
217
+ $array = array('Zero', 'One', -1 => 'MinusOne', '' => 'EmptyString', '1.5' => 'FloatButString', '01' => 'IntegerButStringWithLeadingZeros');
218
+
219
+ $this->assertSame('Zero', $array[false]);
220
+ $this->assertSame('One', $array[true]);
221
+ $this->assertSame('One', $array[1.5]);
222
+ $this->assertSame('One', $array['1']);
223
+ $this->assertSame('MinusOne', $array[-1.5]);
224
+ $this->assertSame('FloatButString', $array['1.5']);
225
+ $this->assertSame('IntegerButStringWithLeadingZeros', $array['01']);
226
+ $this->assertSame('EmptyString', $array[null]);
227
+
228
+ $this->assertSame('Zero', $template->getAttribute($array, false), 'false is treated as 0 when accessing an array (equals PHP behavior)');
229
+ $this->assertSame('One', $template->getAttribute($array, true), 'true is treated as 1 when accessing an array (equals PHP behavior)');
230
+ $this->assertSame('One', $template->getAttribute($array, 1.5), 'float is casted to int when accessing an array (equals PHP behavior)');
231
+ $this->assertSame('One', $template->getAttribute($array, '1'), '